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,206 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'shared/protocol_msgbus_behaviour'
4
+
5
+ describe Ably::Realtime::Channel do
6
+ let(:client) { double('client').as_null_object }
7
+ let(:channel_name) { 'test' }
8
+
9
+ subject do
10
+ Ably::Realtime::Channel.new(client, channel_name)
11
+ end
12
+
13
+ describe '#initializer' do
14
+ let(:channel_name) { random_str.encode(encoding) }
15
+
16
+ context 'as UTF_8 string' do
17
+ let(:encoding) { Encoding::UTF_8 }
18
+
19
+ it 'is permitted' do
20
+ expect(subject.name).to eql(channel_name)
21
+ end
22
+
23
+ it 'remains as UTF-8' do
24
+ expect(subject.name.encoding).to eql(encoding)
25
+ end
26
+ end
27
+
28
+ context 'as SHIFT_JIS string' do
29
+ let(:encoding) { Encoding::SHIFT_JIS }
30
+
31
+ it 'gets converted to UTF-8' do
32
+ expect(subject.name.encoding).to eql(Encoding::UTF_8)
33
+ end
34
+
35
+ it 'is compatible with original encoding' do
36
+ expect(subject.name.encode(encoding)).to eql(channel_name)
37
+ end
38
+ end
39
+
40
+ context 'as ASCII_8BIT string' do
41
+ let(:encoding) { Encoding::ASCII_8BIT }
42
+
43
+ it 'gets converted to UTF-8' do
44
+ expect(subject.name.encoding).to eql(Encoding::UTF_8)
45
+ end
46
+
47
+ it 'is compatible with original encoding' do
48
+ expect(subject.name.encode(encoding)).to eql(channel_name)
49
+ end
50
+ end
51
+
52
+ context 'as Integer' do
53
+ let(:channel_name) { 1 }
54
+
55
+ it 'raises an argument error' do
56
+ expect { subject }.to raise_error ArgumentError, /must be a String/
57
+ end
58
+ end
59
+
60
+ context 'as Nil' do
61
+ let(:channel_name) { nil }
62
+
63
+ it 'raises an argument error' do
64
+ expect { subject }.to raise_error ArgumentError, /must be a String/
65
+ end
66
+ end
67
+ end
68
+
69
+ describe '#publish name argument' do
70
+ let(:encoded_value) { random_str.encode(encoding) }
71
+
72
+ before do
73
+ allow(subject).to receive(:create_message).and_return('message_stubbed')
74
+ end
75
+
76
+ context 'as UTF_8 string' do
77
+ let(:encoding) { Encoding::UTF_8 }
78
+
79
+ it 'is permitted' do
80
+ expect(subject.publish(encoded_value, 'data')).to eql('message_stubbed')
81
+ end
82
+ end
83
+
84
+ context 'as SHIFT_JIS string' do
85
+ let(:encoding) { Encoding::SHIFT_JIS }
86
+
87
+ it 'is permitted' do
88
+ expect(subject.publish(encoded_value, 'data')).to eql('message_stubbed')
89
+ end
90
+ end
91
+
92
+ context 'as ASCII_8BIT string' do
93
+ let(:encoding) { Encoding::ASCII_8BIT }
94
+
95
+ it 'is permitted' do
96
+ expect(subject.publish(encoded_value, 'data')).to eql('message_stubbed')
97
+ end
98
+ end
99
+
100
+ context 'as Integer' do
101
+ let(:encoded_value) { 1 }
102
+
103
+ it 'raises an argument error' do
104
+ expect { subject.publish(encoded_value, 'data') }.to raise_error ArgumentError, /must be a String/
105
+ end
106
+ end
107
+
108
+ context 'as Nil' do
109
+ let(:encoded_value) { nil }
110
+
111
+ it 'raises an argument error' do
112
+ expect { subject.publish(encoded_value, 'data') }.to raise_error ArgumentError, /must be a String/
113
+ end
114
+ end
115
+ end
116
+
117
+ describe 'callbacks' do
118
+ specify 'are supported for valid STATE events' do
119
+ state = nil
120
+ subject.on(:initialized) { state = :ready }
121
+ expect { subject.trigger(:initialized) }.to change { state }.to(:ready)
122
+ end
123
+
124
+ specify 'fail with unacceptable STATE event names' do
125
+ expect { subject.on(:invalid) }.to raise_error KeyError
126
+ expect { subject.trigger(:invalid) }.to raise_error KeyError
127
+ expect { subject.off(:invalid) }.to raise_error KeyError
128
+ end
129
+ end
130
+
131
+ context 'msgbus', :api_private do
132
+ let(:message) do
133
+ Ably::Models::Message.new({
134
+ 'name' => 'test',
135
+ 'data' => 'payload'
136
+ }, instance_double('Ably::Models::ProtocolMessage'))
137
+ end
138
+ let(:msgbus) { subject.__incoming_msgbus__ }
139
+
140
+ specify 'supports messages' do
141
+ received = 0
142
+ msgbus.subscribe(:message) { received += 1 }
143
+ expect { msgbus.publish(:message, message) }.to change { received }.to(1)
144
+ end
145
+
146
+ specify 'fail with unacceptable STATE event names' do
147
+ expect { msgbus.subscribe(:invalid) }.to raise_error KeyError
148
+ expect { msgbus.publish(:invalid) }.to raise_error KeyError
149
+ expect { msgbus.unsubscribe(:invalid) }.to raise_error KeyError
150
+ end
151
+ end
152
+
153
+ context 'subscriptions' do
154
+ let(:message_history) { Hash.new { |hash, key| hash[key] = 0 } }
155
+ let(:event_name) { 'click' }
156
+ let(:message) { instance_double('Ably::Models::Message', name: event_name, encode: nil, decode: nil) }
157
+
158
+ context '#subscribe' do
159
+ specify 'to all events' do
160
+ subject.subscribe { |message| message_history[:received] += 1}
161
+ subject.__incoming_msgbus__.publish(:message, message)
162
+ expect(message_history[:received]).to eql(1)
163
+ end
164
+
165
+ specify 'to specific events' do
166
+ subject.subscribe(event_name) { |message| message_history[:received] += 1 }
167
+ subject.subscribe('move') { |message| message_history[:received] += 1 }
168
+ subject.__incoming_msgbus__.publish(:message, message)
169
+ expect(message_history[:received]).to eql(1)
170
+ end
171
+ end
172
+
173
+ context '#unsubscribe' do
174
+ let(:callback) do
175
+ Proc.new { |message| message_history[:received] += 1 }
176
+ end
177
+ before do
178
+ subject.subscribe(event_name, &callback)
179
+ end
180
+
181
+ specify 'to all events' do
182
+ subject.unsubscribe &callback
183
+ subject.__incoming_msgbus__.publish(:message, message)
184
+ expect(message_history[:received]).to eql(0)
185
+ end
186
+
187
+ specify 'to specific events' do
188
+ subject.unsubscribe event_name, &callback
189
+ subject.__incoming_msgbus__.publish(:message, message)
190
+ expect(message_history[:received]).to eql(0)
191
+ end
192
+
193
+ specify 'to specific non-matching events' do
194
+ subject.unsubscribe 'move', &callback
195
+ subject.__incoming_msgbus__.publish(:message, message)
196
+ expect(message_history[:received]).to eql(1)
197
+ end
198
+
199
+ specify 'all callbacks by not providing a callback' do
200
+ subject.unsubscribe event_name
201
+ subject.__incoming_msgbus__.publish(:message, message)
202
+ expect(message_history[:received]).to eql(0)
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe Ably::Realtime::Channels do
5
+ let(:connection) { instance_double('Ably::Realtime::Connection', on: true) }
6
+ let(:client) { instance_double('Ably::Realtime::Client', connection: connection) }
7
+ let(:channel_name) { 'unique' }
8
+ let(:options) { { 'bizarre' => 'value' } }
9
+
10
+ subject { Ably::Realtime::Channels.new(client) }
11
+
12
+ context 'creating channels' do
13
+ it '#get creates a channel' do
14
+ expect(Ably::Realtime::Channel).to receive(:new).with(client, channel_name, options)
15
+ subject.get(channel_name, options)
16
+ end
17
+
18
+ it '#get will reuse the channel object' do
19
+ channel = subject.get(channel_name, options)
20
+ expect(channel).to be_a(Ably::Realtime::Channel)
21
+ expect(subject.get(channel_name, options).object_id).to eql(channel.object_id)
22
+ end
23
+
24
+ it '[] creates a channel' do
25
+ expect(Ably::Realtime::Channel).to receive(:new).with(client, channel_name, options)
26
+ subject.get(channel_name, options)
27
+ end
28
+ end
29
+
30
+ context '#fetch' do
31
+ it 'retrieves a channel if it exists' do
32
+ channel = subject.get(channel_name, options)
33
+ expect(subject.fetch(channel_name)).to eql(channel)
34
+ end
35
+
36
+ it 'calls the block if channel is missing' do
37
+ block_called = false
38
+ subject.fetch(channel_name) { block_called = true }
39
+ expect(block_called).to eql(true)
40
+ end
41
+ end
42
+
43
+ context 'destroying channels' do
44
+ it '#release detatches and then releases the channel resoures' do
45
+ released_channel = subject.get(channel_name, options)
46
+ expect(released_channel).to receive(:detach).and_yield
47
+ subject.release(channel_name)
48
+ expect(subject.get(channel_name, options).object_id).to_not eql(released_channel.object_id)
49
+ end
50
+ end
51
+
52
+ context 'is Enumerable' do
53
+ let(:channel_count) { 5 }
54
+ let(:mock_channel) { instance_double('Ably::Realtime::Channel') }
55
+
56
+ before do
57
+ allow(Ably::Realtime::Channel).to receive(:new).and_return(mock_channel)
58
+ channel_count.times { |index| subject.get("channel-#{index}") }
59
+ end
60
+
61
+ it 'allows enumeration' do
62
+ expect(subject.map.count).to eql(channel_count)
63
+ end
64
+
65
+ context '#each' do
66
+ it 'returns an enumerator' do
67
+ expect(subject.each).to be_a(Enumerator)
68
+ end
69
+
70
+ it 'yields each channel' do
71
+ subject.each do |channel|
72
+ expect(channel).to eql(mock_channel)
73
+ end
74
+ end
75
+ end
76
+
77
+ it 'provides #length' do
78
+ expect(subject.length).to eql(channel_count)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'shared/client_initializer_behaviour'
4
+
5
+ describe Ably::Realtime::Client do
6
+ subject do
7
+ Ably::Realtime::Client.new(client_options)
8
+ end
9
+
10
+ it_behaves_like 'a client initializer'
11
+
12
+ context 'delegation to the REST Client' do
13
+ let(:client_options) { { api_key: 'appid.keyuid:keysecret' } }
14
+
15
+ it 'passes on the options to the initializer' do
16
+ rest_client = instance_double('Ably::Rest::Client', auth: instance_double('Ably::Auth'), options: client_options)
17
+ expect(Ably::Rest::Client).to receive(:new).with(client_options).and_return(rest_client)
18
+ subject
19
+ end
20
+
21
+ context 'for attribute' do
22
+ [:environment, :use_tls?, :log_level, :custom_host].each do |attribute|
23
+ specify "##{attribute}" do
24
+ expect(subject.rest_client).to receive(attribute)
25
+ subject.public_send attribute
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+ require 'shared/protocol_msgbus_behaviour'
3
+
4
+ describe Ably::Realtime::Connection do
5
+ let(:client) { instance_double('Ably::Realtime::Client', logger: double('logger').as_null_object) }
6
+
7
+ subject do
8
+ Ably::Realtime::Connection.new(client)
9
+ end
10
+
11
+ before do
12
+ expect(EventMachine).to receive(:next_tick) # non_blocking_loop_while for delivery of messages async
13
+ subject.__incoming_protocol_msgbus__.off
14
+ subject.__outgoing_protocol_msgbus__.off
15
+ end
16
+
17
+ describe 'callbacks' do
18
+ specify 'are supported for valid STATE events' do
19
+ state = nil
20
+ subject.on(:initialized) { state = :ready }
21
+ expect { subject.trigger(:initialized) }.to change { state }.to(:ready)
22
+ end
23
+
24
+ specify 'fail with unacceptable STATE event names' do
25
+ expect { subject.on(:invalid) }.to raise_error KeyError
26
+ expect { subject.trigger(:invalid) }.to raise_error KeyError
27
+ expect { subject.off(:invalid) }.to raise_error KeyError
28
+ end
29
+ end
30
+
31
+ it_behaves_like 'an incoming protocol message bus'
32
+ it_behaves_like 'an outgoing protocol message bus'
33
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ably::Realtime::Client::IncomingMessageDispatcher, :api_private do
4
+ let(:msgbus) do
5
+ Ably::Util::PubSub.new
6
+ end
7
+ let(:connection) do
8
+ instance_double('Ably::Realtime::Connection', __incoming_protocol_msgbus__: msgbus, configure_new: true, id: nil)
9
+ end
10
+ let(:client) do
11
+ instance_double('Ably::Realtime::Client', channels: {})
12
+ end
13
+
14
+ subject { Ably::Realtime::Client::IncomingMessageDispatcher.new(client, connection) }
15
+
16
+ context '#initialize' do
17
+ it 'should subscribe to protocol messages from the connection' do
18
+ expect(msgbus).to receive(:subscribe).with(:protocol_message).and_call_original
19
+ subject
20
+ end
21
+ end
22
+
23
+ context '#dispatch_protocol_message' do
24
+ before { subject }
25
+
26
+ it 'should raise an exception if a message is sent that is not a ProtocolMessage' do
27
+ expect { msgbus.publish :protocol_message, nil }.to raise_error ArgumentError
28
+ end
29
+
30
+ it 'should warn if a message is received for a non-existent channel' do
31
+ allow(subject).to receive_message_chain(:logger, :debug)
32
+ expect(subject).to receive_message_chain(:logger, :warn)
33
+ msgbus.publish :protocol_message, Ably::Models::ProtocolMessage.new(:action => :attached, channel: 'unknown')
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,111 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'shared/protocol_msgbus_behaviour'
4
+
5
+ describe Ably::Realtime::Presence do
6
+ let(:channel) { double('Ably::Realtime::Channel').as_null_object }
7
+
8
+ subject do
9
+ Ably::Realtime::Presence.new(channel)
10
+ end
11
+
12
+ describe 'callbacks' do
13
+ specify 'are supported for valid STATE events' do
14
+ state = nil
15
+ subject.on(:initialized) { state = :entered }
16
+ expect { subject.trigger(:initialized) }.to change { state }.to(:entered)
17
+ end
18
+
19
+ specify 'fail with unacceptable STATE event names' do
20
+ expect { subject.on(:invalid) }.to raise_error KeyError
21
+ expect { subject.trigger(:invalid) }.to raise_error KeyError
22
+ expect { subject.off(:invalid) }.to raise_error KeyError
23
+ end
24
+ end
25
+
26
+ context 'msgbus', :api_private do
27
+ let(:message) do
28
+ Ably::Models::PresenceMessage.new({
29
+ 'action' => 0,
30
+ 'connection_id' => random_str,
31
+ }, instance_double('Ably::Models::ProtocolMessage'))
32
+ end
33
+ let(:msgbus) { subject.__incoming_msgbus__ }
34
+
35
+ specify 'supports messages' do
36
+ received = 0
37
+ msgbus.subscribe(:presence) { received += 1 }
38
+ expect { msgbus.publish(:presence, message) }.to change { received }.to(1)
39
+ end
40
+
41
+ specify 'fail with unacceptable STATE event names' do
42
+ expect { msgbus.subscribe(:invalid) }.to raise_error KeyError
43
+ expect { msgbus.publish(:invalid) }.to raise_error KeyError
44
+ expect { msgbus.unsubscribe(:invalid) }.to raise_error KeyError
45
+ end
46
+ end
47
+
48
+ context 'subscriptions' do
49
+ let(:message_history) { Hash.new { |hash, key| hash[key] = 0 } }
50
+ let(:presence_action) { Ably::Models::PresenceMessage::ACTION.Enter }
51
+ let(:message) do
52
+ instance_double('Ably::Models::PresenceMessage', action: presence_action, connection_id: random_str, decode: true, member_key: random_str)
53
+ end
54
+
55
+ context '#subscribe' do
56
+ before do
57
+ subject.sync_completed
58
+ end
59
+
60
+ specify 'to all presence state actions' do
61
+ subject.subscribe { |message| message_history[:received] += 1}
62
+ subject.__incoming_msgbus__.publish(:presence, message)
63
+ expect(message_history[:received]).to eql(1)
64
+ end
65
+
66
+ specify 'to specific presence state actions' do
67
+ subject.subscribe(presence_action) { |message| message_history[:received] += 1 }
68
+ subject.subscribe(:leave) { |message| message_history[:received] += 1 }
69
+ subject.__incoming_msgbus__.publish(:presence, message)
70
+ expect(message_history[:received]).to eql(1)
71
+ end
72
+ end
73
+
74
+ context '#unsubscribe' do
75
+ before do
76
+ subject.sync_completed
77
+ end
78
+
79
+ let(:callback) do
80
+ Proc.new { |message| message_history[:received] += 1 }
81
+ end
82
+ before do
83
+ subject.subscribe(presence_action, &callback)
84
+ end
85
+
86
+ specify 'to all presence state actions' do
87
+ subject.unsubscribe &callback
88
+ subject.__incoming_msgbus__.publish(:presence, message)
89
+ expect(message_history[:received]).to eql(0)
90
+ end
91
+
92
+ specify 'to specific presence state actions' do
93
+ subject.unsubscribe presence_action, &callback
94
+ subject.__incoming_msgbus__.publish(:presence, message)
95
+ expect(message_history[:received]).to eql(0)
96
+ end
97
+
98
+ specify 'to specific non-matching presence state actions' do
99
+ subject.unsubscribe :leave, &callback
100
+ subject.__incoming_msgbus__.publish(:presence, message)
101
+ expect(message_history[:received]).to eql(1)
102
+ end
103
+
104
+ specify 'all callbacks by not providing a callback' do
105
+ subject.unsubscribe presence_action
106
+ subject.__incoming_msgbus__.publish(:presence, message)
107
+ expect(message_history[:received]).to eql(0)
108
+ end
109
+ end
110
+ end
111
+ end