ably-rest 0.7.1 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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