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.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -4
  3. data/CHANGELOG.md +6 -2
  4. data/README.md +5 -1
  5. data/SPEC.md +1473 -852
  6. data/ably.gemspec +11 -8
  7. data/lib/ably/auth.rb +90 -53
  8. data/lib/ably/exceptions.rb +37 -8
  9. data/lib/ably/logger.rb +10 -1
  10. data/lib/ably/models/auth_details.rb +42 -0
  11. data/lib/ably/models/channel_state_change.rb +18 -4
  12. data/lib/ably/models/connection_details.rb +6 -3
  13. data/lib/ably/models/connection_state_change.rb +4 -3
  14. data/lib/ably/models/error_info.rb +1 -1
  15. data/lib/ably/models/message.rb +17 -1
  16. data/lib/ably/models/message_encoders/base.rb +103 -82
  17. data/lib/ably/models/message_encoders/base64.rb +1 -1
  18. data/lib/ably/models/presence_message.rb +16 -1
  19. data/lib/ably/models/protocol_message.rb +20 -3
  20. data/lib/ably/models/token_details.rb +11 -1
  21. data/lib/ably/models/token_request.rb +16 -6
  22. data/lib/ably/modules/async_wrapper.rb +7 -3
  23. data/lib/ably/modules/encodeable.rb +51 -12
  24. data/lib/ably/modules/enum.rb +17 -7
  25. data/lib/ably/modules/event_emitter.rb +29 -14
  26. data/lib/ably/modules/model_common.rb +13 -21
  27. data/lib/ably/modules/state_emitter.rb +7 -4
  28. data/lib/ably/modules/state_machine.rb +2 -4
  29. data/lib/ably/modules/uses_state_machine.rb +7 -3
  30. data/lib/ably/realtime.rb +2 -0
  31. data/lib/ably/realtime/auth.rb +102 -42
  32. data/lib/ably/realtime/channel.rb +68 -26
  33. data/lib/ably/realtime/channel/channel_manager.rb +154 -65
  34. data/lib/ably/realtime/channel/channel_state_machine.rb +14 -15
  35. data/lib/ably/realtime/client.rb +18 -3
  36. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +38 -29
  37. data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -1
  38. data/lib/ably/realtime/connection.rb +108 -49
  39. data/lib/ably/realtime/connection/connection_manager.rb +167 -61
  40. data/lib/ably/realtime/connection/connection_state_machine.rb +22 -3
  41. data/lib/ably/realtime/connection/websocket_transport.rb +19 -10
  42. data/lib/ably/realtime/presence.rb +70 -45
  43. data/lib/ably/realtime/presence/members_map.rb +201 -36
  44. data/lib/ably/realtime/presence/presence_manager.rb +30 -6
  45. data/lib/ably/realtime/presence/presence_state_machine.rb +5 -12
  46. data/lib/ably/rest.rb +2 -2
  47. data/lib/ably/rest/channel.rb +5 -5
  48. data/lib/ably/rest/client.rb +31 -27
  49. data/lib/ably/rest/middleware/exceptions.rb +1 -3
  50. data/lib/ably/rest/middleware/logger.rb +2 -2
  51. data/lib/ably/rest/presence.rb +2 -2
  52. data/lib/ably/util/pub_sub.rb +1 -1
  53. data/lib/ably/util/safe_deferrable.rb +26 -0
  54. data/lib/ably/version.rb +2 -2
  55. data/spec/acceptance/realtime/auth_spec.rb +470 -111
  56. data/spec/acceptance/realtime/channel_history_spec.rb +5 -3
  57. data/spec/acceptance/realtime/channel_spec.rb +1017 -168
  58. data/spec/acceptance/realtime/client_spec.rb +6 -6
  59. data/spec/acceptance/realtime/connection_failures_spec.rb +458 -27
  60. data/spec/acceptance/realtime/connection_spec.rb +424 -105
  61. data/spec/acceptance/realtime/message_spec.rb +52 -23
  62. data/spec/acceptance/realtime/presence_history_spec.rb +5 -3
  63. data/spec/acceptance/realtime/presence_spec.rb +1110 -96
  64. data/spec/acceptance/rest/auth_spec.rb +222 -59
  65. data/spec/acceptance/rest/base_spec.rb +1 -1
  66. data/spec/acceptance/rest/channel_spec.rb +1 -2
  67. data/spec/acceptance/rest/client_spec.rb +104 -48
  68. data/spec/acceptance/rest/message_spec.rb +42 -15
  69. data/spec/acceptance/rest/presence_spec.rb +4 -11
  70. data/spec/rspec_config.rb +2 -1
  71. data/spec/shared/client_initializer_behaviour.rb +2 -2
  72. data/spec/shared/safe_deferrable_behaviour.rb +6 -2
  73. data/spec/spec_helper.rb +4 -2
  74. data/spec/support/debug_failure_helper.rb +20 -4
  75. data/spec/support/event_machine_helper.rb +32 -1
  76. data/spec/unit/auth_spec.rb +4 -11
  77. data/spec/unit/logger_spec.rb +28 -2
  78. data/spec/unit/models/auth_details_spec.rb +49 -0
  79. data/spec/unit/models/channel_state_change_spec.rb +23 -3
  80. data/spec/unit/models/connection_details_spec.rb +12 -1
  81. data/spec/unit/models/connection_state_change_spec.rb +15 -4
  82. data/spec/unit/models/message_encoders/base64_spec.rb +2 -1
  83. data/spec/unit/models/message_spec.rb +153 -0
  84. data/spec/unit/models/presence_message_spec.rb +192 -0
  85. data/spec/unit/models/protocol_message_spec.rb +64 -6
  86. data/spec/unit/models/token_details_spec.rb +75 -0
  87. data/spec/unit/models/token_request_spec.rb +74 -0
  88. data/spec/unit/modules/async_wrapper_spec.rb +2 -1
  89. data/spec/unit/modules/enum_spec.rb +69 -0
  90. data/spec/unit/modules/event_emitter_spec.rb +149 -22
  91. data/spec/unit/modules/state_emitter_spec.rb +9 -3
  92. data/spec/unit/realtime/client_spec.rb +1 -1
  93. data/spec/unit/realtime/connection_spec.rb +8 -5
  94. data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +1 -1
  95. data/spec/unit/realtime/presence_spec.rb +4 -3
  96. data/spec/unit/rest/client_spec.rb +1 -1
  97. data/spec/unit/util/crypto_spec.rb +3 -3
  98. metadata +22 -19
