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
@@ -182,7 +182,7 @@ describe Ably::Auth do
182
182
  context 'with :query_time option' do
183
183
  let(:options) { { query_time: true } }
184
184
 
185
- it 'queries the server for the time' do
185
+ it 'queries the server for the time (#RSA10k)' do
186
186
  expect(client).to receive(:time).and_call_original
187
187
  auth.request_token({}, options)
188
188
  end
@@ -404,7 +404,7 @@ describe Ably::Auth do
404
404
  end
405
405
 
406
406
  it 'raises ServerError' do
407
- expect { auth.request_token({}, auth_options) }.to raise_error(Ably::Exceptions::ServerError)
407
+ expect { auth.request_token({}, auth_options) }.to raise_error(Ably::Exceptions::AuthenticationFailed)
408
408
  end
409
409
  end
410
410
 
@@ -415,7 +415,7 @@ describe Ably::Auth do
415
415
  end
416
416
 
417
417
  it 'raises InvalidResponseBody' do
418
- expect { auth.request_token({}, auth_options) }.to raise_error(Ably::Exceptions::InvalidResponseBody)
418
+ expect { auth.request_token({}, auth_options) }.to raise_error(Ably::Exceptions::AuthenticationFailed, /Content Type.*not supported/)
419
419
  end
420
420
  end
421
421
  end
@@ -445,8 +445,8 @@ describe Ably::Auth do
445
445
  expect(request_token.client_id).to eql(client_id)
446
446
  end
447
447
 
448
- context 'when authorised' do
449
- before { auth.authorise(token_params, auth_callback: auth_callback) }
448
+ context 'when authorized' do
449
+ before { auth.authorize(token_params, auth_callback: auth_callback) }
450
450
 
451
451
  it "sets Auth#client_id to the new token's client_id" do
452
452
  expect(auth.client_id).to eql(client_id)
@@ -500,8 +500,8 @@ describe Ably::Auth do
500
500
  expect(token_details.capability).to eql(capability)
501
501
  end
502
502
 
503
- context 'when authorised' do
504
- before { auth.authorise(token_params, auth_callback: auth_callback) }
503
+ context 'when authorized' do
504
+ before { auth.authorize(token_params, auth_callback: auth_callback) }
505
505
 
506
506
  it "sets Auth#client_id to the new token's client_id" do
507
507
  expect(auth.client_id).to eql(client_id)
@@ -583,13 +583,13 @@ describe Ably::Auth do
583
583
  end
584
584
  end
585
585
 
586
- context 'before #authorise has been called' do
586
+ context 'before #authorize has been called' do
587
587
  it 'has no current_token_details' do
588
588
  expect(auth.current_token_details).to be_nil
589
589
  end
590
590
  end
591
591
 
592
- describe '#authorise' do
592
+ describe '#authorize (#RSA10, #RSA10j)' do
593
593
  context 'when called for the first time since the client has been instantiated' do
594
594
  let(:auth_options) do
595
595
  { auth_url: 'http://somewhere.com/' }
@@ -600,19 +600,19 @@ describe Ably::Auth do
600
600
 
601
601
  it 'passes all auth_options and token_params to #request_token' do
602
602
  expect(auth).to receive(:request_token).with(token_params, auth_options)
603
- auth.authorise token_params, auth_options
603
+ auth.authorize token_params, auth_options
604
604
  end
605
605
 
606
606
  it 'returns a valid token' do
607
- expect(auth.authorise).to be_a(Ably::Models::TokenDetails)
607
+ expect(auth.authorize).to be_a(Ably::Models::TokenDetails)
608
608
  end
609
609
 
610
- it 'issues a new token if option :force => true' do
611
- expect { auth.authorise(force: true) }.to change { auth.current_token_details }
610
+ it 'issues a new token every time (#RSA10a)' do
611
+ expect { auth.authorize }.to change { auth.current_token_details }
612
612
  end
613
613
  end
614
614
 
615
- context 'query_time: true' do
615
+ context 'query_time: true with authorize' do
616
616
  let(:local_time) { @now - 60 }
617
617
  let(:server_time) { @now }
618
618
 
@@ -621,11 +621,32 @@ describe Ably::Auth do
621
621
  allow(Time).to receive(:now).and_return(local_time)
