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
@@ -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::
|
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::
|
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
|
449
|
-
before { auth.
|
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
|
504
|
-
before { auth.
|
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 #
|
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 '#
|
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.
|
603
|
+
auth.authorize token_params, auth_options
|
604
604
|
end
|
605
605
|
|
606
606
|
it 'returns a valid token' do
|
607
|
-
expect(auth.
|
607
|
+
expect(auth.authorize).to be_a(Ably::Models::TokenDetails)
|
608
608
|
end
|
609
609
|
|
610
|
-
it 'issues a new token
|
611
|
-
expect { auth.
|
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.
|
628
|
-
auth.
|
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.
|
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.
|
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.
|
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
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
746
|
+
expect { auth.authorize }.to change { auth.current_token_details }
|
711
747
|
end
|
712
748
|
|
713
|
-
it 'issues a new token
|
714
|
-
expect { auth.
|
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
|
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.
|
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
|
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.
|
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.
|
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,
|
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.
|
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.
|
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.
|
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.
|
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 '
|
849
|
-
expect(subject['ttl']).to
|
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)
|
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
|
857
|
-
expect(subject
|
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 '
|
862
|
-
expect(subject['capability']).to
|
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.
|
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.
|
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
|
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
|
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
|