ably-rest 0.7.1 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +13 -5
  2. data/.gitmodules +1 -1
  3. data/.rspec +1 -0
  4. data/.travis.yml +7 -3
  5. data/SPEC.md +495 -419
  6. data/ably-rest.gemspec +19 -5
  7. data/lib/ably-rest.rb +9 -1
  8. data/lib/submodules/ably-ruby/.gitignore +6 -0
  9. data/lib/submodules/ably-ruby/.rspec +1 -0
  10. data/lib/submodules/ably-ruby/.ruby-version.old +1 -0
  11. data/lib/submodules/ably-ruby/.travis.yml +10 -0
  12. data/lib/submodules/ably-ruby/Gemfile +4 -0
  13. data/lib/submodules/ably-ruby/LICENSE.txt +22 -0
  14. data/lib/submodules/ably-ruby/README.md +122 -0
  15. data/lib/submodules/ably-ruby/Rakefile +34 -0
  16. data/lib/submodules/ably-ruby/SPEC.md +1794 -0
  17. data/lib/submodules/ably-ruby/ably.gemspec +36 -0
  18. data/lib/submodules/ably-ruby/lib/ably.rb +12 -0
  19. data/lib/submodules/ably-ruby/lib/ably/auth.rb +438 -0
  20. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +69 -0
  21. data/lib/submodules/ably-ruby/lib/ably/logger.rb +102 -0
  22. data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +37 -0
  23. data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +223 -0
  24. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +132 -0
  25. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +108 -0
  26. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base64.rb +40 -0
  27. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/cipher.rb +83 -0
  28. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/json.rb +34 -0
  29. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/utf8.rb +26 -0
  30. data/lib/submodules/ably-ruby/lib/ably/models/nil_logger.rb +20 -0
  31. data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +173 -0
  32. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +147 -0
  33. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +210 -0
  34. data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +161 -0
  35. data/lib/submodules/ably-ruby/lib/ably/models/token.rb +74 -0
  36. data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +15 -0
  37. data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +62 -0
  38. data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +69 -0
  39. data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +100 -0
  40. data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +69 -0
  41. data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +202 -0
  42. data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +128 -0
  43. data/lib/submodules/ably-ruby/lib/ably/modules/event_machine_helpers.rb +26 -0
  44. data/lib/submodules/ably-ruby/lib/ably/modules/http_helpers.rb +41 -0
  45. data/lib/submodules/ably-ruby/lib/ably/modules/message_pack.rb +14 -0
  46. data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +41 -0
  47. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +153 -0
  48. data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +57 -0
  49. data/lib/submodules/ably-ruby/lib/ably/modules/statesman_monkey_patch.rb +33 -0
  50. data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +74 -0
  51. data/lib/submodules/ably-ruby/lib/ably/realtime.rb +64 -0
  52. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +298 -0
  53. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +92 -0
  54. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +69 -0
  55. data/lib/submodules/ably-ruby/lib/ably/realtime/channels.rb +50 -0
  56. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +184 -0
  57. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +184 -0
  58. data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +70 -0
  59. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +445 -0
  60. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +368 -0
  61. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +91 -0
  62. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +188 -0
  63. data/lib/submodules/ably-ruby/lib/ably/realtime/models/nil_channel.rb +30 -0
  64. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +564 -0
  65. data/lib/submodules/ably-ruby/lib/ably/rest.rb +43 -0
  66. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +104 -0
  67. data/lib/submodules/ably-ruby/lib/ably/rest/channels.rb +44 -0
  68. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +396 -0
  69. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/encoder.rb +49 -0
  70. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +41 -0
  71. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/external_exceptions.rb +24 -0
  72. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +17 -0
  73. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +58 -0
  74. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_json.rb +27 -0
  75. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +27 -0
  76. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +92 -0
  77. data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +105 -0
  78. data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +43 -0
  79. data/lib/submodules/ably-ruby/lib/ably/version.rb +3 -0
  80. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +154 -0
  81. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +558 -0
  82. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +119 -0
  83. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +575 -0
  84. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +785 -0
  85. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +457 -0
  86. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +55 -0
  87. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +1001 -0
  88. data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +23 -0
  89. data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +27 -0
  90. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +564 -0
  91. data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +165 -0
  92. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +134 -0
  93. data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +41 -0
  94. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +273 -0
  95. data/lib/submodules/ably-ruby/spec/acceptance/rest/encoders_spec.rb +185 -0
  96. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +247 -0
  97. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +292 -0
  98. data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +172 -0
  99. data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +15 -0
  100. data/lib/submodules/ably-ruby/spec/resources/crypto-data-128.json +56 -0
  101. data/lib/submodules/ably-ruby/spec/resources/crypto-data-256.json +56 -0
  102. data/lib/submodules/ably-ruby/spec/rspec_config.rb +57 -0
  103. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +212 -0
  104. data/lib/submodules/ably-ruby/spec/shared/model_behaviour.rb +86 -0
  105. data/lib/submodules/ably-ruby/spec/shared/protocol_msgbus_behaviour.rb +36 -0
  106. data/lib/submodules/ably-ruby/spec/spec_helper.rb +20 -0
  107. data/lib/submodules/ably-ruby/spec/support/api_helper.rb +60 -0
  108. data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +104 -0
  109. data/lib/submodules/ably-ruby/spec/support/markdown_spec_formatter.rb +118 -0
  110. data/lib/submodules/ably-ruby/spec/support/private_api_formatter.rb +36 -0
  111. data/lib/submodules/ably-ruby/spec/support/protocol_helper.rb +32 -0
  112. data/lib/submodules/ably-ruby/spec/support/random_helper.rb +15 -0
  113. data/lib/submodules/ably-ruby/spec/support/rest_testapp_before_retry.rb +15 -0
  114. data/lib/submodules/ably-ruby/spec/support/test_app.rb +113 -0
  115. data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +68 -0
  116. data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +146 -0
  117. data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +18 -0
  118. data/lib/submodules/ably-ruby/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +349 -0
  119. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/base64_spec.rb +181 -0
  120. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/cipher_spec.rb +260 -0
  121. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/json_spec.rb +135 -0
  122. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/utf8_spec.rb +56 -0
  123. data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +389 -0
  124. data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +288 -0
  125. data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +386 -0
  126. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +315 -0
  127. data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +113 -0
  128. data/lib/submodules/ably-ruby/spec/unit/models/token_spec.rb +86 -0
  129. data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +124 -0
  130. data/lib/submodules/ably-ruby/spec/unit/modules/conversions_spec.rb +72 -0
  131. data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +272 -0
  132. data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +184 -0
  133. data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +283 -0
  134. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +206 -0
  135. data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +81 -0
  136. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +30 -0
  137. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +33 -0
  138. data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +36 -0
  139. data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +111 -0
  140. data/lib/submodules/ably-ruby/spec/unit/realtime/realtime_spec.rb +9 -0
  141. data/lib/submodules/ably-ruby/spec/unit/realtime/websocket_transport_spec.rb +25 -0
  142. data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +109 -0
  143. data/lib/submodules/ably-ruby/spec/unit/rest/channels_spec.rb +79 -0
  144. data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +53 -0
  145. data/lib/submodules/ably-ruby/spec/unit/rest/rest_spec.rb +10 -0
  146. data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +87 -0
  147. data/lib/submodules/ably-ruby/spec/unit/util/pub_sub_spec.rb +86 -0
  148. metadata +182 -27