622
622
  end
623
623
 
624
- it 'only queries the server time once and then works out the offset, query_time option is never persisted' do
624
+ it 'only queries the server time once and then works out the offset, query_time option is never persisted (#RSA10k)' do
625
625
  expect(client).to receive(:time).once.and_return(server_time)
626
626
 
627
- auth.authorise({}, query_time: true)
628
- auth.authorise({}, force: true)
627
+ auth.authorize({}, query_time: true)
628
+ auth.authorize({})
629
+ expect(auth.auth_options).to_not have_key(:query_time)
630
+ end
631
+ end
632
+
633
+ context 'query_time: true ClientOption when instanced' do
634
+ let(:local_time) { @now - 60 }
635
+ let(:server_time) { @now }
636
+
637
+ let(:client_options) { default_options.merge(key: api_key, query_time: true) }
638
+
639
+ before do
640
+ @now = Time.now
641
+ allow(Time).to receive(:now).and_return(local_time)
642
+ end
643
+
644
+ it 'only queries the server time once and then works out the offset, query_time option is never persisted (#RSA10k)' do
645
+ expect(client).to receive(:time).once.and_return(server_time)
646
+
647
+ auth.authorize({})
648
+ auth.authorize({})
649
+ auth.authorize({})
629
650
  expect(auth.auth_options).to_not have_key(:query_time)
630
651
  end
631
652
  end
@@ -634,28 +655,36 @@ describe Ably::Auth do
634
655
  let(:default_token_params) { { ttl: 23 } }
635
656
 
636
657
  before do
637
- auth.authorise default_token_params
658
+ auth.authorize default_token_params
638
659
  end
639
660
 
640
661
  it 'has no effect on the defaults when null and TokenParam defaults remain the same' do
641
662
  old_token = auth.current_token_details
642
- auth.authorise(nil, force: true)
663
+ auth.authorize
643
664
  expect(old_token).to_not eql(auth.current_token_details)
644
665
  expect(auth.token_params[:ttl]).to eql(23)
645
666
  end
646
667
 
647
- it 'updates defaults when present and all previous configured TokenParams are discarded' do
668
+ it 'updates defaults when present and all previous configured TokenParams are discarded (#RSA10g)' do
648
669
  old_token = auth.current_token_details
649
- auth.authorise({ client_id: 'bob' }, { force: true })
670
+ auth.authorize({ client_id: 'bob' })
650
671
  expect(old_token).to_not eql(auth.current_token_details)
651
- expect(auth.token_params[:ttl]).to_not eql(23)
672
+ expect(auth.token_params[:ttl]).to_not eq(23)
652
673
  expect(auth.token_params[:client_id]).to eql('bob')
653
674
  end
654
675
 
655
676
  it 'updates Auth#token_params attribute with an immutable hash' do
656
- auth.authorise({ client_id: 'bob' }, { force: true })
677
+ auth.authorize({ client_id: 'bob' })
657
678
  expect { auth.token_params['key_name'] = 'new_name' }.to raise_error RuntimeError, /can't modify frozen.*Hash/
658
679
  end
680
+
681
+ it 'uses TokenParams#timestamp for this request but obtains a new timestamp for subsequence requests (#RSA10g)' do
682
+ timestamp = Time.now.to_i
683
+ expect(auth).to receive(:create_token_request).with({ timestamp: Time.now.to_i }, {}).once.and_call_original
684
+ expect(auth).to receive(:create_token_request).with({}, {}).once.and_call_original
685
+ auth.authorize(timestamp: Time.now.to_i)
686
+ auth.authorize
687
+ end
659
688
  end
660
689
 
661
690
  context 'AuthOptions argument' do
@@ -669,68 +698,75 @@ describe Ably::Auth do
669
698
  stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', 0 # allow token to be used even if about to expire
670
699
  stub_const 'Ably::Auth::TOKEN_DEFAULTS', Ably::Auth::TOKEN_DEFAULTS.merge(renew_token_buffer: 0) # Ensure tokens issued expire immediately after issue
671
700
 
672
- auth.authorise(nil, default_auth_options)
701
+ auth.authorize(nil, default_auth_options)
673
702
  @old_token = auth.current_token_details
