ably 0.8.15 → 1.0.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/.travis.yml +6 -4
- data/CHANGELOG.md +6 -2
- data/README.md +5 -1
- data/SPEC.md +1473 -852
- data/ably.gemspec +11 -8
- data/lib/ably/auth.rb +90 -53
- data/lib/ably/exceptions.rb +37 -8
- data/lib/ably/logger.rb +10 -1
- data/lib/ably/models/auth_details.rb +42 -0
- data/lib/ably/models/channel_state_change.rb +18 -4
- data/lib/ably/models/connection_details.rb +6 -3
- data/lib/ably/models/connection_state_change.rb +4 -3
- data/lib/ably/models/error_info.rb +1 -1
- data/lib/ably/models/message.rb +17 -1
- data/lib/ably/models/message_encoders/base.rb +103 -82
- data/lib/ably/models/message_encoders/base64.rb +1 -1
- data/lib/ably/models/presence_message.rb +16 -1
- data/lib/ably/models/protocol_message.rb +20 -3
- data/lib/ably/models/token_details.rb +11 -1
- data/lib/ably/models/token_request.rb +16 -6
- data/lib/ably/modules/async_wrapper.rb +7 -3
- data/lib/ably/modules/encodeable.rb +51 -12
- data/lib/ably/modules/enum.rb +17 -7
- data/lib/ably/modules/event_emitter.rb +29 -14
- data/lib/ably/modules/model_common.rb +13 -21
- data/lib/ably/modules/state_emitter.rb +7 -4
- data/lib/ably/modules/state_machine.rb +2 -4
- data/lib/ably/modules/uses_state_machine.rb +7 -3
- data/lib/ably/realtime.rb +2 -0
- data/lib/ably/realtime/auth.rb +102 -42
- data/lib/ably/realtime/channel.rb +68 -26
- data/lib/ably/realtime/channel/channel_manager.rb +154 -65
- data/lib/ably/realtime/channel/channel_state_machine.rb +14 -15
- data/lib/ably/realtime/client.rb +18 -3
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +38 -29
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -1
- data/lib/ably/realtime/connection.rb +108 -49
- data/lib/ably/realtime/connection/connection_manager.rb +167 -61
- data/lib/ably/realtime/connection/connection_state_machine.rb +22 -3
- data/lib/ably/realtime/connection/websocket_transport.rb +19 -10
- data/lib/ably/realtime/presence.rb +70 -45
- data/lib/ably/realtime/presence/members_map.rb +201 -36
- data/lib/ably/realtime/presence/presence_manager.rb +30 -6
- data/lib/ably/realtime/presence/presence_state_machine.rb +5 -12
- data/lib/ably/rest.rb +2 -2
- data/lib/ably/rest/channel.rb +5 -5
- data/lib/ably/rest/client.rb +31 -27
- data/lib/ably/rest/middleware/exceptions.rb +1 -3
- data/lib/ably/rest/middleware/logger.rb +2 -2
- data/lib/ably/rest/presence.rb +2 -2
- data/lib/ably/util/pub_sub.rb +1 -1
- data/lib/ably/util/safe_deferrable.rb +26 -0
- data/lib/ably/version.rb +2 -2
- data/spec/acceptance/realtime/auth_spec.rb +470 -111
- data/spec/acceptance/realtime/channel_history_spec.rb +5 -3
- data/spec/acceptance/realtime/channel_spec.rb +1017 -168
- data/spec/acceptance/realtime/client_spec.rb +6 -6
- data/spec/acceptance/realtime/connection_failures_spec.rb +458 -27
- data/spec/acceptance/realtime/connection_spec.rb +424 -105
- data/spec/acceptance/realtime/message_spec.rb +52 -23
- data/spec/acceptance/realtime/presence_history_spec.rb +5 -3
- data/spec/acceptance/realtime/presence_spec.rb +1110 -96
- data/spec/acceptance/rest/auth_spec.rb +222 -59
- data/spec/acceptance/rest/base_spec.rb +1 -1
- data/spec/acceptance/rest/channel_spec.rb +1 -2
- data/spec/acceptance/rest/client_spec.rb +104 -48
- data/spec/acceptance/rest/message_spec.rb +42 -15
- data/spec/acceptance/rest/presence_spec.rb +4 -11
- data/spec/rspec_config.rb +2 -1
- data/spec/shared/client_initializer_behaviour.rb +2 -2
- data/spec/shared/safe_deferrable_behaviour.rb +6 -2
- data/spec/spec_helper.rb +4 -2
- data/spec/support/debug_failure_helper.rb +20 -4
- data/spec/support/event_machine_helper.rb +32 -1
- data/spec/unit/auth_spec.rb +4 -11
- data/spec/unit/logger_spec.rb +28 -2
- data/spec/unit/models/auth_details_spec.rb +49 -0
- data/spec/unit/models/channel_state_change_spec.rb +23 -3
- data/spec/unit/models/connection_details_spec.rb +12 -1
- data/spec/unit/models/connection_state_change_spec.rb +15 -4
- data/spec/unit/models/message_encoders/base64_spec.rb +2 -1
- data/spec/unit/models/message_spec.rb +153 -0
- data/spec/unit/models/presence_message_spec.rb +192 -0
- data/spec/unit/models/protocol_message_spec.rb +64 -6
- data/spec/unit/models/token_details_spec.rb +75 -0
- data/spec/unit/models/token_request_spec.rb +74 -0
- data/spec/unit/modules/async_wrapper_spec.rb +2 -1
- data/spec/unit/modules/enum_spec.rb +69 -0
- data/spec/unit/modules/event_emitter_spec.rb +149 -22
- data/spec/unit/modules/state_emitter_spec.rb +9 -3
- data/spec/unit/realtime/client_spec.rb +1 -1
- data/spec/unit/realtime/connection_spec.rb +8 -5
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +1 -1
- data/spec/unit/realtime/presence_spec.rb +4 -3
- data/spec/unit/rest/client_spec.rb +1 -1
- data/spec/unit/util/crypto_spec.rb +3 -3
- metadata +22 -19
@@ -84,7 +84,7 @@ describe Ably::Rest::Channel do
|
|
84
84
|
|
85
85
|
context 'without adequate permissions on the channel' do
|
86
86
|
let(:capability) { { onlyChannel: ['subscribe'] } }
|
87
|
-
let(:client_options) { default_options.merge(use_token_auth: true,
|
87
|
+
let(:client_options) { default_options.merge(use_token_auth: true, default_token_params: { capability: capability }) }
|
88
88
|
|
89
89
|
it 'raises a permission error when publishing' do
|
90
90
|
expect { channel.publish(name, data) }.to raise_error(Ably::Exceptions::UnauthorizedRequest, /not permitted/)
|
@@ -375,7 +375,6 @@ describe Ably::Rest::Channel do
|
|
375
375
|
query_params = default_history_options
|
376
376
|
.merge(option => milliseconds).map { |k, v| "#{k}=#{v}" }.join('&')
|
377
377
|
stub_request(:get, "#{endpoint}/channels/#{Addressable::URI.encode(channel_name)}/messages?#{query_params}").
|
378
|
-
with(basic_auth: [key_name, key_secret]).
|
379
378
|
to_return(:body => '{}', :headers => { 'Content-Type' => 'application/json' })
|
380
379
|
}
|
381
380
|
|
@@ -51,6 +51,14 @@ describe Ably::Rest::Client do
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
context 'with a non string :client_id' do
|
55
|
+
let(:client) { Ably::Rest::Client.new(client_options.merge(key: api_key, client_id: 1)) }
|
56
|
+
|
57
|
+
it 'raises an ArgumentError' do
|
58
|
+
expect { client.auth }.to raise_error ArgumentError, /client_id.*String/
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
54
62
|
context 'with an invalid wildcard "*" :client_id' do
|
55
63
|
it 'raises an exception' do
|
56
64
|
expect { Ably::Rest::Client.new(client_options.merge(key: api_key, client_id: '*')) }.to raise_error ArgumentError
|
@@ -70,6 +78,21 @@ describe Ably::Rest::Client do
|
|
70
78
|
end
|
71
79
|
end
|
72
80
|
|
81
|
+
context 'with :default_token_params' do
|
82
|
+
let(:client) do
|
83
|
+
Ably::Rest::Client.new(client_options.merge(
|
84
|
+
default_token_params: { client_id: 'bob' },
|
85
|
+
use_token_auth: true,
|
86
|
+
key: api_key
|
87
|
+
))
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'overides the default token params (#TO3j11)' do
|
91
|
+
client.auth.authorize
|
92
|
+
expect(client.auth.client_id).to eql('bob')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
73
96
|
context 'with an :auth_callback Proc (clientId provided in library options instead of as a token_request param)' do
|
74
97
|
let(:client) { Ably::Rest::Client.new(client_options.merge(client_id: client_id, auth_callback: Proc.new { token_request })) }
|
75
98
|
let(:token_request) { client.auth.create_token_request({}, key_name: key_name, key_secret: key_secret) }
|
@@ -112,7 +135,6 @@ describe Ably::Rest::Client do
|
|
112
135
|
|
113
136
|
let!(:get_message_history_stub) do
|
114
137
|
stub_request(:get, "https://#{environment}-#{Ably::Rest::Client::DOMAIN}/channels/#{channel_name}/messages?#{history_querystring}").
|
115
|
-
with(basic_auth: [key_name, key_secret]).
|
116
138
|
to_return(body: [], headers: { 'Content-Type' => 'application/json' })
|
117
139
|
end
|
118
140
|
|
@@ -273,7 +295,7 @@ describe Ably::Rest::Client do
|
|
273
295
|
context 'configured' do
|
274
296
|
let(:client_options) { default_options.merge(key: api_key, environment: 'production') }
|
275
297
|
|
276
|
-
it 'should make connection attempts to A.ably-realtime.com, B.ably-realtime.com, C.ably-realtime.com, D.ably-realtime.com, E.ably-realtime.com' do
|
298
|
+
it 'should make connection attempts to A.ably-realtime.com, B.ably-realtime.com, C.ably-realtime.com, D.ably-realtime.com, E.ably-realtime.com (#RSC15a)' do
|
277
299
|
hosts = []
|
278
300
|
5.times do
|
279
301
|
hosts << client.fallback_connection.host
|
@@ -282,12 +304,10 @@ describe Ably::Rest::Client do
|
|
282
304
|
end
|
283
305
|
end
|
284
306
|
|
285
|
-
context 'when environment is NOT production' do
|
307
|
+
context 'when environment is NOT production (#RSC15b)' do
|
286
308
|
let(:client_options) { default_options.merge(environment: 'sandbox', key: api_key) }
|
287
309
|
let!(:default_host_request_stub) do
|
288
|
-
stub_request(:post, "https://#{environment}-#{Ably::Rest::Client::DOMAIN}#{path}").
|
289
|
-
with(basic_auth: [key_name, key_secret]).
|
290
|
-
to_return do
|
310
|
+
stub_request(:post, "https://#{environment}-#{Ably::Rest::Client::DOMAIN}#{path}").to_return do
|
291
311
|
raise Faraday::TimeoutError.new('timeout error message')
|
292
312
|
end
|
293
313
|
end
|
@@ -307,7 +327,8 @@ describe Ably::Rest::Client do
|
|
307
327
|
environment: nil,
|
308
328
|
key: api_key,
|
309
329
|
http_max_retry_duration: max_retry_duration,
|
310
|
-
http_max_retry_count: max_retry_count
|
330
|
+
http_max_retry_count: max_retry_count,
|
331
|
+
log_level: :error
|
311
332
|
)
|
312
333
|
end
|
313
334
|
|
@@ -316,21 +337,21 @@ describe Ably::Rest::Client do
|
|
316
337
|
end
|
317
338
|
|
318
339
|
let!(:first_fallback_request_stub) do
|
319
|
-
stub_request(:post, "https://#{custom_hosts[0]}#{path}").
|
340
|
+
stub_request(:post, "https://#{custom_hosts[0]}#{path}").to_return(&fallback_block)
|
320
341
|
end
|
321
342
|
|
322
343
|
let!(:second_fallback_request_stub) do
|
323
|
-
stub_request(:post, "https://#{custom_hosts[1]}#{path}").
|
344
|
+
stub_request(:post, "https://#{custom_hosts[1]}#{path}").to_return(&fallback_block)
|
324
345
|
end
|
325
346
|
|
326
347
|
context 'and connection times out' do
|
327
348
|
let!(:default_host_request_stub) do
|
328
|
-
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").
|
349
|
+
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").to_return do
|
329
350
|
raise Faraday::TimeoutError.new('timeout error message')
|
330
351
|
end
|
331
352
|
end
|
332
353
|
|
333
|
-
it "tries fallback hosts #{http_defaults.fetch(:max_retry_count)} times" do
|
354
|
+
it "tries fallback hosts #{http_defaults.fetch(:max_retry_count)} times (#RSC15b, #RSC15b)" do
|
334
355
|
expect { publish_block.call }.to raise_error Ably::Exceptions::ConnectionError, /ssl error message/
|
335
356
|
expect(default_host_request_stub).to have_been_requested
|
336
357
|
expect(first_fallback_request_stub).to have_been_requested
|
@@ -339,7 +360,7 @@ describe Ably::Rest::Client do
|
|
339
360
|
|
340
361
|
context "and the total request time exeeds #{http_defaults.fetch(:max_retry_duration)} seconds" do
|
341
362
|
let!(:default_host_request_stub) do
|
342
|
-
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").
|
363
|
+
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").to_return do
|
343
364
|
sleep max_retry_duration * 1.5
|
344
365
|
raise Faraday::TimeoutError.new('timeout error message')
|
345
366
|
end
|
@@ -356,7 +377,7 @@ describe Ably::Rest::Client do
|
|
356
377
|
|
357
378
|
context 'and connection fails' do
|
358
379
|
let!(:default_host_request_stub) do
|
359
|
-
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").
|
380
|
+
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").to_return do
|
360
381
|
raise Faraday::ConnectionFailed.new('connection failure error message')
|
361
382
|
end
|
362
383
|
end
|
@@ -369,10 +390,47 @@ describe Ably::Rest::Client do
|
|
369
390
|
end
|
370
391
|
end
|
371
392
|
|
393
|
+
context 'and first request to primary endpoint fails' do
|
394
|
+
let(:client_options) do
|
395
|
+
default_options.merge(
|
396
|
+
environment: nil,
|
397
|
+
key: api_key,
|
398
|
+
http_max_retry_duration: max_retry_duration,
|
399
|
+
http_max_retry_count: max_retry_count,
|
400
|
+
log_level: :error
|
401
|
+
)
|
402
|
+
end
|
403
|
+
let(:requests) { [] }
|
404
|
+
let!(:default_host_request_stub) do
|
405
|
+
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").to_return do
|
406
|
+
requests << true
|
407
|
+
if requests.count == 1
|
408
|
+
raise Faraday::ConnectionFailed.new('connection failure error message')
|
409
|
+
else
|
410
|
+
{
|
411
|
+
headers: { 'Content-Type' => 'application/json' },
|
412
|
+
status: 200,
|
413
|
+
body: {}.to_json
|
414
|
+
}
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
it "tries a fallback host, and for the next request tries the primary endpoint again (#RSC15e)" do
|
420
|
+
expect { publish_block.call }.to raise_error Ably::Exceptions::ConnectionError, /ssl error message/
|
421
|
+
expect(default_host_request_stub).to have_been_requested
|
422
|
+
expect(first_fallback_request_stub).to have_been_requested
|
423
|
+
expect(requests.count).to eql(1)
|
424
|
+
|
425
|
+
publish_block.call
|
426
|
+
expect(requests.count).to eql(2)
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
372
430
|
context 'and basic authentication fails' do
|
373
431
|
let(:status) { 401 }
|
374
432
|
let!(:default_host_request_stub) do
|
375
|
-
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").
|
433
|
+
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").to_return(
|
376
434
|
headers: { 'Content-Type' => 'application/json' },
|
377
435
|
status: status,
|
378
436
|
body: {
|
@@ -404,10 +462,10 @@ describe Ably::Rest::Client do
|
|
404
462
|
end
|
405
463
|
end
|
406
464
|
let!(:default_host_request_stub) do
|
407
|
-
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").
|
465
|
+
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").to_return(&fallback_block)
|
408
466
|
end
|
409
467
|
|
410
|
-
it 'attempts the fallback hosts as this is an authentication failure' do
|
468
|
+
it 'attempts the fallback hosts as this is an authentication failure (#RSC15d)' do
|
411
469
|
expect { publish_block.call }.to raise_error(Ably::Exceptions::ServerError)
|
412
470
|
expect(default_host_request_stub).to have_been_requested
|
413
471
|
expect(first_fallback_request_stub).to have_been_requested
|
@@ -440,23 +498,23 @@ describe Ably::Rest::Client do
|
|
440
498
|
end
|
441
499
|
end
|
442
500
|
let!(:default_host_request_stub) do
|
443
|
-
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").
|
501
|
+
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").to_return(&fallback_block)
|
444
502
|
end
|
445
503
|
|
446
504
|
context 'with custom fallback hosts provided' do
|
447
505
|
let!(:first_fallback_request_stub) do
|
448
|
-
stub_request(:post, "https://#{custom_hosts[0]}#{path}").
|
506
|
+
stub_request(:post, "https://#{custom_hosts[0]}#{path}").to_return(&fallback_block)
|
449
507
|
end
|
450
508
|
|
451
509
|
let!(:second_fallback_request_stub) do
|
452
|
-
stub_request(:post, "https://#{custom_hosts[1]}#{path}").
|
510
|
+
stub_request(:post, "https://#{custom_hosts[1]}#{path}").to_return(&fallback_block)
|
453
511
|
end
|
454
512
|
|
455
513
|
let(:client_options) {
|
456
514
|
production_options.merge(fallback_hosts: custom_hosts, log_level: :error)
|
457
515
|
}
|
458
516
|
|
459
|
-
it 'attempts the fallback hosts as this is an authentication failure (#RSC15b, #TO3k6)' do
|
517
|
+
it 'attempts the fallback hosts as this is an authentication failure (#RSC15b, #RSC15a, #TO3k6)' do
|
460
518
|
expect { publish_block.call }.to raise_error(Ably::Exceptions::ServerError)
|
461
519
|
expect(default_host_request_stub).to have_been_requested
|
462
520
|
expect(first_fallback_request_stub).to have_been_requested
|
@@ -464,7 +522,7 @@ describe Ably::Rest::Client do
|
|
464
522
|
end
|
465
523
|
end
|
466
524
|
|
467
|
-
context 'with an empty array of fallback hosts provided (#RSC15b, #TO3k6)' do
|
525
|
+
context 'with an empty array of fallback hosts provided (#RSC15b, #RSC15a, #TO3k6)' do
|
468
526
|
let(:client_options) {
|
469
527
|
production_options.merge(fallback_hosts: [])
|
470
528
|
}
|
@@ -488,7 +546,7 @@ describe Ably::Rest::Client do
|
|
488
546
|
|
489
547
|
context 'and timing out the primary host' do
|
490
548
|
before do
|
491
|
-
@web_server = WEBrick::HTTPServer.new(:Port => port, :SSLEnable => false)
|
549
|
+
@web_server = WEBrick::HTTPServer.new(:Port => port, :SSLEnable => false, :AccessLog => [], Logger: WEBrick::Log.new("/dev/null"))
|
492
550
|
@web_server.mount_proc "/channels/#{channel_name}/publish" do |req, res|
|
493
551
|
if req.header["host"].first.include?(primary_host)
|
494
552
|
@primary_host_requested = true
|
@@ -525,7 +583,7 @@ describe Ably::Rest::Client do
|
|
525
583
|
end
|
526
584
|
let(:fail_fallback_request_count) { 1 }
|
527
585
|
|
528
|
-
it 'tries one of the fallback hosts' do
|
586
|
+
it 'tries one of the fallback hosts (#RSC15d)' do
|
529
587
|
client.channel(channel_name).publish('event', 'data')
|
530
588
|
expect(@primary_host_requested).to be_truthy
|
531
589
|
expect(@fallback_request_count).to eql(2)
|
@@ -541,12 +599,13 @@ describe Ably::Rest::Client do
|
|
541
599
|
port: port,
|
542
600
|
tls: false,
|
543
601
|
http_request_timeout: request_timeout,
|
544
|
-
max_retry_duration: request_timeout / 2
|
602
|
+
max_retry_duration: request_timeout / 2,
|
603
|
+
log_level: :error
|
545
604
|
)
|
546
605
|
end
|
547
606
|
let(:fail_fallback_request_count) { 0 }
|
548
607
|
|
549
|
-
it 'tries one of the fallback hosts' do
|
608
|
+
it 'tries one of the fallback hosts (#RSC15d)' do
|
550
609
|
client.channel(channel_name).publish('event', 'data')
|
551
610
|
expect(@primary_host_requested).to be_truthy
|
552
611
|
expect(@fallback_request_count).to eql(1)
|
@@ -556,7 +615,7 @@ describe Ably::Rest::Client do
|
|
556
615
|
|
557
616
|
context 'and failing the primary host' do
|
558
617
|
before do
|
559
|
-
@web_server = WEBrick::HTTPServer.new(:Port => port, :SSLEnable => false)
|
618
|
+
@web_server = WEBrick::HTTPServer.new(:Port => port, :SSLEnable => false, :AccessLog => [], Logger: WEBrick::Log.new("/dev/null"))
|
560
619
|
@web_server.mount_proc "/channels/#{channel_name}/publish" do |req, res|
|
561
620
|
if req.header["host"].first.include?(primary_host)
|
562
621
|
@primary_host_requested = true
|
@@ -584,7 +643,8 @@ describe Ably::Rest::Client do
|
|
584
643
|
fallback_hosts: fallbacks,
|
585
644
|
token: 'fake.token',
|
586
645
|
port: port,
|
587
|
-
tls: false
|
646
|
+
tls: false,
|
647
|
+
log_level: :error
|
588
648
|
)
|
589
649
|
end
|
590
650
|
let(:fail_fallback_request_count) { 1 }
|
@@ -623,23 +683,23 @@ describe Ably::Rest::Client do
|
|
623
683
|
end
|
624
684
|
end
|
625
685
|
let!(:default_host_request_stub) do
|
626
|
-
stub_request(:post, "https://#{env}-#{Ably::Rest::Client::DOMAIN}#{path}").
|
686
|
+
stub_request(:post, "https://#{env}-#{Ably::Rest::Client::DOMAIN}#{path}").to_return(&fallback_block)
|
627
687
|
end
|
628
688
|
|
629
689
|
context 'with custom fallback hosts provided (#RSC15b, #TO3k6)' do
|
630
690
|
let!(:first_fallback_request_stub) do
|
631
|
-
stub_request(:post, "https://#{custom_hosts[0]}#{path}").
|
691
|
+
stub_request(:post, "https://#{custom_hosts[0]}#{path}").to_return(&fallback_block)
|
632
692
|
end
|
633
693
|
|
634
694
|
let!(:second_fallback_request_stub) do
|
635
|
-
stub_request(:post, "https://#{custom_hosts[1]}#{path}").
|
695
|
+
stub_request(:post, "https://#{custom_hosts[1]}#{path}").to_return(&fallback_block)
|
636
696
|
end
|
637
697
|
|
638
698
|
let(:client_options) {
|
639
|
-
production_options.merge(fallback_hosts: custom_hosts)
|
699
|
+
production_options.merge(fallback_hosts: custom_hosts, log_level: :error)
|
640
700
|
}
|
641
701
|
|
642
|
-
it 'attempts the fallback hosts as this is an authentication failure' do
|
702
|
+
it 'attempts the fallback hosts as this is not an authentication failure' do
|
643
703
|
expect { publish_block.call }.to raise_error(Ably::Exceptions::ServerError)
|
644
704
|
expect(default_host_request_stub).to have_been_requested
|
645
705
|
expect(first_fallback_request_stub).to have_been_requested
|
@@ -665,20 +725,16 @@ describe Ably::Rest::Client do
|
|
665
725
|
stub_const 'Ably::FALLBACK_HOSTS', custom_hosts
|
666
726
|
end
|
667
727
|
|
668
|
-
let(:client_options) {
|
669
|
-
production_options.merge(fallback_hosts_use_default: true)
|
670
|
-
}
|
671
|
-
|
672
728
|
let!(:first_fallback_request_stub) do
|
673
|
-
stub_request(:post, "https://#{Ably::FALLBACK_HOSTS[0]}#{path}").
|
729
|
+
stub_request(:post, "https://#{Ably::FALLBACK_HOSTS[0]}#{path}").to_return(&fallback_block)
|
674
730
|
end
|
675
731
|
|
676
732
|
let!(:second_fallback_request_stub) do
|
677
|
-
stub_request(:post, "https://#{Ably::FALLBACK_HOSTS[1]}#{path}").
|
733
|
+
stub_request(:post, "https://#{Ably::FALLBACK_HOSTS[1]}#{path}").to_return(&fallback_block)
|
678
734
|
end
|
679
735
|
|
680
736
|
let(:client_options) {
|
681
|
-
production_options.merge(fallback_hosts: custom_hosts)
|
737
|
+
production_options.merge(fallback_hosts: custom_hosts, log_level: :error)
|
682
738
|
}
|
683
739
|
|
684
740
|
it 'attempts the default fallback hosts as this is an authentication failure' do
|
@@ -705,7 +761,7 @@ describe Ably::Rest::Client do
|
|
705
761
|
let(:path) { '/channels/test/publish' }
|
706
762
|
|
707
763
|
let!(:custom_host_request_stub) do
|
708
|
-
stub_request(:post, "https://#{custom_host}#{path}").
|
764
|
+
stub_request(:post, "https://#{custom_host}#{path}").to_return do
|
709
765
|
raise Faraday::ConnectionFailed.new('connection failure error message')
|
710
766
|
end
|
711
767
|
end
|
@@ -762,16 +818,16 @@ describe Ably::Rest::Client do
|
|
762
818
|
expect(client.http_defaults[:open_timeout]).to eql(4)
|
763
819
|
end
|
764
820
|
|
765
|
-
specify '#http_request_timeout is
|
766
|
-
expect(client.http_defaults[:request_timeout]).to eql(
|
821
|
+
specify '#http_request_timeout is 10s' do
|
822
|
+
expect(client.http_defaults[:request_timeout]).to eql(10)
|
767
823
|
end
|
768
824
|
|
769
825
|
specify '#http_max_retry_count is 3' do
|
770
826
|
expect(client.http_defaults[:max_retry_count]).to eql(3)
|
771
827
|
end
|
772
828
|
|
773
|
-
specify '#http_max_retry_duration is
|
774
|
-
expect(client.http_defaults[:max_retry_duration]).to eql(
|
829
|
+
specify '#http_max_retry_duration is 15s' do
|
830
|
+
expect(client.http_defaults[:max_retry_duration]).to eql(15)
|
775
831
|
end
|
776
832
|
end
|
777
833
|
|
@@ -844,18 +900,18 @@ describe Ably::Rest::Client do
|
|
844
900
|
lib << Ably::VERSION
|
845
901
|
|
846
902
|
|
847
|
-
stub_request(:post, "#{client.endpoint
|
903
|
+
stub_request(:post, "#{client.endpoint}/channels/foo/publish").
|
848
904
|
with(headers: {
|
849
905
|
'X-Ably-Version' => Ably::PROTOCOL_VERSION,
|
850
906
|
'X-Ably-Lib' => lib.join('-')
|
851
907
|
}).
|
852
|
-
with(basic_auth: [key_name, key_secret]).
|
853
908
|
to_return(status: 201, body: '{}', headers: { 'Content-Type' => 'application/json' })
|
854
909
|
end
|
855
910
|
|
856
|
-
it 'sends a protocol version and lib version header' do
|
911
|
+
it 'sends a protocol version and lib version header (#G4, #RSC7a, #RSC7b)' do
|
857
912
|
client.channels.get('foo').publish("event")
|
858
913
|
expect(publish_message_stub).to have_been_requested
|
914
|
+
expect(Ably::PROTOCOL_VERSION).to eql('1.0')
|
859
915
|
end
|
860
916
|
end
|
861
917
|
end
|
@@ -886,7 +942,7 @@ describe Ably::Rest::Client do
|
|
886
942
|
|
887
943
|
it 'provides paging' do
|
888
944
|
10.times do
|
889
|
-
client.request(:post, "/channels/#{channel_name}/publish", {}, { 'name'
|
945
|
+
client.request(:post, "/channels/#{channel_name}/publish", {}, { 'name' => 'test' })
|
890
946
|
end
|
891
947
|
response = client.request(:get, "/channels/#{channel_name}/messages", { limit: 2 })
|
892
948
|
expect(response.items.length).to eql(2)
|
@@ -61,6 +61,33 @@ describe Ably::Rest::Channel, 'messages' do
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
+
context 'with supported extra payload content type (#RSL1h, #RSL6a2)' do
|
65
|
+
context 'JSON Object (Hash)' do
|
66
|
+
let(:data) { { 'push' => { 'title' => 'Testing' } } }
|
67
|
+
|
68
|
+
it 'is encoded and decoded to the same hash' do
|
69
|
+
channel.publish 'event', {}, extras: data
|
70
|
+
expect(channel.history.items.first.extras).to eql(data)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'JSON Array' do
|
75
|
+
let(:data) { { 'push' => [ nil, true, false, 55, 'string', { 'Hash' => true }, ['array'] ] } }
|
76
|
+
|
77
|
+
it 'is encoded and decoded to the same Array' do
|
78
|
+
channel.publish 'event', {}, extras: data
|
79
|
+
expect(channel.history.items.first.extras).to eql(data)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'nil' do
|
84
|
+
it 'is encoded and decoded to the same Array' do
|
85
|
+
channel.publish 'event', {}, extras: nil
|
86
|
+
expect(channel.history.items.first.extras).to be_nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
64
91
|
context 'with unsupported data payload content type' do
|
65
92
|
context 'Integer' do
|
66
93
|
let(:data) { 1 }
|
@@ -134,7 +161,7 @@ describe Ably::Rest::Channel, 'messages' do
|
|
134
161
|
end
|
135
162
|
end
|
136
163
|
|
137
|
-
it 'encrypts message automatically when published' do
|
164
|
+
it 'encrypts message automatically when published (#RTL7d)' do
|
138
165
|
expect(client).to receive(:post) do |path, message|
|
139
166
|
if protocol == :json
|
140
167
|
expect(message['encoding']).to eql(encrypted_encoding)
|
@@ -149,7 +176,7 @@ describe Ably::Rest::Channel, 'messages' do
|
|
149
176
|
encrypted_channel.publish 'example', encoded_data_decoded
|
150
177
|
end
|
151
178
|
|
152
|
-
it 'sends and retrieves messages that are encrypted & decrypted by the Ably library' do
|
179
|
+
it 'sends and retrieves messages that are encrypted & decrypted by the Ably library (#RTL7d)' do
|
153
180
|
encrypted_channel.publish 'example', encoded_data_decoded
|
154
181
|
|
155
182
|
message = encrypted_channel.history.items.first
|
@@ -168,12 +195,12 @@ describe Ably::Rest::Channel, 'messages' do
|
|
168
195
|
end
|
169
196
|
end
|
170
197
|
|
171
|
-
context 'with AES-128-CBC using crypto-data-128.json fixtures' do
|
198
|
+
context 'with AES-128-CBC using crypto-data-128.json fixtures (#RTL7d)' do
|
172
199
|
data = JSON.parse(File.read(File.join(resources_root, 'crypto-data-128.json')))
|
173
200
|
add_tests_for_data data
|
174
201
|
end
|
175
202
|
|
176
|
-
context 'with AES-256-CBC using crypto-data-256.json fixtures' do
|
203
|
+
context 'with AES-256-CBC using crypto-data-256.json fixtures (#RTL7d)' do
|
177
204
|
data = JSON.parse(File.read(File.join(resources_root, 'crypto-data-256.json')))
|
178
205
|
add_tests_for_data data
|
179
206
|
end
|
@@ -246,21 +273,21 @@ describe Ably::Rest::Channel, 'messages' do
|
|
246
273
|
encrypted_channel.publish 'example', payload
|
247
274
|
end
|
248
275
|
|
249
|
-
it 'retrieves the message that remains encrypted with an encrypted encoding attribute' do
|
276
|
+
it 'retrieves the message that remains encrypted with an encrypted encoding attribute (#RTL7e)' do
|
250
277
|
message = other_client_unencrypted_channel.history.items.first
|
251
278
|
expect(message.data).to_not eql(payload)
|
252
279
|
expect(message.encoding).to match(/^cipher\+aes-256-cbc/)
|
253
280
|
end
|
254
281
|
|
255
|
-
it 'logs a Cipher exception' do
|
256
|
-
expect(other_client.logger).to receive(:error) do |
|
257
|
-
expect(
|
282
|
+
it 'logs a Cipher exception (#RTL7e)' do
|
283
|
+
expect(other_client.logger).to receive(:error) do |*args, &block|
|
284
|
+
expect(args.concat([block ? block.call : nil]).join(',')).to match(/Message cannot be decrypted/)
|
258
285
|
end
|
259
286
|
other_client_unencrypted_channel.history
|
260
287
|
end
|
261
288
|
end
|
262
289
|
|
263
|
-
context 'publishing on an encrypted channel and retrieving #history with a different algorithm on another client' do
|
290
|
+
context 'publishing on an encrypted channel and retrieving #history with a different algorithm on another client (#RTL7e)' do
|
264
291
|
let(:client_options) { default_client_options.merge(log_level: :fatal) }
|
265
292
|
let(:cipher_options_client1) { { key: Ably::Util::Crypto.generate_random_key(256), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
|
266
293
|
let(:encrypted_channel_client1) { client.channel(channel_name, cipher: cipher_options_client1) }
|
@@ -273,15 +300,15 @@ describe Ably::Rest::Channel, 'messages' do
|
|
273
300
|
encrypted_channel_client1.publish 'example', payload
|
274
301
|
end
|
275
302
|
|
276
|
-
it 'retrieves the message that remains encrypted with an encrypted encoding attribute' do
|
303
|
+
it 'retrieves the message that remains encrypted with an encrypted encoding attribute (#RTL7e)' do
|
277
304
|
message = encrypted_channel_client2.history.items.first
|
278
305
|
expect(message.data).to_not eql(payload)
|
279
306
|
expect(message.encoding).to match(/^cipher\+aes-256-cbc/)
|
280
307
|
end
|
281
308
|
|
282
|
-
it 'logs a Cipher exception' do
|
283
|
-
expect(other_client.logger).to receive(:error) do |
|
284
|
-
expect(
|
309
|
+
it 'logs a Cipher exception (#RTL7e)' do
|
310
|
+
expect(other_client.logger).to receive(:error) do |*args, &block|
|
311
|
+
expect(args.concat([block ? block.call : nil]).join(',')).to match(/Cipher algorithm [\w-]+ does not match/)
|
285
312
|
end
|
286
313
|
encrypted_channel_client2.history
|
287
314
|
end
|
@@ -307,8 +334,8 @@ describe Ably::Rest::Channel, 'messages' do
|
|
307
334
|
end
|
308
335
|
|
309
336
|
it 'logs a Cipher exception' do
|
310
|
-
expect(other_client.logger).to receive(:error) do |
|
311
|
-
expect(
|
337
|
+
expect(other_client.logger).to receive(:error) do |*args, &block|
|
338
|
+
expect(args.concat([block ? block.call : nil]).join(',')).to match(/CipherError decrypting data/)
|
312
339
|
end
|
313
340
|
encrypted_channel_client2.history
|
314
341
|
end
|