ably 1.1.8 → 1.2.0
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 +4 -4
- data/CHANGELOG.md +46 -0
- data/README.md +1 -1
- data/UPDATING.md +30 -0
- data/lib/ably/auth.rb +3 -3
- data/lib/ably/models/channel_options.rb +97 -0
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -0
- data/lib/ably/models/message.rb +4 -4
- data/lib/ably/models/protocol_message.rb +17 -5
- data/lib/ably/models/token_details.rb +7 -2
- data/lib/ably/modules/channels_collection.rb +22 -2
- data/lib/ably/modules/conversions.rb +34 -0
- data/lib/ably/realtime/channel/channel_manager.rb +16 -4
- data/lib/ably/realtime/channel/channel_state_machine.rb +5 -0
- data/lib/ably/realtime/channel.rb +54 -24
- data/lib/ably/realtime/channels.rb +1 -1
- data/lib/ably/rest/channel.rb +26 -34
- data/lib/ably/rest/client.rb +4 -1
- data/lib/ably/util/crypto.rb +1 -1
- data/lib/ably/version.rb +2 -2
- data/spec/acceptance/realtime/channel_spec.rb +247 -21
- data/spec/acceptance/realtime/channels_spec.rb +59 -7
- data/spec/acceptance/realtime/connection_spec.rb +1 -1
- data/spec/acceptance/realtime/message_spec.rb +77 -0
- data/spec/acceptance/rest/auth_spec.rb +18 -0
- data/spec/acceptance/rest/channel_spec.rb +1 -1
- data/spec/acceptance/rest/channels_spec.rb +22 -5
- data/spec/acceptance/rest/client_spec.rb +2 -2
- data/spec/acceptance/rest/message_spec.rb +61 -3
- data/spec/lib/unit/models/channel_options_spec.rb +52 -0
- data/spec/unit/models/message_spec.rb +14 -0
- data/spec/unit/models/protocol_message_spec.rb +53 -7
- data/spec/unit/models/token_details_spec.rb +14 -0
- data/spec/unit/realtime/channels_spec.rb +52 -14
- data/spec/unit/rest/channels_spec.rb +81 -14
- metadata +21 -3
@@ -1165,6 +1165,24 @@ describe Ably::Auth do
|
|
1165
1165
|
end
|
1166
1166
|
end
|
1167
1167
|
|
1168
|
+
context 'when token does not expire' do
|
1169
|
+
let(:client_options) { default_options.merge(use_token_auth: true, key: api_key, query_time: true) }
|
1170
|
+
let(:channel) { client.channels.get(random_str) }
|
1171
|
+
|
1172
|
+
context 'for the next 2 hours' do
|
1173
|
+
let(:local_time) { Time.now - 2 * 60 * 60 }
|
1174
|
+
|
1175
|
+
before { allow(Time).to receive(:now).and_return(local_time) }
|
1176
|
+
|
1177
|
+
it 'should not request for the new token (#RSA4b1)' do
|
1178
|
+
expect { channel.publish 'event' }.to change { auth.current_token_details }
|
1179
|
+
expect do
|
1180
|
+
expect { channel.publish 'event' }.not_to change { auth.current_token_details }
|
1181
|
+
end.not_to change { auth.current_token_details.expires }
|
1182
|
+
end
|
1183
|
+
end
|
1184
|
+
end
|
1185
|
+
|
1168
1186
|
context 'when :client_id is provided in a token' do
|
1169
1187
|
let(:client_id) { '123' }
|
1170
1188
|
let(:token) do
|
@@ -5,7 +5,7 @@ describe Ably::Rest::Channel do
|
|
5
5
|
include Ably::Modules::Conversions
|
6
6
|
|
7
7
|
vary_by_protocol do
|
8
|
-
let(:default_options) { { key: api_key, environment: environment, protocol: protocol, max_frame_size: max_frame_size, max_message_size: max_message_size } }
|
8
|
+
let(:default_options) { { key: api_key, environment: environment, protocol: protocol, max_frame_size: max_frame_size, max_message_size: max_message_size, idempotent_rest_publishing: false } }
|
9
9
|
let(:client_options) { default_options }
|
10
10
|
let(:client) do
|
11
11
|
Ably::Rest::Client.new(client_options)
|
@@ -5,11 +5,11 @@ describe Ably::Rest::Channels do
|
|
5
5
|
shared_examples 'a channel' do
|
6
6
|
it 'returns a channel object' do
|
7
7
|
expect(channel).to be_a Ably::Rest::Channel
|
8
|
-
expect(channel.name).to
|
8
|
+
expect(channel.name).to eq(channel_name)
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'returns channel object and passes the provided options' do
|
12
|
-
expect(channel_with_options.options).to
|
12
|
+
expect(channel_with_options.options.to_h).to eq(options)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -32,12 +32,29 @@ describe Ably::Rest::Channels do
|
|
32
32
|
it_behaves_like 'a channel'
|
33
33
|
end
|
34
34
|
|
35
|
+
describe '#set_options (#RTL16)' do
|
36
|
+
let(:channel) { client.channel(channel_name) }
|
37
|
+
|
38
|
+
it "updates channel's options" do
|
39
|
+
expect { channel.options = options }.to change { channel.options.to_h }.from({}).to(options)
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when providing Ably::Models::ChannelOptions object' do
|
43
|
+
let(:options_object) { Ably::Models::ChannelOptions.new(options) }
|
44
|
+
|
45
|
+
it "updates channel's options" do
|
46
|
+
expect { channel.options = options_object}.to change { channel.options.to_h }.from({}).to(options)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
35
51
|
describe 'accessing an existing channel object with different options' do
|
36
52
|
let(:new_channel_options) { { encrypted: true } }
|
37
53
|
let(:original_channel) { client.channels.get(channel_name, options) }
|
38
54
|
|
39
55
|
it 'overrides the existing channel options and returns the channel object (RSN3c)' do
|
40
|
-
expect(original_channel.options).to_not include(:encrypted)
|
56
|
+
expect(original_channel.options.to_h).to_not include(:encrypted)
|
57
|
+
|
41
58
|
new_channel = client.channels.get(channel_name, new_channel_options)
|
42
59
|
expect(new_channel).to be_a(Ably::Rest::Channel)
|
43
60
|
expect(new_channel.options[:encrypted]).to eql(true)
|
@@ -48,10 +65,10 @@ describe Ably::Rest::Channels do
|
|
48
65
|
let(:original_channel) { client.channels.get(channel_name, options) }
|
49
66
|
|
50
67
|
it 'returns the existing channel without modifying the channel options' do
|
51
|
-
expect(original_channel.options).to
|
68
|
+
expect(original_channel.options.to_h).to eq(options)
|
52
69
|
new_channel = client.channels.get(channel_name)
|
53
70
|
expect(new_channel).to be_a(Ably::Rest::Channel)
|
54
|
-
expect(original_channel.options).to
|
71
|
+
expect(original_channel.options.to_h).to eq(options)
|
55
72
|
end
|
56
73
|
end
|
57
74
|
|
@@ -1097,7 +1097,7 @@ describe Ably::Rest::Client do
|
|
1097
1097
|
it 'sends a protocol version and lib version header (#G4, #RSC7a, #RSC7b)' do
|
1098
1098
|
client.channels.get('foo').publish("event")
|
1099
1099
|
expect(publish_message_stub).to have_been_requested
|
1100
|
-
expect(Ably::PROTOCOL_VERSION).to eql('1.
|
1100
|
+
expect(Ably::PROTOCOL_VERSION).to eql('1.2')
|
1101
1101
|
end
|
1102
1102
|
end
|
1103
1103
|
end
|
@@ -1231,7 +1231,7 @@ describe Ably::Rest::Client do
|
|
1231
1231
|
end
|
1232
1232
|
end
|
1233
1233
|
|
1234
|
-
context 'request_id generation' do
|
1234
|
+
context 'request_id generation (#RSC7c)' do
|
1235
1235
|
context 'Timeout error' do
|
1236
1236
|
context 'with option add_request_ids: true and no fallback hosts', :webmock, :prevent_log_stubbing do
|
1237
1237
|
let(:custom_logger_object) { TestLogger.new }
|
@@ -24,6 +24,57 @@ describe Ably::Rest::Channel, 'messages' do
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
context 'a single Message object (#RSL1a)' do
|
28
|
+
let(:name) { random_str }
|
29
|
+
let(:data) { random_str }
|
30
|
+
let(:message) { Ably::Models::Message.new(name: name, data: data) }
|
31
|
+
|
32
|
+
it 'publishes the message' do
|
33
|
+
channel.publish(message)
|
34
|
+
expect(channel.history.items.length).to eql(1)
|
35
|
+
message = channel.history.items.first
|
36
|
+
expect(message.name).to eq(name)
|
37
|
+
expect(message.data).to eq(data)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'an array of Message objects (#RSL1a)' do
|
42
|
+
let(:data) { random_str }
|
43
|
+
let(:message1) { Ably::Models::Message.new(name: random_str, data: data) }
|
44
|
+
let(:message2) { Ably::Models::Message.new(name: random_str, data: data) }
|
45
|
+
let(:message3) { Ably::Models::Message.new(name: random_str, data: data) }
|
46
|
+
|
47
|
+
it 'publishes three messages' do
|
48
|
+
channel.publish([message1, message2, message3])
|
49
|
+
expect(channel.history.items.length).to eql(3)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'an array of hashes (#RSL1a)' do
|
54
|
+
let(:data) { random_str }
|
55
|
+
let(:message1) { { name: random_str, data: data } }
|
56
|
+
let(:message2) { { name: random_str, data: data } }
|
57
|
+
let(:message3) { { name: random_str, data: data } }
|
58
|
+
|
59
|
+
it 'publishes three messages' do
|
60
|
+
channel.publish([message1, message2, message3])
|
61
|
+
expect(channel.history.items.length).to eql(3)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'a name with data payload (#RSL1a, #RSL1b)' do
|
66
|
+
let(:name) { random_str }
|
67
|
+
let(:data) { random_str }
|
68
|
+
|
69
|
+
it 'publishes the message' do
|
70
|
+
channel.publish(name, data)
|
71
|
+
expect(channel.history.items.length).to eql(1)
|
72
|
+
message = channel.history.items.first
|
73
|
+
expect(message.name).to eq(name)
|
74
|
+
expect(message.data).to eq(data)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
27
78
|
context 'with supported data payload content type' do
|
28
79
|
context 'JSON Object (Hash)' do
|
29
80
|
let(:data) { { 'Hash' => 'true' } }
|
@@ -153,13 +204,20 @@ describe Ably::Rest::Channel, 'messages' do
|
|
153
204
|
end
|
154
205
|
end
|
155
206
|
|
156
|
-
specify 'idempotent publishing is disabled by default with 1.1 (#TO3n)' do
|
207
|
+
specify 'idempotent publishing is disabled by default with <= 1.1 (#TO3n)' do
|
208
|
+
stub_const 'Ably::PROTOCOL_VERSION', '1.0'
|
209
|
+
client = Ably::Rest::Client.new(key: api_key, protocol: protocol)
|
210
|
+
expect(client.idempotent_rest_publishing).to be_falsey
|
211
|
+
stub_const 'Ably::PROTOCOL_VERSION', '1.1'
|
157
212
|
client = Ably::Rest::Client.new(key: api_key, protocol: protocol)
|
158
213
|
expect(client.idempotent_rest_publishing).to be_falsey
|
159
214
|
end
|
160
215
|
|
161
|
-
specify 'idempotent publishing is enabled by default with 1.2 (#TO3n)' do
|
162
|
-
stub_const 'Ably::
|
216
|
+
specify 'idempotent publishing is enabled by default with >= 1.2 (#TO3n)' do
|
217
|
+
stub_const 'Ably::PROTOCOL_VERSION', '1.2'
|
218
|
+
client = Ably::Rest::Client.new(key: api_key, protocol: protocol)
|
219
|
+
expect(client.idempotent_rest_publishing).to be_truthy
|
220
|
+
stub_const 'Ably::PROTOCOL_VERSION', '1.3'
|
163
221
|
client = Ably::Rest::Client.new(key: api_key, protocol: protocol)
|
164
222
|
expect(client.idempotent_rest_publishing).to be_truthy
|
165
223
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Ably::Models::ChannelOptions do
|
6
|
+
let(:modes) { nil }
|
7
|
+
let(:params) { {} }
|
8
|
+
let(:options) { described_class.new(modes: modes, params: params) }
|
9
|
+
|
10
|
+
describe '#modes_to_flags' do
|
11
|
+
let(:modes) { %w[publish subscribe presence_subscribe] }
|
12
|
+
|
13
|
+
subject(:protocol_message) do
|
14
|
+
Ably::Models::ProtocolMessage.new(action: Ably::Models::ProtocolMessage::ACTION.Attach, flags: options.modes_to_flags)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'converts modes to ProtocolMessage#flags correctly' do
|
18
|
+
expect(protocol_message.has_attach_publish_flag?).to eq(true)
|
19
|
+
expect(protocol_message.has_attach_subscribe_flag?).to eq(true)
|
20
|
+
expect(protocol_message.has_attach_presence_subscribe_flag?).to eq(true)
|
21
|
+
|
22
|
+
expect(protocol_message.has_attach_resume_flag?).to eq(false)
|
23
|
+
expect(protocol_message.has_attach_presence_flag?).to eq(false)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#set_modes_from_flags' do
|
28
|
+
let(:subscribe_flag) { 262144 }
|
29
|
+
|
30
|
+
it 'converts flags to ChannelOptions#modes correctly' do
|
31
|
+
result = options.set_modes_from_flags(subscribe_flag)
|
32
|
+
|
33
|
+
expect(result).to eq(options.modes)
|
34
|
+
expect(options.modes.map(&:to_sym)).to eq(%i[subscribe])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#set_params' do
|
39
|
+
let(:previous_params) { { example_attribute: 1 } }
|
40
|
+
let(:new_params) { { new_attribute: 1 } }
|
41
|
+
let(:params) { previous_params }
|
42
|
+
|
43
|
+
it 'should be able to overwrite attributes' do
|
44
|
+
expect { options.set_params(new_params) }.to \
|
45
|
+
change { options.params }.from(previous_params).to(new_params)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should be able to make params empty' do # (1)
|
49
|
+
expect { options.set_params({}) }.to change { options.params }.from(previous_params).to({})
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -270,6 +270,20 @@ describe Ably::Models::Message do
|
|
270
270
|
end
|
271
271
|
end
|
272
272
|
|
273
|
+
describe '#protocol_message_index (#RTL21)' do
|
274
|
+
let(:messages) { [{ name: 'test1' }, { name: 'test2' }, { name: 'test3' }] }
|
275
|
+
|
276
|
+
let(:protocol_message) do
|
277
|
+
Ably::Models::ProtocolMessage.new({ action: 1 }.merge(messages: messages))
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'should return correct protocol_message_index' do
|
281
|
+
expect(protocol_message.messages[0].protocol_message_index).to eq(0)
|
282
|
+
expect(protocol_message.messages[1].protocol_message_index).to eq(1)
|
283
|
+
expect(protocol_message.messages[2].protocol_message_index).to eq(2)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
273
287
|
context 'from REST request with embedded fields', :api_private do
|
274
288
|
let(:id) { random_str }
|
275
289
|
let(:protocol_message_id) { random_str }
|
@@ -223,6 +223,24 @@ describe Ably::Models::ProtocolMessage do
|
|
223
223
|
end
|
224
224
|
end
|
225
225
|
|
226
|
+
context '#params (#RTL4k1)' do
|
227
|
+
let(:params) do
|
228
|
+
{ foo: :bar }
|
229
|
+
end
|
230
|
+
|
231
|
+
context 'when present' do
|
232
|
+
specify do
|
233
|
+
expect(new_protocol_message({ params: params }).params).to eq(params)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
context 'when empty' do
|
238
|
+
specify do
|
239
|
+
expect(new_protocol_message({}).params).to eq({})
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
226
244
|
context '#has_connection_serial?' do
|
227
245
|
context 'without connection_serial' do
|
228
246
|
let(:protocol_message) { new_protocol_message({}) }
|
@@ -330,6 +348,26 @@ describe Ably::Models::ProtocolMessage do
|
|
330
348
|
end
|
331
349
|
end
|
332
350
|
|
351
|
+
context '#messages (#RTL21)' do
|
352
|
+
let(:protocol_message) do
|
353
|
+
new_protocol_message(messages: [{ name: 'test1' }, { name: 'test2' }, { name: 'test3' }])
|
354
|
+
end
|
355
|
+
|
356
|
+
before do
|
357
|
+
message = Ably::Models::Message(name: 'test4')
|
358
|
+
message.assign_to_protocol_message(protocol_message)
|
359
|
+
protocol_message.add_message(message)
|
360
|
+
end
|
361
|
+
|
362
|
+
it 'contains Message objects in ascending order' do
|
363
|
+
expect(protocol_message.messages.count).to eql(4)
|
364
|
+
protocol_message.messages.each_with_index do |message, index|
|
365
|
+
expect(message.protocol_message_index).to eql(index)
|
366
|
+
expect(message.name).to include('test')
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
333
371
|
context '#presence (#TR4l)' do
|
334
372
|
let(:protocol_message) { new_protocol_message(presence: [{ action: 1, data: 'test' }]) }
|
335
373
|
|
@@ -443,19 +481,23 @@ describe Ably::Models::ProtocolMessage do
|
|
443
481
|
|
444
482
|
context '#to_json', :api_private do
|
445
483
|
let(:json_object) { JSON.parse(model.to_json) }
|
446
|
-
let(:
|
484
|
+
let(:message1) { { 'name' => 'event1', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
485
|
+
let(:message2) { { 'name' => 'event2', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
486
|
+
let(:message3) { { 'name' => 'event3', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
447
487
|
let(:attached_action) { Ably::Models::ProtocolMessage::ACTION.Attached }
|
448
488
|
let(:message_action) { Ably::Models::ProtocolMessage::ACTION.Message }
|
449
489
|
|
450
490
|
context 'with valid data' do
|
451
|
-
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [
|
491
|
+
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [message1, message2, message3] }) }
|
452
492
|
|
453
493
|
it 'converts the attribute back to Java mixedCase notation using string keys' do
|
454
494
|
expect(json_object["channelSerial"]).to eql('unique')
|
455
495
|
end
|
456
496
|
|
457
497
|
it 'populates the messages' do
|
458
|
-
expect(json_object["messages"]
|
498
|
+
expect(json_object["messages"][0]).to include(message1)
|
499
|
+
expect(json_object["messages"][1]).to include(message2)
|
500
|
+
expect(json_object["messages"][2]).to include(message3)
|
459
501
|
end
|
460
502
|
end
|
461
503
|
|
@@ -468,7 +510,7 @@ describe Ably::Models::ProtocolMessage do
|
|
468
510
|
end
|
469
511
|
|
470
512
|
context 'is aliased by #to_s' do
|
471
|
-
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [
|
513
|
+
let(:model) { new_protocol_message({ :action => attached_action, :channelSerial => 'unique', messages: [message1, message2, message3], :timestamp => as_since_epoch(Time.now) }) }
|
472
514
|
|
473
515
|
specify do
|
474
516
|
expect(json_object).to eql(JSON.parse("#{model}"))
|
@@ -477,14 +519,18 @@ describe Ably::Models::ProtocolMessage do
|
|
477
519
|
end
|
478
520
|
|
479
521
|
context '#to_msgpack', :api_private do
|
480
|
-
let(:model) { new_protocol_message({ :connectionSerial => 'unique', messages: [
|
481
|
-
let(:
|
522
|
+
let(:model) { new_protocol_message({ :connectionSerial => 'unique', messages: [message1, message2, message3] }) }
|
523
|
+
let(:message1) { { 'name' => 'event1', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
524
|
+
let(:message2) { { 'name' => 'event2', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
525
|
+
let(:message3) { { 'name' => 'event3', 'clientId' => 'joe', 'timestamp' => as_since_epoch(Time.now) } }
|
482
526
|
let(:packed) { model.to_msgpack }
|
483
527
|
let(:unpacked) { MessagePack.unpack(packed) }
|
484
528
|
|
485
529
|
it 'returns a unpackable msgpack object' do
|
486
530
|
expect(unpacked['connectionSerial']).to eq('unique')
|
487
|
-
expect(unpacked['messages'][0]['name']).to eq('
|
531
|
+
expect(unpacked['messages'][0]['name']).to eq('event1')
|
532
|
+
expect(unpacked['messages'][1]['name']).to eq('event2')
|
533
|
+
expect(unpacked['messages'][2]['name']).to eq('event3')
|
488
534
|
end
|
489
535
|
end
|
490
536
|
end
|
@@ -80,6 +80,20 @@ describe Ably::Models::TokenDetails do
|
|
80
80
|
expect(subject.expired?).to eql(false)
|
81
81
|
end
|
82
82
|
end
|
83
|
+
|
84
|
+
context 'with :from attribute' do
|
85
|
+
subject { Ably::Models::TokenDetails.new(expires: expire_time) }
|
86
|
+
|
87
|
+
let(:server_offset_time) { 2 * 60 * 60 } # 2 hours
|
88
|
+
|
89
|
+
it 'is false' do
|
90
|
+
expect(subject.expired?(from: (Time.now - server_offset_time))).to eql(false)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'is true' do
|
94
|
+
expect(subject.expired?(from: Time.now)).to eql(true)
|
95
|
+
end
|
96
|
+
end
|
83
97
|
end
|
84
98
|
end
|
85
99
|
|
@@ -3,39 +3,77 @@ require 'spec_helper'
|
|
3
3
|
|
4
4
|
describe Ably::Realtime::Channels do
|
5
5
|
let(:connection) { instance_double('Ably::Realtime::Connection', unsafe_on: true, on_resume: true) }
|
6
|
-
let(:client)
|
6
|
+
let(:client) do
|
7
|
+
instance_double('Ably::Realtime::Client', connection: connection, client_id: 'clientId', logger: double('logger').as_null_object)
|
8
|
+
end
|
7
9
|
let(:channel_name) { 'unique' }
|
8
|
-
let(:options)
|
10
|
+
let(:options) do
|
11
|
+
{ params: { bizarre: 'value' } }
|
12
|
+
end
|
9
13
|
|
10
14
|
subject { Ably::Realtime::Channels.new(client) }
|
11
15
|
|
12
16
|
context 'creating channels' do
|
13
17
|
context '#get' do
|
14
|
-
|
15
|
-
|
16
|
-
|
18
|
+
context "when channel doesn't exist" do
|
19
|
+
shared_examples 'creates a channel' do
|
20
|
+
it 'creates a channel (RTS3a)' do
|
21
|
+
expect(Ably::Realtime::Channel).to receive(:new).with(client, channel_name, channel_options)
|
22
|
+
subject.get(channel_name, channel_options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'hash' do
|
27
|
+
let(:channel_options) { options }
|
28
|
+
it { expect(channel_options).to be_a(Hash) }
|
29
|
+
|
30
|
+
include_examples 'creates a channel'
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'ChannelOptions object' do
|
34
|
+
let(:channel_options) { Ably::Models::ChannelOptions.new(options) }
|
35
|
+
it { expect(channel_options).to be_a(Ably::Models::ChannelOptions) }
|
36
|
+
|
37
|
+
include_examples 'creates a channel'
|
38
|
+
end
|
17
39
|
end
|
18
40
|
|
19
41
|
context 'when an existing channel exists' do
|
20
|
-
|
21
|
-
channel
|
22
|
-
|
23
|
-
|
42
|
+
shared_examples 'reuse a channel object if it exists' do
|
43
|
+
it 'will reuse a channel object if it exists (RTS3a)' do
|
44
|
+
channel = subject.get(channel_name, channel_options)
|
45
|
+
expect(channel).to be_a(Ably::Realtime::Channel)
|
46
|
+
expect(subject.get(channel_name, channel_options).object_id).to eql(channel.object_id)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'hash' do
|
51
|
+
let(:channel_options) { options }
|
52
|
+
it { expect(channel_options).to be_a(Hash) }
|
53
|
+
|
54
|
+
include_examples 'reuse a channel object if it exists'
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'ChannelOptions object' do
|
58
|
+
let(:channel_options) { Ably::Models::ChannelOptions.new(options) }
|
59
|
+
it { expect(channel_options).to be_a(Ably::Models::ChannelOptions) }
|
60
|
+
|
61
|
+
include_examples 'reuse a channel object if it exists'
|
24
62
|
end
|
25
63
|
|
26
64
|
it 'will update the options on the channel if provided (RSN3c)' do
|
27
65
|
channel = subject.get(channel_name, options)
|
28
|
-
expect(channel.options).to
|
29
|
-
expect(channel.options).to_not include(:encrypted)
|
66
|
+
expect(channel.options.to_h).to eq(options)
|
67
|
+
expect(channel.options.to_h).to_not include(:encrypted)
|
30
68
|
subject.get(channel_name, encrypted: true)
|
31
|
-
expect(channel.options[:encrypted]).to
|
69
|
+
expect(channel.options[:encrypted]).to eq(true)
|
32
70
|
end
|
33
71
|
|
34
72
|
it 'will leave the options intact on the channel if not provided' do
|
35
73
|
channel = subject.get(channel_name, options)
|
36
|
-
expect(channel.options).to
|
74
|
+
expect(channel.options.to_h).to eq(options)
|
37
75
|
subject.get(channel_name)
|
38
|
-
expect(channel.options).to
|
76
|
+
expect(channel.options.to_h).to eq(options)
|
39
77
|
end
|
40
78
|
end
|
41
79
|
end
|
@@ -2,30 +2,97 @@
|
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
4
|
describe Ably::Rest::Channels do
|
5
|
-
let(:client) { instance_double('Ably::Rest::Client') }
|
5
|
+
let(:client) { instance_double('Ably::Rest::Client', logger: double('logger').as_null_object) }
|
6
6
|
let(:channel_name) { 'unique'.encode(Encoding::UTF_8) }
|
7
|
-
let(:options)
|
7
|
+
let(:options) do
|
8
|
+
{ params: { 'bizarre' => 'value' } }
|
9
|
+
end
|
8
10
|
|
9
11
|
subject { Ably::Rest::Channels.new(client) }
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
describe '#get' do
|
14
|
+
context "when channel doesn't exist" do
|
15
|
+
shared_examples 'creates a channel' do
|
16
|
+
it 'creates a channel (RSN3a)' do
|
17
|
+
expect(Ably::Rest::Channel).to receive(:new).with(client, channel_name, options)
|
18
|
+
subject.get(channel_name, options)
|
19
|
+
end
|
20
|
+
end
|
16
21
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
22
|
+
describe 'hash' do
|
23
|
+
let(:channel_options) { options }
|
24
|
+
it { expect(channel_options).to be_a(Hash) }
|
25
|
+
|
26
|
+
include_examples 'creates a channel'
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'ChannelOptions object' do
|
30
|
+
let(:channel_options) { Ably::Models::ChannelOptions.new(options) }
|
31
|
+
it { expect(channel_options).to be_a(Ably::Models::ChannelOptions) }
|
32
|
+
|
33
|
+
include_examples 'creates a channel'
|
34
|
+
end
|
21
35
|
end
|
22
36
|
|
23
|
-
|
24
|
-
|
25
|
-
|
37
|
+
context 'when an existing channel exists' do
|
38
|
+
shared_examples 'reuse a channel object if it exists' do
|
39
|
+
it 'will reuse a channel object if it exists (RSN3a)' do
|
40
|
+
channel = subject.get(channel_name, channel_options)
|
41
|
+
expect(channel).to be_a(Ably::Rest::Channel)
|
42
|
+
expect(subject.get(channel_name, channel_options).object_id).to eql(channel.object_id)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'hash' do
|
47
|
+
let(:channel_options) { options }
|
48
|
+
it { expect(channel_options).to be_a(Hash) }
|
49
|
+
|
50
|
+
include_examples 'reuse a channel object if it exists'
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'ChannelOptions object' do
|
54
|
+
let(:channel_options) { Ably::Models::ChannelOptions.new(options) }
|
55
|
+
it { expect(channel_options).to be_a(Ably::Models::ChannelOptions) }
|
56
|
+
|
57
|
+
include_examples 'reuse a channel object if it exists'
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'with new channel_options modes' do
|
61
|
+
shared_examples 'update channel with provided options :modes' do
|
62
|
+
it 'will update channel with provided options modes (RSN3c)' do
|
63
|
+
channel = subject.get(channel_name, channel_options)
|
64
|
+
expect(channel.options.modes).to eq(modes)
|
65
|
+
|
66
|
+
subject.get(channel_name, channel_options)
|
67
|
+
expect(channel.options.modes).to eq(modes)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
let(:modes) { %i[subscribe] }
|
72
|
+
let(:new_options) { { modes: modes } }
|
73
|
+
|
74
|
+
describe 'hash' do
|
75
|
+
let(:channel_options) { new_options }
|
76
|
+
it { expect(channel_options).to be_a(Hash) }
|
77
|
+
|
78
|
+
include_examples 'update channel with provided options :modes'
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'ChannelOptions object' do
|
82
|
+
let(:channel_options) { Ably::Models::ChannelOptions.new(new_options) }
|
83
|
+
it { expect(channel_options).to be_a(Ably::Models::ChannelOptions) }
|
84
|
+
|
85
|
+
include_examples 'update channel with provided options :modes'
|
86
|
+
end
|
87
|
+
end
|
26
88
|
end
|
27
89
|
end
|
28
90
|
|
91
|
+
it '[] creates a channel' do
|
92
|
+
expect(Ably::Rest::Channel).to receive(:new).with(client, channel_name, options)
|
93
|
+
subject.get(channel_name, options)
|
94
|
+
end
|
95
|
+
|
29
96
|
context '#fetch' do
|
30
97
|
it 'retrieves a channel if it exists' do
|
31
98
|
channel = subject.get(channel_name, options)
|