674
703
  sleep token_ttl + 0.5
675
704
  end
676
705
 
677
706
  it 'has no effect on the defaults when null and AuthOptions defaults remain the same' do
678
- auth.authorise(nil, nil)
707
+ auth.authorize(nil, nil)
679
708
  expect(@old_token).to_not eql(auth.current_token_details)
680
709
  expect(auth.options[:auth_callback]).to eql(auth_callback)
681
710
  end
682
711
 
683
- it 'updates defaults when present and all previous configured AuthOptions are discarded' do
684
- auth.authorise(nil, auth_method: :post)
712
+ it 'updates defaults when present and all previous configured AuthOptions are discarded (#RSA10g)' do
713
+ auth.authorize(nil, auth_method: :post)
685
714
  expect(@old_token).to_not eql(auth.current_token_details)
686
715
  expect(auth.options[:auth_callback]).to be_nil
687
716
  expect(auth.options[:auth_method]).to eql(:post)
688
717
  end
689
718
 
690
719
  it 'updates Auth#options attribute with an immutable hash' do
691
- auth.authorise(nil, auth_callback: Proc.new { '1231232.12321:12321312' })
720
+ auth.authorize(nil, auth_callback: Proc.new { '1231232.12321:12321312' })
692
721
  expect { auth.options['key_name'] = 'new_name' }.to raise_error RuntimeError, /can't modify frozen.*Hash/
693
722
  end
723
+
724
+ it 'uses AuthOptions#query_time for this request and will not query_time for subsequent requests (#RSA10g)' do
725
+ expect(client).to receive(:time).once.and_call_original
726
+ auth.authorize({}, query_time: true)
727
+ auth.authorize
728
+ end
729
+
730
+ it 'uses AuthOptions#query_time for this request and will query_time again if provided subsequently' do
731
+ expect(client).to receive(:time).twice.and_call_original
732
+ auth.authorize({}, query_time: true)
733
+ auth.authorize({}, query_time: true)
734
+ end
694
735
  end
695
736
 
696
737
  context 'with previous authorisation' do
697
738
  before do
698
- auth.authorise
739
+ auth.authorize
699
740
  expect(auth.current_token_details).to_not be_expired
700
741
  end
701
742
 
702
- it 'does not request a token if current_token_details has not expired' do
703
- expect(auth).to_not receive(:request_token)
704
- auth.authorise
705
- end
706
-
707
743
  it 'requests a new token if token is expired' do
708
744
  allow(auth.current_token_details).to receive(:expired?).and_return(true)
709
745
  expect(auth).to receive(:request_token)
710
- expect { auth.authorise }.to change { auth.current_token_details }
746
+ expect { auth.authorize }.to change { auth.current_token_details }
711
747
  end
712
748
 
713
- it 'issues a new token if option :force => true' do
714
- expect { auth.authorise({}, force: true) }.to change { auth.current_token_details }
749
+ it 'issues a new token every time #authorize is called' do
750
+ expect { auth.authorize({}) }.to change { auth.current_token_details }
715
751
  end
716
752
  end
717
753
 
718
- it 'updates the persisted token params that are then used for subsequent authorise requests' do
754
+ it 'updates the persisted token params that are then used for subsequent authorize requests' do
719
755
  expect(auth.token_params[:ttl]).to_not eql(26)
720
- auth.authorise(ttl: 26)
756
+ auth.authorize(ttl: 26)
721
757
  expect(auth.token_params[:ttl]).to eql(26)
722
758
  end
723
759
 
724
- it 'updates the persisted auth options that are then used for subsequent authorise requests' do
760
+ it 'updates the persisted auth options that are then used for subsequent authorize requests' do
725
761
  expect(auth.options[:authUrl]).to be_nil
726
- auth.authorise({}, authUrl: 'http://foo.com')
762
+ auth.authorize({}, authUrl: 'http://foo.com')
727
763
  expect(auth.options[:authUrl]).to eql('http://foo.com')
728
764
  end
729
765
 
730
766
  context 'with a Proc for the :auth_callback option' do
731
767
  let(:client_id) { random_str }
732
768
  let!(:token) do