@@ -137,7 +137,7 @@ describe Ably::Rest do
137
137
 
138
138
  context 'when auth#token_renewable?' do
139
139
  before do
140
- client.auth.authorise
140
+ client.auth.authorize
141
141
  end
142
142
 
143
143
  it 'should automatically reissue a token' do
@@ -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, token_params: { capability: capability }) }
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}").with(basic_auth: [key_name, key_secret]).to_return(&fallback_block)
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}").with(basic_auth: [key_name, key_secret]).to_return(&fallback_block)
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}").with(basic_auth: [key_name, key_secret]).to_return do
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}").with(basic_auth: [key_name, key_secret]).to_return do
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}").with(basic_auth: [key_name, key_secret]).to_return do
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}").with(basic_auth: [key_name, key_secret]).to_return(
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}").with(basic_auth: [key_name, key_secret]).to_return(&fallback_block)
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}").with(basic_auth: [key_name, key_secret]).to_return(&fallback_block)
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}").with(basic_auth: [key_name, key_secret]).to_return(&fallback_block)
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}").with(basic_auth: [key_name, key_secret]).to_return(&fallback_block)
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}").with(basic_auth: [key_name, key_secret]).to_return(&fallback_block)
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}").with(basic_auth: [key_name, key_secret]).to_return(&fallback_block)
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}").with(basic_auth: [key_name, key_secret]).to_return(&fallback_block)
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}").with(basic_auth: [key_name, key_secret]).to_return(&fallback_block)
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}").with(basic_auth: [key_name, key_secret]).to_return(&fallback_block)
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}").with(basic_auth: [key_name, key_secret]).to_return do
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 15s' do
766
- expect(client.http_defaults[:request_timeout]).to eql(15)
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 10s' do
774
- expect(client.http_defaults[:max_retry_duration]).to eql(10)
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.to_s.gsub('://', "://")}/channels/foo/publish").
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': 'test' })
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 |message|
257
- expect(message).to match(/Message cannot be decrypted/)
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 |message|
284
- expect(message).to match(/Cipher algorithm [\w-]+ does not match/)
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 |message|
311
- expect(message).to match(/CipherError decrypting data/)
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