ably 0.8.15 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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