733
- auth.authorise({}, auth_callback: Proc.new do
769
+ auth.authorize({}, auth_callback: Proc.new do
734
770
  @block_called ||= 0
735
771
  @block_called += 1
736
772
  auth.create_token_request(client_id: client_id)
@@ -773,7 +809,7 @@ describe Ably::Auth do
773
809
  @block_called = 0
774
810
  end
775
811
 
776
- let(:token_client) { Ably::Rest::Client.new(default_options.merge(key: api_key, token_params: { ttl: 3 })) }
812
+ let(:token_client) { Ably::Rest::Client.new(default_options.merge(key: api_key, default_token_params: { ttl: 3 })) }
777
813
  let(:client_options) {
778
814
  default_options.merge(token: token_client.auth.request_token.token, auth_callback: Proc.new do
779
815
  @block_called += 1
@@ -800,7 +836,7 @@ describe Ably::Auth do
800
836
  let(:auth_token_object) { auth_client.auth.request_token }
801
837
 
802
838
  it 'rejects a TokenDetails object with an incompatible client_id and raises an exception' do
803
- expect { client.auth.authorise({}, force: true) }.to raise_error Ably::Exceptions::IncompatibleClientId
839
+ expect { client.auth.authorize({}) }.to raise_error Ably::Exceptions::IncompatibleClientId
804
840
  end
805
841
  end
806
842
 
@@ -808,7 +844,7 @@ describe Ably::Auth do
808
844
  let(:auth_token_object) { auth_client.auth.create_token_request }
809
845
 
810
846
  it 'rejects a TokenRequests object with an incompatible client_id and raises an exception' do
811
- expect { client.auth.authorise({}, force: true) }.to raise_error Ably::Exceptions::IncompatibleClientId
847
+ expect { client.auth.authorize({}) }.to raise_error Ably::Exceptions::IncompatibleClientId
812
848
  end
813
849
  end
814
850
 
@@ -816,7 +852,7 @@ describe Ably::Auth do
816
852
  let(:auth_token_object) { auth_client.auth.request_token(client_id: 'different').token }
817
853
 
818
854
  it 'rejects a TokenRequests object with an incompatible client_id and raises an exception' do
819
- client.auth.authorise({}, force: true)
855
+ client.auth.authorize({})
820
856
  expect(client.client_id).to eql(client_id)
821
857
  end
822
858
  end
@@ -838,28 +874,29 @@ describe Ably::Auth do
838
874
  auth_callback = Proc.new { subject }
839
875
  client_without_api_key = Ably::Rest::Client.new(default_options.merge(auth_callback: auth_callback))
840
876
  expect(client_without_api_key.auth).to be_using_token_auth
841
- expect { client_without_api_key.auth.authorise }.to_not raise_error
877
+ expect { client_without_api_key.auth.authorize }.to_not raise_error
842
878
  end
843
879
 
844
880
  it 'uses the key name from the client' do
845
881
  expect(subject['keyName']).to eql(key_name)
846
882
  end
847
883
 
848
- it 'uses the default TTL' do
849
- expect(subject['ttl']).to eql(Ably::Auth::TOKEN_DEFAULTS.fetch(:ttl) * 1000)
884
+ it 'specifies no TTL (#RSA5)' do
885
+ expect(subject['ttl']).to be_nil
850
886
  end
851
887
 
852
888
  context 'with a :ttl option below the Token expiry buffer that ensures tokens are renewed 15s before they expire as they are considered expired' do
853
- let(:ttl) { 1 }
889
+ let(:ttl) { 1 }
890
+ let(:token_params) { { ttl: ttl } }
854
891
 
855
892
  it 'uses the Token expiry buffer default + 10s to allow for a token request in flight' do
856
- expect(subject.ttl).to be > 1
857
- expect(subject.ttl).to be > Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER
893
+ expect(subject['ttl']).to be > 1
894
+ expect(subject['ttl']).to be > Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER
858
895
  end
859
896
  end
860
897
 
861
- it 'uses the default capability' do
862
- expect(subject['capability']).to eql(Ably::Auth::TOKEN_DEFAULTS.fetch(:capability).to_json)
898
+ it 'specifies no capability (#RSA6)' do
899
+ expect(subject['capability']).to be_nil
863
900
  end
864
901
 
865
902
  context 'the nonce' do
@@ -897,7 +934,7 @@ describe Ably::Auth do
897
934
  it 'uses these capabilities when Ably issues an actual token' do
898
935
  auth_callback = Proc.new { subject }
899
936
  client_without_api_key = Ably::Rest::Client.new(default_options.merge(auth_callback: auth_callback))
900
- client_without_api_key.auth.authorise
937
+ client_without_api_key.auth.authorize
901
938
  expect(client_without_api_key.auth.current_token_details.capability).to eql(capability)
902
939
  end
903
940
  end
@@ -1008,7 +1045,7 @@ describe Ably::Auth do
1008
1045
  auth.create_token_request(token_attributes)
1009
1046
  end
1010
1047
  client = Ably::Rest::Client.new(auth_callback: auth_callback, environment: environment, protocol: protocol)
1011
- client.auth.authorise
1048
+ client.auth.authorize
1012
1049
  end
1013
1050
  end
1014
1051
  end
@@ -1053,6 +1090,42 @@ describe Ably::Auth do
1053
1090
  it 'cannot be renewed automatically' do
1054
1091
  expect(token_auth_client.auth).to_not be_token_renewable
1055
1092
  end
1093
+
1094
+ context 'and the token expires' do
1095
+ let(:ttl) { 1 }
1096
+
1097
+ before do
1098
+ stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', 0 # allow token to be used even if about to expire
1099
+ stub_const 'Ably::Auth::TOKEN_DEFAULTS', Ably::Auth::TOKEN_DEFAULTS.merge(renew_token_buffer: 0) # Ensure tokens issued expire immediately after issue
1100
+
1101
+ @token = auth.request_token(ttl: ttl)
1102
+ WebMock.enable!
1103
+ WebMock.disable_net_connect!
1104
+
1105
+ token_expired = {
1106
+ "error" => {
1107
+ "statusCode" => 401,
1108
+ "code" => 40140,
1109
+ "message" => "Token expired"
1110
+ }
1111
+ }
1112
+
1113
+ stub_request(:post, "https://#{environment}-rest.ably.io/channels/foo/publish").
1114
+ to_return(status: 401, body: token_expired.to_json, headers: { 'Content-Type' => 'application/json' })
1115
+ end
1116
+
1117
+ after do
1118
+ WebMock.allow_net_connect!
1119
+ WebMock.disable!
1120
+ end
1121
+
1122
+ let(:token) { @token.token }
1123
+
1124
+ it 'should indicate an error and not retry the request (#RSA4a)' do
1125
+ sleep ttl + 1
1126
+ expect { token_auth_client.channels.get('foo').publish 'event' }.to raise_error(Ably::Exceptions::TokenExpired)
1127
+ end
1128
+ end
1056
1129
  end
1057
1130
 
1058
1131
  context 'when implicit as a result of using :client_id' do
@@ -1095,14 +1168,14 @@ describe Ably::Auth do
1095
1168
  expect(client.channel('foo').publish('event', 'data')).to be_truthy
1096
1169
  end
1097
1170
 
1098
- it 'with capability and TTL defaults' do
1171
+ it 'with capability and TTL defaults (#TK2a, #TK2b)' do
1099
1172
  client.channel('foo').publish('event', 'data')
1100
1173
 
1101
1174
  expect(token).to be_a(Ably::Models::TokenDetails)
1102
- capability_with_str_key = Ably::Auth::TOKEN_DEFAULTS.fetch(:capability)
1175
+ capability_with_str_key = { "*" => ["*"] } # Ably default is all capabilities
1103
1176
  capability = Hash[capability_with_str_key.keys.map(&:to_s).zip(capability_with_str_key.values)]
1104
1177
  expect(token.capability).to eq(capability)
1105
- expect(token.expires.to_i).to be_within(2).of(Time.now.to_i + Ably::Auth::TOKEN_DEFAULTS.fetch(:ttl))
1178
+ expect(token.expires.to_i).to be_within(2).of(Time.now.to_i + 60 * 60) # Ably default is 1hr
1106
1179
  expect(token.client_id).to eq(client_id)
1107
1180
  end
1108
1181
 
@@ -1112,6 +1185,54 @@ describe Ably::Auth do
1112
1185
  end
1113
1186
  end
1114
1187
 
1188
+ context 'when token expires' do
1189
+ before do
1190
+ stub_const 'Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER', 0 # allow token to be used even if about to expire
1191
+ stub_const 'Ably::Auth::TOKEN_DEFAULTS', Ably::Auth::TOKEN_DEFAULTS.merge(renew_token_buffer: 0) # Ensure tokens issued expire immediately after issue
1192
+ end
1193
+
1194
+ after do
1195
+ WebMock.allow_net_connect!
1196
+ WebMock.disable!
1197
+ end
1198
+
1199
+ let(:client_options) { default_options.merge(use_token_auth: true, key: api_key, query_time: true, default_token_params: { ttl: 2 }) }
1200
+ let(:channel) { client.channels.get(random_str) }
1201
+ let(:token_expired_response) do
1202
+ {
1203
+ "error" => {
1204
+ "statusCode" => 401,
1205
+ "code" => 40140,
1206
+ "message" => "Token expired"
1207
+ }
1208
+ }
1209
+ end
1210
+
1211
+ it 'automatically renews the token (#RSA4b)' do
1212
+ expect(auth.current_token_details).to be_nil
1213
+ channel.publish 'event'
1214
+ token = auth.current_token_details
1215
+ expect(token).to_not be_nil
1216
+ sleep 2.5
1217
+ channel.publish 'event'
1218
+ expect(auth.current_token_details).to_not eql(token)
1219
+ end
1220
+
1221
+ it 'fails if the token renewal fails (#RSA4b)' do
1222
+ expect(auth.current_token_details).to be_nil
1223
+ channel.publish 'event'
1224
+ token = auth.current_token_details
1225
+ expect(token).to_not be_nil
1226
+ sleep 2.5
1227
+ WebMock.enable!
1228
+ WebMock.disable_net_connect!
1229
+ stub_request(:post, "https://#{environment}-rest.ably.io/keys/#{TestApp.instance.key_name}/requestToken").
1230
+ to_return(status: 401, body: token_expired_response.to_json, headers: { 'Content-Type' => 'application/json' })
1231
+ expect { channel.publish 'event' }.to raise_error Ably::Exceptions::TokenExpired
1232
+ expect(auth.current_token_details).to eql(token)
1233
+ end
1234
+ end
1235
+
1115
1236
  context 'when :client_id is provided in a token' do
1116
1237
  let(:client_id) { '123' }
1117
1238
  let(:token) do
@@ -1202,5 +1323,47 @@ describe Ably::Auth do
1202
1323
  expect(auth).to be_using_basic_auth
1203
1324
  end
1204
1325
  end
1326
+
1327
+ context 'deprecated #authorise' do
1328
+ let(:client_options) { default_options.merge(key: api_key, logger: custom_logger_object, use_token_auth: true) }
1329
+ let(:custom_logger) do
1330
+ Class.new do
1331
+ def initialize
1332
+ @messages = []
1333
+ end
1334
+
1335
+ [:fatal, :error, :warn, :info, :debug].each do |severity|
1336
+ define_method severity do |message, &block|
1337
+ message_val = [message]
1338
+ message_val << block.call if block
1339
+
1340
+ @messages << [severity, message_val.compact.join(' ')]
1341
+ end
1342
+ end
1343
+
1344
+ def logs
1345
+ @messages
1346
+ end
1347
+
1348
+ def level
1349
+ 1
1350
+ end
1351
+
1352
+ def level=(new_level)
1353
+ end
1354
+ end
1355
+ end
1356
+ let(:custom_logger_object) { custom_logger.new }
1357
+
1358
+ it 'logs a deprecation warning (#RSA10l)' do
1359
+ client.auth.authorise
1360
+ expect(custom_logger_object.logs.find { |severity, message| message.match(/authorise.*deprecated/i)} ).to_not be_nil
1361
+ end
1362
+
1363
+ it 'returns a valid token (#RSA10l)' do
1364
+ response = client.auth.authorise
1365
+ expect(response).to be_a(Ably::Models::TokenDetails)
1366
+ end
1367
+ end
1205
1368
  end
1206
1369
  end