ably-rest 0.7.3 → 0.7.5
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.
- checksums.yaml +8 -8
- data/.travis.yml +1 -0
- data/SPEC.md +480 -472
- data/lib/ably-rest.rb +1 -1
- data/lib/submodules/ably-ruby/LICENSE.txt +1 -1
- data/lib/submodules/ably-ruby/README.md +107 -24
- data/lib/submodules/ably-ruby/SPEC.md +531 -398
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +24 -16
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +9 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +17 -9
- data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +12 -8
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +18 -10
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +15 -4
- data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +4 -3
- data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +31 -2
- data/lib/submodules/ably-ruby/lib/ably/modules/message_emitter.rb +77 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/safe_deferrable.rb +71 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/safe_yield.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +28 -8
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +0 -5
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +24 -29
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +54 -11
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +21 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +7 -2
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +29 -26
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +4 -4
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +41 -9
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +72 -24
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +26 -4
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +19 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +74 -208
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +264 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_manager.rb +59 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_state_machine.rb +64 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +6 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +3 -1
- data/lib/submodules/ably-ruby/lib/ably/util/safe_deferrable.rb +18 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +28 -6
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +116 -46
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +55 -10
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +32 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +456 -96
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +96 -7
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +8 -0
- data/lib/submodules/ably-ruby/spec/shared/safe_deferrable_behaviour.rb +71 -0
- data/lib/submodules/ably-ruby/spec/support/api_helper.rb +1 -1
- data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +1 -1
- data/lib/submodules/ably-ruby/spec/support/test_app.rb +13 -7
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +15 -14
- data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +4 -4
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +17 -17
- data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +4 -4
- data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +28 -9
- data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +50 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +76 -2
- data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +51 -20
- data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +3 -3
- data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +30 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +52 -26
- data/lib/submodules/ably-ruby/spec/unit/realtime/safe_deferrable_spec.rb +12 -0
- data/spec/spec_helper.rb +5 -0
- metadata +12 -4
- data/lib/submodules/ably-ruby/.ruby-version.old +0 -1
@@ -28,7 +28,7 @@ describe Ably::Models::PresenceMessage do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
context 'with a protocol message with a different connectionId' do
|
31
|
-
let(:model) { subject.new({ 'connectionId' => model_connection_id }, protocol_message) }
|
31
|
+
let(:model) { subject.new({ 'connectionId' => model_connection_id }, protocol_message: protocol_message) }
|
32
32
|
|
33
33
|
it 'uses the model value' do
|
34
34
|
expect(model.connection_id).to eql(model_connection_id)
|
@@ -46,7 +46,7 @@ describe Ably::Models::PresenceMessage do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
context 'with a protocol message with a connectionId' do
|
49
|
-
let(:model) { subject.new({ }, protocol_message) }
|
49
|
+
let(:model) { subject.new({ }, protocol_message: protocol_message) }
|
50
50
|
|
51
51
|
it 'uses the model value' do
|
52
52
|
expect(model.connection_id).to eql(protocol_connection_id)
|
@@ -63,8 +63,8 @@ describe Ably::Models::PresenceMessage do
|
|
63
63
|
end
|
64
64
|
|
65
65
|
context 'with the same client id across multiple connections' do
|
66
|
-
let(:connection_1) { subject.new({ client_id: 'same', connection_id: 'unique' }, protocol_message) }
|
67
|
-
let(:connection_2) { subject.new({ client_id: 'same', connection_id: 'different' }, protocol_message) }
|
66
|
+
let(:connection_1) { subject.new({ client_id: 'same', connection_id: 'unique' }, protocol_message: protocol_message) }
|
67
|
+
let(:connection_2) { subject.new({ client_id: 'same', connection_id: 'different' }, protocol_message: protocol_message) }
|
68
68
|
|
69
69
|
it 'is unique' do
|
70
70
|
expect(connection_1.member_key).to_not eql(connection_2.member_key)
|
@@ -72,8 +72,8 @@ describe Ably::Models::PresenceMessage do
|
|
72
72
|
end
|
73
73
|
|
74
74
|
context 'with a single connection and different client_ids' do
|
75
|
-
let(:client_1) { subject.new({ client_id: 'unique', connection_id: 'same' }, protocol_message) }
|
76
|
-
let(:client_2) { subject.new({ client_id: 'different', connection_id: 'same' }, protocol_message) }
|
75
|
+
let(:client_1) { subject.new({ client_id: 'unique', connection_id: 'same' }, protocol_message: protocol_message) }
|
76
|
+
let(:client_2) { subject.new({ client_id: 'different', connection_id: 'same' }, protocol_message: protocol_message) }
|
77
77
|
|
78
78
|
it 'is unique' do
|
79
79
|
expect(client_1.member_key).to_not eql(client_2.member_key)
|
@@ -82,7 +82,7 @@ describe Ably::Models::PresenceMessage do
|
|
82
82
|
end
|
83
83
|
|
84
84
|
context '#timestamp' do
|
85
|
-
let(:model) { subject.new({}, protocol_message) }
|
85
|
+
let(:model) { subject.new({}, protocol_message: protocol_message) }
|
86
86
|
it 'retrieves attribute :timestamp as a Time object from ProtocolMessage' do
|
87
87
|
expect(model.timestamp).to be_a(Time)
|
88
88
|
expect(model.timestamp.to_i).to be_within(1).of(Time.now.to_i)
|
@@ -90,7 +90,7 @@ describe Ably::Models::PresenceMessage do
|
|
90
90
|
end
|
91
91
|
|
92
92
|
context 'Java naming', :api_private do
|
93
|
-
let(:model) { subject.new({ clientId: 'joe' }, protocol_message) }
|
93
|
+
let(:model) { subject.new({ clientId: 'joe' }, protocol_message: protocol_message) }
|
94
94
|
|
95
95
|
it 'converts the attribute to ruby symbol naming convention' do
|
96
96
|
expect(model.client_id).to eql('joe')
|
@@ -99,7 +99,7 @@ describe Ably::Models::PresenceMessage do
|
|
99
99
|
|
100
100
|
context 'with action', :api_private do
|
101
101
|
context 'absent' do
|
102
|
-
let(:model) { subject.new({ action: 0 }, protocol_message) }
|
102
|
+
let(:model) { subject.new({ action: 0 }, protocol_message: protocol_message) }
|
103
103
|
|
104
104
|
it 'provides action as an Enum' do
|
105
105
|
expect(model.action).to eq(:absent)
|
@@ -107,7 +107,7 @@ describe Ably::Models::PresenceMessage do
|
|
107
107
|
end
|
108
108
|
|
109
109
|
context 'enter' do
|
110
|
-
let(:model) { subject.new({ action: 2 }, protocol_message) }
|
110
|
+
let(:model) { subject.new({ action: 2 }, protocol_message: protocol_message) }
|
111
111
|
|
112
112
|
it 'provides action as an Enum' do
|
113
113
|
expect(model.action).to eq(:enter)
|
@@ -116,7 +116,7 @@ describe Ably::Models::PresenceMessage do
|
|
116
116
|
end
|
117
117
|
|
118
118
|
context 'without action', :api_private do
|
119
|
-
let(:model) { subject.new({}, protocol_message) }
|
119
|
+
let(:model) { subject.new({}, protocol_message: protocol_message) }
|
120
120
|
|
121
121
|
it 'raises an exception when accessed' do
|
122
122
|
expect { model.action }.to raise_error KeyError
|
@@ -129,7 +129,7 @@ describe Ably::Models::PresenceMessage do
|
|
129
129
|
let(:encoded_value) { value.encode(encoding) }
|
130
130
|
let(:value) { random_str }
|
131
131
|
let(:options) { { attribute.to_sym => encoded_value } }
|
132
|
-
let(:model) { subject.new(options, protocol_message) }
|
132
|
+
let(:model) { subject.new(options, protocol_message: protocol_message) }
|
133
133
|
let(:model_attribute) { model.public_send(attribute) }
|
134
134
|
|
135
135
|
context 'as UTF_8 string' do
|
@@ -191,7 +191,7 @@ describe Ably::Models::PresenceMessage do
|
|
191
191
|
let(:json_object) { JSON.parse(model.to_json) }
|
192
192
|
|
193
193
|
context 'with valid data' do
|
194
|
-
let(:model) { subject.new({ action: 'enter', clientId: 'joe' }, protocol_message) }
|
194
|
+
let(:model) { subject.new({ action: 'enter', clientId: 'joe' }, protocol_message: protocol_message) }
|
195
195
|
|
196
196
|
it 'converts the attribute back to Java mixedCase notation using string keys' do
|
197
197
|
expect(json_object["clientId"]).to eql('joe')
|
@@ -199,7 +199,7 @@ describe Ably::Models::PresenceMessage do
|
|
199
199
|
end
|
200
200
|
|
201
201
|
context 'with invalid data' do
|
202
|
-
let(:model) { subject.new({ clientId: 'joe' }, protocol_message) }
|
202
|
+
let(:model) { subject.new({ clientId: 'joe' }, protocol_message: protocol_message) }
|
203
203
|
|
204
204
|
it 'raises an exception' do
|
205
205
|
expect { model.to_json }.to raise_error KeyError, /cannot generate a valid Hash/
|
@@ -208,7 +208,7 @@ describe Ably::Models::PresenceMessage do
|
|
208
208
|
|
209
209
|
context 'with binary data' do
|
210
210
|
let(:data) { MessagePack.pack(random_str(32)) }
|
211
|
-
let(:model) { subject.new({ action: 'enter', data: data }, protocol_message) }
|
211
|
+
let(:model) { subject.new({ action: 'enter', data: data }, protocol_message: protocol_message) }
|
212
212
|
|
213
213
|
it 'encodes as Base64 so that it can be converted to UTF-8 automatically by JSON#dump' do
|
214
214
|
expect(json_object["data"]).to eql(::Base64.encode64(data))
|
@@ -319,7 +319,7 @@ describe Ably::Models::PresenceMessage do
|
|
319
319
|
end
|
320
320
|
|
321
321
|
context 'with ProtocolMessage' do
|
322
|
-
subject { Ably::Models.PresenceMessage(json, protocol_message) }
|
322
|
+
subject { Ably::Models.PresenceMessage(json, protocol_message: protocol_message) }
|
323
323
|
|
324
324
|
it 'returns a PresenceMessage object' do
|
325
325
|
expect(subject).to be_a(Ably::Models::PresenceMessage)
|
@@ -363,7 +363,7 @@ describe Ably::Models::PresenceMessage do
|
|
363
363
|
end
|
364
364
|
|
365
365
|
context 'with ProtocolMessage' do
|
366
|
-
subject { Ably::Models.PresenceMessage(message, protocol_message) }
|
366
|
+
subject { Ably::Models.PresenceMessage(message, protocol_message: protocol_message) }
|
367
367
|
|
368
368
|
it 'returns a PresenceMessage object' do
|
369
369
|
expect(subject).to be_a(Ably::Models::PresenceMessage)
|
@@ -64,22 +64,22 @@ describe Ably::Models::Stat do
|
|
64
64
|
|
65
65
|
describe '#from_interval_id' do
|
66
66
|
it 'converts a month interval_id 2014-02 into a Time object in UTC 0' do
|
67
|
-
expect(subject.from_interval_id('2014-02')).to eql(Time.
|
67
|
+
expect(subject.from_interval_id('2014-02')).to eql(Time.gm(2014, 2))
|
68
68
|
expect(subject.from_interval_id('2014-02').utc_offset).to eql(0)
|
69
69
|
end
|
70
70
|
|
71
71
|
it 'converts a day interval_id 2014-02-03 into a Time object in UTC 0' do
|
72
|
-
expect(subject.from_interval_id('2014-02-03')).to eql(Time.
|
72
|
+
expect(subject.from_interval_id('2014-02-03')).to eql(Time.gm(2014, 2, 3))
|
73
73
|
expect(subject.from_interval_id('2014-02-03').utc_offset).to eql(0)
|
74
74
|
end
|
75
75
|
|
76
76
|
it 'converts an hour interval_id 2014-02-03:05 into a Time object in UTC 0' do
|
77
|
-
expect(subject.from_interval_id('2014-02-03:05')).to eql(Time.
|
77
|
+
expect(subject.from_interval_id('2014-02-03:05')).to eql(Time.gm(2014, 2, 3, 5))
|
78
78
|
expect(subject.from_interval_id('2014-02-03:05').utc_offset).to eql(0)
|
79
79
|
end
|
80
80
|
|
81
81
|
it 'converts a minute interval_id 2014-02-03:05:06 into a Time object in UTC 0' do
|
82
|
-
expect(subject.from_interval_id('2014-02-03:05:06')).to eql(Time.
|
82
|
+
expect(subject.from_interval_id('2014-02-03:05:06')).to eql(Time.gm(2014, 2, 3, 5, 6))
|
83
83
|
expect(subject.from_interval_id('2014-02-03:05:06').utc_offset).to eql(0)
|
84
84
|
end
|
85
85
|
|
@@ -14,6 +14,10 @@ describe Ably::Modules::AsyncWrapper, :api_private do
|
|
14
14
|
def block=(block)
|
15
15
|
@block = block
|
16
16
|
end
|
17
|
+
|
18
|
+
def logger
|
19
|
+
true
|
20
|
+
end
|
17
21
|
end
|
18
22
|
end
|
19
23
|
let(:subject) { class_with_module.new }
|
@@ -33,7 +37,15 @@ describe Ably::Modules::AsyncWrapper, :api_private do
|
|
33
37
|
end
|
34
38
|
end
|
35
39
|
|
36
|
-
it '
|
40
|
+
it 'returns a SafeDeferrable that catches and logs exceptions in the provided callbacks' do
|
41
|
+
run_reactor do
|
42
|
+
deferrable = subject.operation
|
43
|
+
expect(deferrable).to be_a(Ably::Util::SafeDeferrable)
|
44
|
+
stop_reactor
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'calls the provided block with result when provided' do
|
37
49
|
run_reactor do
|
38
50
|
subject.operation do |result|
|
39
51
|
expect(result).to eql(result)
|
@@ -42,10 +54,20 @@ describe Ably::Modules::AsyncWrapper, :api_private do
|
|
42
54
|
end
|
43
55
|
end
|
44
56
|
|
45
|
-
it '
|
57
|
+
it 'catches exceptions in the provided block and logs them to logger' do
|
58
|
+
run_reactor do
|
59
|
+
subject.operation do |result|
|
60
|
+
raise 'Intentional exception'
|
61
|
+
end
|
62
|
+
expect(subject.logger).to receive(:error).with(/Intentional exception/) do
|
63
|
+
stop_reactor
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'returns a SafeDeferrable that calls the callback block' do
|
46
69
|
run_reactor do
|
47
70
|
deferrable = subject.operation
|
48
|
-
expect(deferrable).to be_a(EventMachine::Deferrable)
|
49
71
|
deferrable.callback do |result|
|
50
72
|
expect(result).to eql(result)
|
51
73
|
stop_reactor
|
@@ -56,7 +78,6 @@ describe Ably::Modules::AsyncWrapper, :api_private do
|
|
56
78
|
it 'does not call the errback' do
|
57
79
|
run_reactor do
|
58
80
|
deferrable = subject.operation
|
59
|
-
expect(deferrable).to be_a(EventMachine::Deferrable)
|
60
81
|
deferrable.callback do |result|
|
61
82
|
expect(result).to eql(result)
|
62
83
|
EventMachine.add_timer(sleep_time * 2) { stop_reactor }
|
@@ -88,10 +109,9 @@ describe Ably::Modules::AsyncWrapper, :api_private do
|
|
88
109
|
end
|
89
110
|
end
|
90
111
|
|
91
|
-
it 'calls the errback block of the
|
112
|
+
it 'calls the errback block of the SafeDeferrable' do
|
92
113
|
run_reactor do
|
93
114
|
deferrable = subject.operation
|
94
|
-
expect(deferrable).to be_a(EventMachine::Deferrable)
|
95
115
|
deferrable.errback do |error|
|
96
116
|
expect(error).to be_a(RuntimeError)
|
97
117
|
expect(error.message).to match(/Intentional/)
|
@@ -100,7 +120,7 @@ describe Ably::Modules::AsyncWrapper, :api_private do
|
|
100
120
|
end
|
101
121
|
end
|
102
122
|
|
103
|
-
it 'does not call the
|
123
|
+
it 'does not call the provided block' do
|
104
124
|
run_reactor do
|
105
125
|
subject.operation do |result|
|
106
126
|
raise 'Callback should not have been called'
|
@@ -109,10 +129,9 @@ describe Ably::Modules::AsyncWrapper, :api_private do
|
|
109
129
|
end
|
110
130
|
end
|
111
131
|
|
112
|
-
it 'does not call the callback block of the
|
132
|
+
it 'does not call the callback block of the SafeDeferrable' do
|
113
133
|
run_reactor do
|
114
134
|
deferrable = subject.operation
|
115
|
-
expect(deferrable).to be_a(EventMachine::Deferrable)
|
116
135
|
deferrable.callback do |result|
|
117
136
|
raise 'Callback should not have been called'
|
118
137
|
end
|
@@ -7,6 +7,7 @@ describe Ably::Modules::EventEmitter do
|
|
7
7
|
Class.new do
|
8
8
|
include Ably::Modules::EventEmitter
|
9
9
|
configure_event_emitter callback_opts
|
10
|
+
def logger; end
|
10
11
|
end
|
11
12
|
end
|
12
13
|
let(:obj) { double('example') }
|
@@ -124,6 +125,35 @@ describe Ably::Modules::EventEmitter do
|
|
124
125
|
end
|
125
126
|
end
|
126
127
|
|
128
|
+
context '#on' do
|
129
|
+
it 'calls the block every time an event is emitted only' do
|
130
|
+
block_called = 0
|
131
|
+
subject.on('event') { block_called += 1 }
|
132
|
+
3.times { subject.trigger 'event', 'data' }
|
133
|
+
expect(block_called).to eql(3)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'catches exceptions in the provided block, logs the error and continues' do
|
137
|
+
expect(subject.logger).to receive(:error).with(/Intentional exception/)
|
138
|
+
subject.on(:event) { raise 'Intentional exception' }
|
139
|
+
subject.trigger :event
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context '#unsafe_on', api_private: true do
|
144
|
+
it 'calls the block every time an event is emitted only' do
|
145
|
+
block_called = 0
|
146
|
+
subject.unsafe_on('event') { block_called += 1 }
|
147
|
+
3.times { subject.trigger 'event', 'data' }
|
148
|
+
expect(block_called).to eql(3)
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'does not catch exceptions in provided blocks' do
|
152
|
+
subject.unsafe_on(:event) { raise 'Intentional exception' }
|
153
|
+
expect { subject.trigger :event }.to raise_error(/Intentional exception/)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
127
157
|
context '#once' do
|
128
158
|
it 'calls the block the first time an event is emitted only' do
|
129
159
|
block_called = 0
|
@@ -139,6 +169,26 @@ describe Ably::Modules::EventEmitter do
|
|
139
169
|
3.times { subject.trigger 'event', 'data' }
|
140
170
|
expect(block_called).to eql(4)
|
141
171
|
end
|
172
|
+
|
173
|
+
it 'catches exceptions in the provided block, logs the error and continues' do
|
174
|
+
expect(subject.logger).to receive(:error).with(/Intentional exception/)
|
175
|
+
subject.once(:event) { raise 'Intentional exception' }
|
176
|
+
subject.trigger :event
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context '#unsafe_once' do
|
181
|
+
it 'calls the block the first time an event is emitted only' do
|
182
|
+
block_called = 0
|
183
|
+
subject.unsafe_once('event') { block_called += 1 }
|
184
|
+
3.times { subject.trigger 'event', 'data' }
|
185
|
+
expect(block_called).to eql(1)
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'does not catch exceptions in provided blocks' do
|
189
|
+
subject.unsafe_once(:event) { raise 'Intentional exception' }
|
190
|
+
expect { subject.trigger :event }.to raise_error(/Intentional exception/)
|
191
|
+
end
|
142
192
|
end
|
143
193
|
|
144
194
|
context '#off' do
|
@@ -13,14 +13,17 @@ describe Ably::Modules::StateEmitter do
|
|
13
13
|
)
|
14
14
|
include Ably::Modules::StateEmitter
|
15
15
|
|
16
|
-
def initialize
|
16
|
+
def initialize(logger)
|
17
17
|
@state = :initializing
|
18
|
+
@logger = logger
|
18
19
|
end
|
20
|
+
|
21
|
+
attr_reader :logger
|
19
22
|
end
|
20
23
|
|
21
24
|
let(:initial_state) { :initializing }
|
22
25
|
|
23
|
-
subject { ExampleStateWithEventEmitter.new }
|
26
|
+
subject { ExampleStateWithEventEmitter.new(double('Logger').as_null_object) }
|
24
27
|
|
25
28
|
specify '#state returns current state' do
|
26
29
|
expect(subject.state).to eq(:initializing)
|
@@ -248,6 +251,64 @@ describe Ably::Modules::StateEmitter do
|
|
248
251
|
subject.change_state :connecting, *arguments
|
249
252
|
end
|
250
253
|
end
|
254
|
+
|
255
|
+
context 'with blocks that raise exceptions' do
|
256
|
+
let(:success_block) do
|
257
|
+
proc { raise 'Success exception' }
|
258
|
+
end
|
259
|
+
|
260
|
+
let(:failure_block) do
|
261
|
+
proc { raise 'Failure exception' }
|
262
|
+
end
|
263
|
+
|
264
|
+
let(:target_state) { :connected }
|
265
|
+
|
266
|
+
before do
|
267
|
+
subject.once_or_if target_state, else: failure_block, &success_block
|
268
|
+
end
|
269
|
+
|
270
|
+
context 'success block' do
|
271
|
+
it 'catches exceptions in the provided block, logs the error and continues' do
|
272
|
+
expect(subject.logger).to receive(:error).with(/Success exception/)
|
273
|
+
subject.change_state target_state
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
context 'failure block' do
|
278
|
+
it 'catches exceptions in the provided block, logs the error and continues' do
|
279
|
+
expect(subject.logger).to receive(:error).with(/Failure exception/)
|
280
|
+
subject.change_state :connecting
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
context '#unsafe_once_or_if', :api_private do
|
287
|
+
let(:target_state) { :connected }
|
288
|
+
|
289
|
+
let(:success_block) do
|
290
|
+
proc { raise 'Success exception' }
|
291
|
+
end
|
292
|
+
|
293
|
+
let(:failure_block) do
|
294
|
+
proc { raise 'Failure exception' }
|
295
|
+
end
|
296
|
+
|
297
|
+
before do
|
298
|
+
subject.unsafe_once_or_if target_state, else: failure_block, &success_block
|
299
|
+
end
|
300
|
+
|
301
|
+
context 'success block' do
|
302
|
+
it 'catches exceptions in the provided block, logs the error and continues' do
|
303
|
+
expect { subject.change_state target_state }.to raise_error(/Success exception/)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
context 'failure block' do
|
308
|
+
it 'catches exceptions in the provided block, logs the error and continues' do
|
309
|
+
expect { subject.change_state :connecting }.to raise_error(/Failure exception/)
|
310
|
+
end
|
311
|
+
end
|
251
312
|
end
|
252
313
|
|
253
314
|
context '#once_state_changed', :api_private do
|
@@ -279,5 +340,18 @@ describe Ably::Modules::StateEmitter do
|
|
279
340
|
expect(block_calls.count).to eql(1)
|
280
341
|
expect(block_calls.first).to contain_exactly(1, 2)
|
281
342
|
end
|
343
|
+
|
344
|
+
it 'catches exceptions in the provided block, logs the error and continues' do
|
345
|
+
subject.once_state_changed { raise 'Intentional exception' }
|
346
|
+
expect(subject.logger).to receive(:error).with(/Intentional exception/)
|
347
|
+
subject.change_state :connected
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
context '#unsafe_once_state_changed', :api_private do
|
352
|
+
it 'does not catch exceptions in the provided block' do
|
353
|
+
subject.unsafe_once_state_changed { raise 'Intentional exception' }
|
354
|
+
expect { subject.change_state :connected }.to raise_error(/Intentional exception/)
|
355
|
+
end
|
282
356
|
end
|
283
357
|
end
|
@@ -133,7 +133,7 @@ describe Ably::Realtime::Channel do
|
|
133
133
|
Ably::Models::Message.new({
|
134
134
|
'name' => 'test',
|
135
135
|
'data' => 'payload'
|
136
|
-
}, instance_double('Ably::Models::ProtocolMessage'))
|
136
|
+
}, protocol_message: instance_double('Ably::Models::ProtocolMessage'))
|
137
137
|
end
|
138
138
|
let(:msgbus) { subject.__incoming_msgbus__ }
|
139
139
|
|
@@ -152,20 +152,45 @@ describe Ably::Realtime::Channel do
|
|
152
152
|
|
153
153
|
context 'subscriptions' do
|
154
154
|
let(:message_history) { Hash.new { |hash, key| hash[key] = 0 } }
|
155
|
-
let(:
|
156
|
-
let(:
|
155
|
+
let(:click_event) { 'click' }
|
156
|
+
let(:click_message) { instance_double('Ably::Models::Message', name: click_event, encode: nil, decode: nil) }
|
157
|
+
let(:focus_event) { 'focus' }
|
158
|
+
let(:focus_message) { instance_double('Ably::Models::Message', name: focus_event, encode: nil, decode: nil) }
|
159
|
+
let(:blur_message) { instance_double('Ably::Models::Message', name: 'blur', encode: nil, decode: nil) }
|
157
160
|
|
158
161
|
context '#subscribe' do
|
159
|
-
specify '
|
162
|
+
specify 'without a block raises an invalid ArgumentError' do
|
163
|
+
expect { subject.subscribe }.to raise_error ArgumentError
|
164
|
+
end
|
165
|
+
|
166
|
+
specify 'with no event name specified subscribes the provided block to all events' do
|
160
167
|
subject.subscribe { |message| message_history[:received] += 1}
|
161
|
-
subject.__incoming_msgbus__.publish(:message,
|
168
|
+
subject.__incoming_msgbus__.publish(:message, click_message)
|
169
|
+
expect(message_history[:received]).to eql(1)
|
170
|
+
end
|
171
|
+
|
172
|
+
specify 'with a single event name subscribes that block to matching events' do
|
173
|
+
subject.subscribe(click_event) { |message| message_history[:received] += 1 }
|
174
|
+
subject.subscribe('non_match_move') { |message| message_history[:received] += 1 }
|
175
|
+
subject.__incoming_msgbus__.publish(:message, click_message)
|
176
|
+
expect(message_history[:received]).to eql(1)
|
177
|
+
end
|
178
|
+
|
179
|
+
specify 'with a multiple event name arguments subscribes that block to all of those event names' do
|
180
|
+
subject.subscribe(focus_event, click_event) { |message| message_history[:received] += 1 }
|
181
|
+
subject.__incoming_msgbus__.publish(:message, click_message)
|
162
182
|
expect(message_history[:received]).to eql(1)
|
183
|
+
subject.__incoming_msgbus__.publish(:message, focus_message)
|
184
|
+
expect(message_history[:received]).to eql(2)
|
185
|
+
|
186
|
+
# Blur does not match subscribed focus & click events
|
187
|
+
subject.__incoming_msgbus__.publish(:message, blur_message)
|
188
|
+
expect(message_history[:received]).to eql(2)
|
163
189
|
end
|
164
190
|
|
165
|
-
specify 'to
|
166
|
-
subject.subscribe(
|
167
|
-
subject.
|
168
|
-
subject.__incoming_msgbus__.publish(:message, message)
|
191
|
+
specify 'with a multiple duplicate event name arguments subscribes that block to all of those unique event names once' do
|
192
|
+
subject.subscribe(click_event, click_event) { |message| message_history[:received] += 1 }
|
193
|
+
subject.__incoming_msgbus__.publish(:message, click_message)
|
169
194
|
expect(message_history[:received]).to eql(1)
|
170
195
|
end
|
171
196
|
end
|
@@ -175,30 +200,36 @@ describe Ably::Realtime::Channel do
|
|
175
200
|
Proc.new { |message| message_history[:received] += 1 }
|
176
201
|
end
|
177
202
|
before do
|
178
|
-
subject.subscribe(
|
203
|
+
subject.subscribe(click_event, &callback)
|
179
204
|
end
|
180
205
|
|
181
|
-
specify '
|
206
|
+
specify 'with no event name specified unsubscribes that block from all events' do
|
182
207
|
subject.unsubscribe &callback
|
183
|
-
subject.__incoming_msgbus__.publish(:message,
|
208
|
+
subject.__incoming_msgbus__.publish(:message, click_message)
|
209
|
+
expect(message_history[:received]).to eql(0)
|
210
|
+
end
|
211
|
+
|
212
|
+
specify 'with a single event name argument unsubscribes the provided block with the matching event name' do
|
213
|
+
subject.unsubscribe click_event, &callback
|
214
|
+
subject.__incoming_msgbus__.publish(:message, click_message)
|
184
215
|
expect(message_history[:received]).to eql(0)
|
185
216
|
end
|
186
217
|
|
187
|
-
specify '
|
188
|
-
subject.unsubscribe
|
189
|
-
subject.__incoming_msgbus__.publish(:message,
|
218
|
+
specify 'with multiple event name arguments unsubscribes each of those matching event names with the provided block' do
|
219
|
+
subject.unsubscribe focus_event, click_event, &callback
|
220
|
+
subject.__incoming_msgbus__.publish(:message, click_message)
|
190
221
|
expect(message_history[:received]).to eql(0)
|
191
222
|
end
|
192
223
|
|
193
|
-
specify '
|
224
|
+
specify 'with a non-matching event name argument has no effect' do
|
194
225
|
subject.unsubscribe 'move', &callback
|
195
|
-
subject.__incoming_msgbus__.publish(:message,
|
226
|
+
subject.__incoming_msgbus__.publish(:message, click_message)
|
196
227
|
expect(message_history[:received]).to eql(1)
|
197
228
|
end
|
198
229
|
|
199
|
-
specify 'all
|
200
|
-
subject.unsubscribe
|
201
|
-
subject.__incoming_msgbus__.publish(:message,
|
230
|
+
specify 'with no block argument unsubscribes all blocks for the event name argument' do
|
231
|
+
subject.unsubscribe click_event
|
232
|
+
subject.__incoming_msgbus__.publish(:message, click_message)
|
202
233
|
expect(message_history[:received]).to eql(0)
|
203
234
|
end
|
204
235
|
end
|