@@ -0,0 +1,172 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe Ably::Rest::Client, '#stats' do
5
+ include Ably::Modules::Conversions
6
+
7
+ LAST_YEAR = Time.now.year - 1
8
+ LAST_INTERVAL = Time.new(LAST_YEAR, 2, 3, 15, 5, 0) # 3rd Feb 20(x) 16:05:00
9
+
10
+ STATS_FIXTURES = [
11
+ {
12
+ intervalId: Ably::Models::Stat.to_interval_id(LAST_INTERVAL - 120, :minute),
13
+ inbound: { realtime: { messages: { count: 50, data: 5000 } } },
14
+ outbound: { realtime: { messages: { count: 20, data: 2000 } } }
15
+ },
16
+ {
17
+ intervalId: Ably::Models::Stat.to_interval_id(LAST_INTERVAL - 60, :minute),
18
+ inbound: { realtime: { messages: { count: 60, data: 6000 } } },
19
+ outbound: { realtime: { messages: { count: 10, data: 1000 } } }
20
+ },
21
+ {
22
+ intervalId: Ably::Models::Stat.to_interval_id(LAST_INTERVAL, :minute),
23
+ inbound: { realtime: { messages: { count: 70, data: 7000 } } },
24
+ outbound: { realtime: { messages: { count: 40, data: 4000 } } },
25
+ persisted: { presence: { count: 20, data: 2000 } },
26
+ connections: { tls: { peak: 20, opened: 10 } },
27
+ channels: { peak: 50, opened: 30 },
28
+ apiRequests: { succeeded: 50, failed: 10 },
29
+ tokenRequests: { succeeded: 60, failed: 20 },
30
+ }
31
+ ]
32
+
33
+ before(:context) do
34
+ reload_test_app # ensure no previous stats interfere
35
+ TestApp.instance.create_test_stats(STATS_FIXTURES)
36
+ end
37
+
38
+ vary_by_protocol do
39
+ let(:client) { Ably::Rest::Client.new(api_key: api_key, environment: environment, protocol: protocol) }
40
+
41
+ describe 'fetching application stats' do
42
+ context 'by minute' do
43
+ let(:first_inbound_realtime_count) { STATS_FIXTURES.first[:inbound][:realtime][:messages][:count] }
44
+ let(:last_inbound_realtime_count) { STATS_FIXTURES.last[:inbound][:realtime][:messages][:count] }
45
+
46
+ context 'with :from set to last interval and :limit set to 1' do
47
+ let(:subject) { client.stats(start: as_since_epoch(LAST_INTERVAL), by: :minute, limit: 1) }
48
+ let(:stat) { subject.first}
49
+
50
+ it 'retrieves only one stat' do
51
+ expect(subject.count).to eql(1)
52
+ end
53
+
54
+ it 'returns all aggregated message data' do
55
+ expect(stat.all[:messages][:count]).to eql(70 + 40) # inbound + outbound
56
+ expect(stat.all[:messages][:data]).to eql(7000 + 4000) # inbound + outbound
57
+ end
58
+
59
+ it 'returns inbound realtime all data' do
60
+ expect(stat.inbound[:realtime][:all][:count]).to eql(70)
61
+ expect(stat.inbound[:realtime][:all][:data]).to eql(7000)
62
+ end
63
+
64
+ it 'returns inbound realtime message data' do
65
+ expect(stat.inbound[:realtime][:messages][:count]).to eql(70)
66
+ expect(stat.inbound[:realtime][:messages][:data]).to eql(7000)
67
+ end
68
+
69
+ it 'returns outbound realtime all data' do
70
+ expect(stat.outbound[:realtime][:all][:count]).to eql(40)
71
+ expect(stat.outbound[:realtime][:all][:data]).to eql(4000)
72
+ end
73
+
74
+ it 'returns persisted presence all data' do
75
+ expect(stat.persisted[:all][:count]).to eql(20)
76
+ expect(stat.persisted[:all][:data]).to eql(2000)
77
+ end
78
+
79
+ it 'returns connections all data' do
80
+ expect(stat.connections[:tls][:peak]).to eql(20)
81
+ expect(stat.connections[:tls][:opened]).to eql(10)
82
+ end
83
+
84
+ it 'returns channels all data' do
85
+ expect(stat.channels[:peak]).to eql(50)
86
+ expect(stat.channels[:opened]).to eql(30)
87
+ end
88
+
89
+ it 'returns api_requests data' do
90
+ expect(stat.api_requests[:succeeded]).to eql(50)
91
+ expect(stat.api_requests[:failed]).to eql(10)
92
+ end
93
+
94
+ it 'returns token_requests data' do
95
+ expect(stat.token_requests[:succeeded]).to eql(60)
96
+ expect(stat.token_requests[:failed]).to eql(20)
97
+ end
98
+
99
+ it 'returns stat objects with #interval_granularity equal to :minute' do
100
+ expect(stat.interval_granularity).to eq(:minute)
101
+ end
102
+
103
+ it 'returns stat objects with #interval_id matching :start' do
104
+ expect(stat.interval_id).to eql(LAST_INTERVAL.strftime('%Y-%m-%d:%H:%M'))
105
+ end
106
+
107
+ it 'returns stat objects with #interval_time matching :start Time' do
108
+ expect(stat.interval_time.to_i).to eql(LAST_INTERVAL.to_i)
109
+ end
110
+ end
111
+
112
+ context 'with :start set to first interval, :limit set to 1 and direction :forwards' do
113
+ let(:first_interval) { LAST_INTERVAL - 120 }
114
+ let(:subject) { client.stats(start: as_since_epoch(first_interval), by: :minute, direction: :forwards, limit: 1) }
115
+ let(:stat) { subject.first}
116
+
117
+ it 'returns the first interval stats as stats are provided forwards from :start' do
118
+ expect(stat.inbound[:realtime][:all][:count]).to eql(first_inbound_realtime_count)
119
+ end
120
+
121
+ it 'returns 3 pages of stats' do
122
+ expect(subject).to be_first_page
123
+ expect(subject).to_not be_last_page
124
+ page3 = subject.next_page.next_page
125
+ expect(page3).to be_last_page
126
+ expect(page3.first.inbound[:realtime][:all][:count]).to eql(last_inbound_realtime_count)
127
+ end
128
+ end
129
+
130
+ context 'with :end set to last interval, :limit set to 1 and direction :backwards' do
131
+ let(:subject) { client.stats(:end => as_since_epoch(LAST_INTERVAL), by: :minute, direction: :backwards, limit: 1) }
132
+ let(:stat) { subject.first}
133
+
134
+ it 'returns the 3rd interval stats first as stats are provided backwards from :end' do
135
+ expect(stat.inbound[:realtime][:all][:count]).to eql(last_inbound_realtime_count)
136
+ end
137
+
138
+ it 'returns 3 pages of stats' do
139
+ expect(subject).to be_first_page
140
+ expect(subject).to_not be_last_page
141
+ page3 = subject.next_page.next_page
142
+ expect(page3.first.inbound[:realtime][:all][:count]).to eql(first_inbound_realtime_count)
143
+ end
144
+ end
145
+ end
146
+
147
+ [:hour, :day, :month].each do |interval|
148
+ context "by #{interval}" do
149
+ let(:subject) { client.stats(start: as_since_epoch(LAST_INTERVAL), by: interval, direction: 'forwards', limit: 1) }
150
+ let(:stat) { subject.first }
151
+ let(:aggregate_messages_count) do
152
+ STATS_FIXTURES.inject(0) do |sum, fixture|
153
+ sum + fixture[:inbound][:realtime][:messages][:count] + fixture[:outbound][:realtime][:messages][:count]
154
+ end
155
+ end
156
+ let(:aggregate_messages_data) do
157
+ STATS_FIXTURES.inject(0) do |sum, fixture|
158
+ sum + fixture[:inbound][:realtime][:messages][:data] + fixture[:outbound][:realtime][:messages][:data]
159
+ end
160
+ end
161
+
162
+ it 'should aggregate the stats for that period' do
163
+ expect(subject.count).to eql(1)
164
+
165
+ expect(stat.all[:messages][:count]).to eql(aggregate_messages_count)
166
+ expect(stat.all[:messages][:data]).to eql(aggregate_messages_data)
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ably::Rest::Client, '#time' do
4
+ vary_by_protocol do
5
+ let(:client) do
6
+ Ably::Rest::Client.new(api_key: api_key, environment: environment, protocol: protocol)
7
+ end
8
+
9
+ describe 'fetching the service time' do
10
+ it 'should return the service time as a Time object' do
11
+ expect(client.time).to be_within(2).of(Time.now)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,56 @@
1
+ {
2
+ "algorithm": "aes",
3
+ "mode": "cbc",
4
+ "keylength": 128,
5
+ "key": "WUP6u0K7MXI5Zeo0VppPwg==",
6
+ "iv": "HO4cYSP8LybPYBPZPHQOtg==",
7
+ "items": [
8
+ {
9
+ "encoded": {
10
+ "name": "example",
11
+ "data": "The quick brown fox jumped over the lazy dog"
12
+ },
13
+ "encrypted": {
14
+ "name": "example",
15
+ "data": "HO4cYSP8LybPYBPZPHQOtmHItcxYdSvcNUC6kXVpMn0VFL+9z2/5tJ6WFbR0SBT1xhFRuJ+MeBGTU3yOY9P5ow==",
16
+ "encoding": "utf-8/cipher+aes-128-cbc/base64"
17
+ }
18
+ },
19
+ {
20
+ "encoded": {
21
+ "name": "example",
22
+ "data": "AAECAwQFBgcICQoLDA0ODw==",
23
+ "encoding": "base64"
24
+ },
25
+ "encrypted": {
26
+ "name": "example",
27
+ "data": "HO4cYSP8LybPYBPZPHQOtuB3dfKG08yw7J4qx3kkjxdW0eoZv+nGAp76OKqYQ327",
28
+ "encoding": "cipher+aes-128-cbc/base64"
29
+ }
30
+ },
31
+ {
32
+ "encoded": {
33
+ "name": "example",
34
+ "data": "{\"example\":{\"json\":\"Object\"}}",
35
+ "encoding": "json"
36
+ },
37
+ "encrypted": {
38
+ "name": "example",
39
+ "data": "HO4cYSP8LybPYBPZPHQOtuD53yrD3YV3NBoTEYBh4U0N1QXHbtkfsDfTspKeLQFt",
40
+ "encoding": "json/utf-8/cipher+aes-128-cbc/base64"
41
+ }
42
+ },
43
+ {
44
+ "encoded": {
45
+ "name": "example",
46
+ "data": "[\"example\",\"json\",\"array\"]",
47
+ "encoding": "json"
48
+ },
49
+ "encrypted": {
50
+ "name": "example",
51
+ "data": "HO4cYSP8LybPYBPZPHQOtvmStzmExkdjvrn51J6cmaTZrGl+EsJ61sgxmZ6j6jcA",
52
+ "encoding": "json/utf-8/cipher+aes-128-cbc/base64"
53
+ }
54
+ }
55
+ ]
56
+ }
@@ -0,0 +1,56 @@
1
+ {
2
+ "algorithm": "aes",
3
+ "mode": "cbc",
4
+ "keylength": 256,
5
+ "key": "o9qXZoPGDNla50VnRwH7cGqIrpyagTxGsRgimKJbY40=",
6
+ "iv": "NMDl1Acnel8HVdu1cEWdrw==",
7
+ "items": [
8
+ {
9
+ "encoded": {
10
+ "name": "example",
11
+ "data": "The quick brown fox jumped over the lazy dog"
12
+ },
13
+ "encrypted": {
14
+ "name": "example",
15
+ "data": "NMDl1Acnel8HVdu1cEWdr9CGPYFoBoLgJCzoybbQbnyfwx3UQ8CGuKyP/g56Za/JB3xW6XGkNzrHYvZwad4fvA==",
16
+ "encoding": "utf-8/cipher+aes-256-cbc/base64"
17
+ }
18
+ },
19
+ {
20
+ "encoded": {
21
+ "name": "example",
22
+ "data": "AAECAwQFBgcICQoLDA0ODw==",
23
+ "encoding": "base64"
24
+ },
25
+ "encrypted": {
26
+ "name": "example",
27
+ "data": "NMDl1Acnel8HVdu1cEWdr8UFEi56Ms0zPHszbppM61BC8Yf6ndq+kiCj9xXW97/O",
28
+ "encoding": "cipher+aes-256-cbc/base64"
29
+ }
30
+ },
31
+ {
32
+ "encoded": {
33
+ "name": "example",
34
+ "data": "{\"example\":{\"json\":\"Object\"}}",
35
+ "encoding": "json"
36
+ },
37
+ "encrypted": {
38
+ "name": "example",
39
+ "data": "NMDl1Acnel8HVdu1cEWdr21pS5//hdtQf3QqQzZM/jWAtn09Vh52E6jMdC3mWS98",
40
+ "encoding": "json/utf-8/cipher+aes-256-cbc/base64"
41
+ }
42
+ },
43
+ {
44
+ "encoded": {
45
+ "name": "example",
46
+ "data": "[\"example\",\"json\",\"array\"]",
47
+ "encoding": "json"
48
+ },
49
+ "encrypted": {
50
+ "name": "example",
51
+ "data": "NMDl1Acnel8HVdu1cEWdr4J5sVAFpnXsz0fTtsuwOaTRU+6P5GaWlNjePWwiOZCQ",
52
+ "encoding": "json/utf-8/cipher+aes-256-cbc/base64"
53
+ }
54
+ }
55
+ ]
56
+ }
@@ -0,0 +1,57 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ require 'rspec/retry'
9
+
10
+ RSpec.configure do |config|
11
+ config.run_all_when_everything_filtered = true
12
+ config.filter_run :focus
13
+
14
+ config.mock_with :rspec do |mocks|
15
+ # This option should be set when all dependencies are being loaded
16
+ # before a spec run, as is the case in a typical spec helper. It will
17
+ # cause any verifying double instantiation for a class that does not
18
+ # exist to raise, protecting against incorrectly spelt names.
19
+ mocks.verify_doubled_constant_names = true
20
+ end
21
+
22
+ # Run specs in random order to surface order dependencies. If you find an
23
+ # order dependency and want to debug it, you can fix the order by providing
24
+ # the seed, which is printed after each run.
25
+ # --seed 1234
26
+ config.order = 'random'
27
+
28
+ config.before(:example) do
29
+ WebMock.disable!
30
+ end
31
+
32
+ config.before(:example, :webmock) do
33
+ allow(TestApp).to receive(:instance).and_return(instance_double('TestApp',
34
+ app_id: 'app_id',
35
+ key_id: 'app_id.key_id',
36
+ api_key: 'app_id.key_id:secret',
37
+ environment: 'sandbox'
38
+ ))
39
+ WebMock.enable!
40
+ end
41
+
42
+ if defined?(EventMachine)
43
+ config.before(:example) do
44
+ # Ensure EventMachine shutdown hooks are deregistered for every test
45
+ EventMachine.instance_variable_set '@tails', []
46
+ end
47
+ end
48
+
49
+ config.add_formatter Ably::RSpec::PrivateApiFormatter
50
+
51
+ if ENV['RSPEC_RETRY']
52
+ puts 'Running tests using RSpec retry'
53
+ config.verbose_retry = true # show retry status in spec process
54
+ config.default_retry_count = 3
55
+ config.default_sleep_interval = 2
56
+ end
57
+ end
@@ -0,0 +1,212 @@
1
+ # encoding: utf-8
2
+
3
+ shared_examples 'a client initializer' do
4
+ def subdomain
5
+ if rest?
6
+ 'rest'
7
+ else
8
+ 'realtime'
9
+ end
10
+ end
11
+
12
+ def protocol
13
+ if rest?
14
+ 'http'
15
+ else
16
+ 'ws'
17
+ end
18
+ end
19
+
20
+ def rest?
21
+ subject.kind_of?(Ably::Rest::Client)
22
+ end
23
+
24
+ context 'with invalid arguments' do
25
+ context 'empty hash' do
26
+ let(:client_options) { Hash.new }
27
+
28
+ it 'raises an exception' do
29
+ expect { subject }.to raise_error(ArgumentError, /api_key is missing/)
30
+ end
31
+ end
32
+
33
+ context 'nil' do
34
+ let(:client_options) { nil }
35
+
36
+ it 'raises an exception' do
37
+ expect { subject }.to raise_error(ArgumentError, /Options Hash is expected/)
38
+ end
39
+ end
40
+
41
+ context 'api_key: "invalid"' do
42
+ let(:client_options) { { api_key: 'invalid' } }
43
+
44
+ it 'raises an exception' do
45
+ expect { subject }.to raise_error(ArgumentError, /api_key is invalid/)
46
+ end
47
+ end
48
+
49
+ context 'api_key: "invalid:asdad"' do
50
+ let(:client_options) { { api_key: 'invalid:asdad' } }
51
+
52
+ it 'raises an exception' do
53
+ expect { subject }.to raise_error(ArgumentError, /api_key is invalid/)
54
+ end
55
+ end
56
+
57
+ context 'api_key and key_id' do
58
+ let(:client_options) { { api_key: 'appid.keyuid:keysecret', key_id: 'invalid' } }
59
+
60
+ it 'raises an exception' do
61
+ expect { subject }.to raise_error(ArgumentError, /api_key and key_id or key_secret are mutually exclusive/)
62
+ end
63
+ end
64
+
65
+ context 'api_key and key_secret' do
66
+ let(:client_options) { { api_key: 'appid.keyuid:keysecret', key_secret: 'invalid' } }
67
+
68
+ it 'raises an exception' do
69
+ expect { subject }.to raise_error(ArgumentError, /api_key and key_id or key_secret are mutually exclusive/)
70
+ end
71
+ end
72
+
73
+ context 'client_id as only option' do
74
+ let(:client_options) { { client_id: 'valid' } }
75
+
76
+ it 'requires a valid key' do
77
+ expect { subject }.to raise_error(ArgumentError, /client_id cannot be provided without a complete API key/)
78
+ end
79
+ end
80
+ end
81
+
82
+ context 'with valid arguments' do
83
+ let(:default_options) { { api_key: 'appid.keyuid:keysecret' } }
84
+ let(:client_options) { default_options }
85
+
86
+ context 'api_key only' do
87
+ it 'connects to the Ably service' do
88
+ expect { subject }.to_not raise_error
89
+ end
90
+ end
91
+
92
+ context 'key_id and key_secret' do
93
+ let(:client_options) { { key_id: 'id', key_secret: 'secret' } }
94
+
95
+ it 'constructs an api_key' do
96
+ expect(subject.auth.api_key).to eql('id:secret')
97
+ end
98
+ end
99
+
100
+ context 'with a string key instead of options hash' do
101
+ let(:client_options) { 'app.key:secret' }
102
+
103
+ it 'sets the api_key' do
104
+ expect(subject.auth.api_key).to eql(client_options)
105
+ end
106
+
107
+ it 'sets the key_id' do
108
+ expect(subject.auth.key_id).to eql('app.key')
109
+ end
110
+
111
+ it 'sets the key_secret' do
112
+ expect(subject.auth.key_secret).to eql('secret')
113
+ end
114
+ end
115
+
116
+ context 'with token' do
117
+ let(:client_options) { { token_id: 'token' } }
118
+
119
+ it 'sets the token_id' do
120
+ expect(subject.auth.token_id).to eql('token')
121
+ end
122
+ end
123
+
124
+ context 'endpoint' do
125
+ it 'defaults to production' do
126
+ expect(subject.endpoint.to_s).to eql("#{protocol}s://#{subdomain}.ably.io")
127
+ end
128
+
129
+ context 'with environment option' do
130
+ let(:client_options) { default_options.merge(environment: 'sandbox') }
131
+
132
+ it 'uses an alternate endpoint' do
133
+ expect(subject.endpoint.to_s).to eql("#{protocol}s://sandbox-#{subdomain}.ably.io")
134
+ end
135
+ end
136
+ end
137
+
138
+ context 'tls' do
139
+ context 'set to false' do
140
+ let(:client_options) { default_options.merge(tls: false) }
141
+
142
+ it 'uses plain text' do
143
+ expect(subject.use_tls?).to eql(false)
144
+ end
145
+
146
+ it 'uses HTTP' do
147
+ expect(subject.endpoint.to_s).to eql("#{protocol}://#{subdomain}.ably.io")
148
+ end
149
+ end
150
+
151
+ it 'defaults to TLS' do
152
+ expect(subject.use_tls?).to eql(true)
153
+ end
154
+ end
155
+
156
+ context 'logger' do
157
+ context 'default' do
158
+ it 'uses Ruby Logger' do
159
+ expect(subject.logger.logger).to be_a(::Logger)
160
+ end
161
+
162
+ it 'specifies Logger::ERROR log level' do
163
+ expect(subject.logger.log_level).to eql(::Logger::ERROR)
164
+ end
165
+ end
166
+
167
+ context 'with log_level :none' do
168
+ let(:client_options) { default_options.merge(log_level: :none) }
169
+
170
+ it 'silences all logging with a NilLogger' do
171
+ expect(subject.logger.logger.class).to eql(Ably::Models::NilLogger)
172
+ expect(subject.logger.log_level).to eql(:none)
173
+ end
174
+ end
175
+
176
+ context 'with custom logger and log_level' do
177
+ let(:custom_logger) do
178
+ Class.new do
179
+ extend Forwardable
180
+ def initialize
181
+ @logger = Logger.new(STDOUT)
182
+ end
183
+ def_delegators :@logger, :fatal, :error, :warn, :info, :debug, :level, :level=
184
+ end
185
+ end
186
+ let(:client_options) { default_options.merge(logger: custom_logger.new, log_level: Logger::DEBUG) }
187
+
188
+ it 'uses the custom logger' do
189
+ expect(subject.logger.logger.class).to eql(custom_logger)
190
+ end
191
+
192
+ it 'sets the custom log level' do
193
+ expect(subject.logger.log_level).to eql(Logger::DEBUG)
194
+ end
195
+ end
196
+ end
197
+ end
198
+
199
+ context 'delegators' do
200
+ let(:client_options) { 'app.key:secret' }
201
+
202
+ it 'delegates :client_id to .auth' do
203
+ expect(subject.auth).to receive(:client_id).and_return('john')
204
+ expect(subject.client_id).to eql('john')
205
+ end
206
+
207
+ it 'delegates :auth_options to .auth' do
208
+ expect(subject.auth).to receive(:auth_options).and_return({ option: 1 })
209
+ expect(subject.auth_options).to eql({ option: 1 })
210
+ end
211
+ end
212
+ end