ably-rest 0.9.3 → 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/ably-rest.gemspec +2 -1
- data/lib/submodules/ably-ruby/.travis.yml +6 -4
- data/lib/submodules/ably-ruby/CHANGELOG.md +52 -61
- data/lib/submodules/ably-ruby/README.md +10 -0
- data/lib/submodules/ably-ruby/SPEC.md +1473 -852
- data/lib/submodules/ably-ruby/ably.gemspec +2 -1
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +57 -25
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +34 -8
- data/lib/submodules/ably-ruby/lib/ably/logger.rb +10 -1
- data/lib/submodules/ably-ruby/lib/ably/models/auth_details.rb +42 -0
- data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +18 -4
- data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +6 -3
- data/lib/submodules/ably-ruby/lib/ably/models/connection_state_change.rb +4 -3
- data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +12 -1
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +101 -97
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +13 -1
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +20 -3
- data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +7 -3
- data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +17 -7
- data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +29 -14
- data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +7 -4
- data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +2 -4
- data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +7 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +2 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +79 -31
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +62 -26
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +154 -65
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +14 -15
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +16 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +38 -29
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +108 -49
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +165 -59
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +22 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +19 -10
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +67 -45
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +198 -36
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_manager.rb +30 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence/presence_state_machine.rb +5 -12
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +3 -3
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +21 -8
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +1 -3
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/util/safe_deferrable.rb +26 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +416 -99
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +5 -3
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +1011 -160
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +458 -27
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +436 -97
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +52 -23
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +5 -3
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +1160 -105
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +151 -22
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +88 -27
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +42 -15
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +4 -4
- data/lib/submodules/ably-ruby/spec/rspec_config.rb +2 -1
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +2 -2
- data/lib/submodules/ably-ruby/spec/shared/safe_deferrable_behaviour.rb +6 -2
- data/lib/submodules/ably-ruby/spec/support/debug_failure_helper.rb +20 -4
- data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +32 -1
- data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +4 -11
- data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +28 -2
- data/lib/submodules/ably-ruby/spec/unit/models/auth_details_spec.rb +49 -0
- data/lib/submodules/ably-ruby/spec/unit/models/channel_state_change_spec.rb +23 -3
- data/lib/submodules/ably-ruby/spec/unit/models/connection_details_spec.rb +12 -1
- data/lib/submodules/ably-ruby/spec/unit/models/connection_state_change_spec.rb +15 -4
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +34 -2
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +73 -2
- data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +64 -6
- data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/models/token_request_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +2 -1
- data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +69 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +149 -22
- data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +9 -3
- data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +8 -5
- data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +4 -3
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +3 -3
- metadata +7 -5
|
@@ -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
|
|
@@ -612,7 +612,7 @@ describe Ably::Auth do
|
|
|
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,7 +621,7 @@ 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
627
|
auth.authorize({}, query_time: true)
|
|
@@ -630,6 +630,27 @@ describe Ably::Auth do
|
|
|
630
630
|
end
|
|
631
631
|
end
|
|
632
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({})
|
|
650
|
+
expect(auth.auth_options).to_not have_key(:query_time)
|
|
651
|
+
end
|
|
652
|
+
end
|
|
653
|
+
|
|
633
654
|
context 'TokenParams argument' do
|
|
634
655
|
let(:default_token_params) { { ttl: 23 } }
|
|
635
656
|
|
|
@@ -644,11 +665,11 @@ describe Ably::Auth do
|
|
|
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
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
|
|
|
@@ -656,6 +677,14 @@ describe Ably::Auth do
|
|
|
656
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
|
|
@@ -680,7 +709,7 @@ describe Ably::Auth do
|
|
|
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
|
|
712
|
+
it 'updates defaults when present and all previous configured AuthOptions are discarded (#RSA10g)' do
|
|
684
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
|
|
@@ -691,6 +720,18 @@ describe Ably::Auth do
|
|
|
691
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
|
|
@@ -768,7 +809,7 @@ describe Ably::Auth do
|
|
|
768
809
|
@block_called = 0
|
|
769
810
|
end
|
|
770
811
|
|
|
771
|
-
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 })) }
|
|
772
813
|
let(:client_options) {
|
|
773
814
|
default_options.merge(token: token_client.auth.request_token.token, auth_callback: Proc.new do
|
|
774
815
|
@block_called += 1
|
|
@@ -840,21 +881,22 @@ describe Ably::Auth do
|
|
|
840
881
|
expect(subject['keyName']).to eql(key_name)
|
|
841
882
|
end
|
|
842
883
|
|
|
843
|
-
it '
|
|
844
|
-
expect(subject['ttl']).to
|
|
884
|
+
it 'specifies no TTL (#RSA5)' do
|
|
885
|
+
expect(subject['ttl']).to be_nil
|
|
845
886
|
end
|
|
846
887
|
|
|
847
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
|
|
848
|
-
let(:ttl)
|
|
889
|
+
let(:ttl) { 1 }
|
|
890
|
+
let(:token_params) { { ttl: ttl } }
|
|
849
891
|
|
|
850
892
|
it 'uses the Token expiry buffer default + 10s to allow for a token request in flight' do
|
|
851
|
-
expect(subject
|
|
852
|
-
expect(subject
|
|
893
|
+
expect(subject['ttl']).to be > 1
|
|
894
|
+
expect(subject['ttl']).to be > Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER
|
|
853
895
|
end
|
|
854
896
|
end
|
|
855
897
|
|
|
856
|
-
it '
|
|
857
|
-
expect(subject['capability']).to
|
|
898
|
+
it 'specifies no capability (#RSA6)' do
|
|
899
|
+
expect(subject['capability']).to be_nil
|
|
858
900
|
end
|
|
859
901
|
|
|
860
902
|
context 'the nonce' do
|
|
@@ -1048,6 +1090,42 @@ describe Ably::Auth do
|
|
|
1048
1090
|
it 'cannot be renewed automatically' do
|
|
1049
1091
|
expect(token_auth_client.auth).to_not be_token_renewable
|
|
1050
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
|
|
1051
1129
|
end
|
|
1052
1130
|
|
|
1053
1131
|
context 'when implicit as a result of using :client_id' do
|
|
@@ -1090,14 +1168,14 @@ describe Ably::Auth do
|
|
|
1090
1168
|
expect(client.channel('foo').publish('event', 'data')).to be_truthy
|
|
1091
1169
|
end
|
|
1092
1170
|
|
|
1093
|
-
it 'with capability and TTL defaults' do
|
|
1171
|
+
it 'with capability and TTL defaults (#TK2a, #TK2b)' do
|
|
1094
1172
|
client.channel('foo').publish('event', 'data')
|
|
1095
1173
|
|
|
1096
1174
|
expect(token).to be_a(Ably::Models::TokenDetails)
|
|
1097
|
-
capability_with_str_key = Ably
|
|
1175
|
+
capability_with_str_key = { "*" => ["*"] } # Ably default is all capabilities
|
|
1098
1176
|
capability = Hash[capability_with_str_key.keys.map(&:to_s).zip(capability_with_str_key.values)]
|
|
1099
1177
|
expect(token.capability).to eq(capability)
|
|
1100
|
-
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
|
|
1101
1179
|
expect(token.client_id).to eq(client_id)
|
|
1102
1180
|
end
|
|
1103
1181
|
|
|
@@ -1107,6 +1185,54 @@ describe Ably::Auth do
|
|
|
1107
1185
|
end
|
|
1108
1186
|
end
|
|
1109
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
|
+
|
|
1110
1236
|
context 'when :client_id is provided in a token' do
|
|
1111
1237
|
let(:client_id) { '123' }
|
|
1112
1238
|
let(:token) do
|
|
@@ -1199,7 +1325,7 @@ describe Ably::Auth do
|
|
|
1199
1325
|
end
|
|
1200
1326
|
|
|
1201
1327
|
context 'deprecated #authorise' do
|
|
1202
|
-
let(:client_options) { default_options.merge(key: api_key, logger: custom_logger_object) }
|
|
1328
|
+
let(:client_options) { default_options.merge(key: api_key, logger: custom_logger_object, use_token_auth: true) }
|
|
1203
1329
|
let(:custom_logger) do
|
|
1204
1330
|
Class.new do
|
|
1205
1331
|
def initialize
|
|
@@ -1207,8 +1333,11 @@ describe Ably::Auth do
|
|
|
1207
1333
|
end
|
|
1208
1334
|
|
|
1209
1335
|
[:fatal, :error, :warn, :info, :debug].each do |severity|
|
|
1210
|
-
define_method severity do |message|
|
|
1211
|
-
|
|
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(' ')]
|
|
1212
1341
|
end
|
|
1213
1342
|
end
|
|
1214
1343
|
|
|
@@ -84,7 +84,7 @@ describe Ably::Rest::Channel do
|
|
|
84
84
|
|
|
85
85
|
context 'without adequate permissions on the channel' do
|
|
86
86
|
let(:capability) { { onlyChannel: ['subscribe'] } }
|
|
87
|
-
let(:client_options) { default_options.merge(use_token_auth: true,
|
|
87
|
+
let(:client_options) { default_options.merge(use_token_auth: true, default_token_params: { capability: capability }) }
|
|
88
88
|
|
|
89
89
|
it 'raises a permission error when publishing' do
|
|
90
90
|
expect { channel.publish(name, data) }.to raise_error(Ably::Exceptions::UnauthorizedRequest, /not permitted/)
|
|
@@ -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) }
|
|
@@ -272,7 +295,7 @@ describe Ably::Rest::Client do
|
|
|
272
295
|
context 'configured' do
|
|
273
296
|
let(:client_options) { default_options.merge(key: api_key, environment: 'production') }
|
|
274
297
|
|
|
275
|
-
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
|
|
276
299
|
hosts = []
|
|
277
300
|
5.times do
|
|
278
301
|
hosts << client.fallback_connection.host
|
|
@@ -281,7 +304,7 @@ describe Ably::Rest::Client do
|
|
|
281
304
|
end
|
|
282
305
|
end
|
|
283
306
|
|
|
284
|
-
context 'when environment is NOT production' do
|
|
307
|
+
context 'when environment is NOT production (#RSC15b)' do
|
|
285
308
|
let(:client_options) { default_options.merge(environment: 'sandbox', key: api_key) }
|
|
286
309
|
let!(:default_host_request_stub) do
|
|
287
310
|
stub_request(:post, "https://#{environment}-#{Ably::Rest::Client::DOMAIN}#{path}").to_return do
|
|
@@ -304,7 +327,8 @@ describe Ably::Rest::Client do
|
|
|
304
327
|
environment: nil,
|
|
305
328
|
key: api_key,
|
|
306
329
|
http_max_retry_duration: max_retry_duration,
|
|
307
|
-
http_max_retry_count: max_retry_count
|
|
330
|
+
http_max_retry_count: max_retry_count,
|
|
331
|
+
log_level: :error
|
|
308
332
|
)
|
|
309
333
|
end
|
|
310
334
|
|
|
@@ -327,7 +351,7 @@ describe Ably::Rest::Client do
|
|
|
327
351
|
end
|
|
328
352
|
end
|
|
329
353
|
|
|
330
|
-
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
|
|
331
355
|
expect { publish_block.call }.to raise_error Ably::Exceptions::ConnectionError, /ssl error message/
|
|
332
356
|
expect(default_host_request_stub).to have_been_requested
|
|
333
357
|
expect(first_fallback_request_stub).to have_been_requested
|
|
@@ -366,6 +390,43 @@ describe Ably::Rest::Client do
|
|
|
366
390
|
end
|
|
367
391
|
end
|
|
368
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
|
+
|
|
369
430
|
context 'and basic authentication fails' do
|
|
370
431
|
let(:status) { 401 }
|
|
371
432
|
let!(:default_host_request_stub) do
|
|
@@ -404,7 +465,7 @@ describe Ably::Rest::Client do
|
|
|
404
465
|
stub_request(:post, "https://#{Ably::Rest::Client::DOMAIN}#{path}").to_return(&fallback_block)
|
|
405
466
|
end
|
|
406
467
|
|
|
407
|
-
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
|
|
408
469
|
expect { publish_block.call }.to raise_error(Ably::Exceptions::ServerError)
|
|
409
470
|
expect(default_host_request_stub).to have_been_requested
|
|
410
471
|
expect(first_fallback_request_stub).to have_been_requested
|
|
@@ -450,10 +511,10 @@ describe Ably::Rest::Client do
|
|
|
450
511
|
end
|
|
451
512
|
|
|
452
513
|
let(:client_options) {
|
|
453
|
-
production_options.merge(fallback_hosts: custom_hosts)
|
|
514
|
+
production_options.merge(fallback_hosts: custom_hosts, log_level: :error)
|
|
454
515
|
}
|
|
455
516
|
|
|
456
|
-
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
|
|
457
518
|
expect { publish_block.call }.to raise_error(Ably::Exceptions::ServerError)
|
|
458
519
|
expect(default_host_request_stub).to have_been_requested
|
|
459
520
|
expect(first_fallback_request_stub).to have_been_requested
|
|
@@ -461,7 +522,7 @@ describe Ably::Rest::Client do
|
|
|
461
522
|
end
|
|
462
523
|
end
|
|
463
524
|
|
|
464
|
-
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
|
|
465
526
|
let(:client_options) {
|
|
466
527
|
production_options.merge(fallback_hosts: [])
|
|
467
528
|
}
|
|
@@ -485,7 +546,7 @@ describe Ably::Rest::Client do
|
|
|
485
546
|
|
|
486
547
|
context 'and timing out the primary host' do
|
|
487
548
|
before do
|
|
488
|
-
@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"))
|
|
489
550
|
@web_server.mount_proc "/channels/#{channel_name}/publish" do |req, res|
|
|
490
551
|
if req.header["host"].first.include?(primary_host)
|
|
491
552
|
@primary_host_requested = true
|
|
@@ -516,12 +577,13 @@ describe Ably::Rest::Client do
|
|
|
516
577
|
port: port,
|
|
517
578
|
tls: false,
|
|
518
579
|
http_request_timeout: request_timeout,
|
|
519
|
-
max_retry_duration: request_timeout * 3
|
|
580
|
+
max_retry_duration: request_timeout * 3,
|
|
581
|
+
log_level: :error
|
|
520
582
|
)
|
|
521
583
|
end
|
|
522
584
|
let(:fail_fallback_request_count) { 1 }
|
|
523
585
|
|
|
524
|
-
it 'tries one of the fallback hosts' do
|
|
586
|
+
it 'tries one of the fallback hosts (#RSC15d)' do
|
|
525
587
|
client.channel(channel_name).publish('event', 'data')
|
|
526
588
|
expect(@primary_host_requested).to be_truthy
|
|
527
589
|
expect(@fallback_request_count).to eql(2)
|
|
@@ -537,12 +599,13 @@ describe Ably::Rest::Client do
|
|
|
537
599
|
port: port,
|
|
538
600
|
tls: false,
|
|
539
601
|
http_request_timeout: request_timeout,
|
|
540
|
-
max_retry_duration: request_timeout / 2
|
|
602
|
+
max_retry_duration: request_timeout / 2,
|
|
603
|
+
log_level: :error
|
|
541
604
|
)
|
|
542
605
|
end
|
|
543
606
|
let(:fail_fallback_request_count) { 0 }
|
|
544
607
|
|
|
545
|
-
it 'tries one of the fallback hosts' do
|
|
608
|
+
it 'tries one of the fallback hosts (#RSC15d)' do
|
|
546
609
|
client.channel(channel_name).publish('event', 'data')
|
|
547
610
|
expect(@primary_host_requested).to be_truthy
|
|
548
611
|
expect(@fallback_request_count).to eql(1)
|
|
@@ -552,7 +615,7 @@ describe Ably::Rest::Client do
|
|
|
552
615
|
|
|
553
616
|
context 'and failing the primary host' do
|
|
554
617
|
before do
|
|
555
|
-
@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"))
|
|
556
619
|
@web_server.mount_proc "/channels/#{channel_name}/publish" do |req, res|
|
|
557
620
|
if req.header["host"].first.include?(primary_host)
|
|
558
621
|
@primary_host_requested = true
|
|
@@ -580,7 +643,8 @@ describe Ably::Rest::Client do
|
|
|
580
643
|
fallback_hosts: fallbacks,
|
|
581
644
|
token: 'fake.token',
|
|
582
645
|
port: port,
|
|
583
|
-
tls: false
|
|
646
|
+
tls: false,
|
|
647
|
+
log_level: :error
|
|
584
648
|
)
|
|
585
649
|
end
|
|
586
650
|
let(:fail_fallback_request_count) { 1 }
|
|
@@ -632,10 +696,10 @@ describe Ably::Rest::Client do
|
|
|
632
696
|
end
|
|
633
697
|
|
|
634
698
|
let(:client_options) {
|
|
635
|
-
production_options.merge(fallback_hosts: custom_hosts)
|
|
699
|
+
production_options.merge(fallback_hosts: custom_hosts, log_level: :error)
|
|
636
700
|
}
|
|
637
701
|
|
|
638
|
-
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
|
|
639
703
|
expect { publish_block.call }.to raise_error(Ably::Exceptions::ServerError)
|
|
640
704
|
expect(default_host_request_stub).to have_been_requested
|
|
641
705
|
expect(first_fallback_request_stub).to have_been_requested
|
|
@@ -661,10 +725,6 @@ describe Ably::Rest::Client do
|
|
|
661
725
|
stub_const 'Ably::FALLBACK_HOSTS', custom_hosts
|
|
662
726
|
end
|
|
663
727
|
|
|
664
|
-
let(:client_options) {
|
|
665
|
-
production_options.merge(fallback_hosts_use_default: true)
|
|
666
|
-
}
|
|
667
|
-
|
|
668
728
|
let!(:first_fallback_request_stub) do
|
|
669
729
|
stub_request(:post, "https://#{Ably::FALLBACK_HOSTS[0]}#{path}").to_return(&fallback_block)
|
|
670
730
|
end
|
|
@@ -674,7 +734,7 @@ describe Ably::Rest::Client do
|
|
|
674
734
|
end
|
|
675
735
|
|
|
676
736
|
let(:client_options) {
|
|
677
|
-
production_options.merge(fallback_hosts: custom_hosts)
|
|
737
|
+
production_options.merge(fallback_hosts: custom_hosts, log_level: :error)
|
|
678
738
|
}
|
|
679
739
|
|
|
680
740
|
it 'attempts the default fallback hosts as this is an authentication failure' do
|
|
@@ -758,16 +818,16 @@ describe Ably::Rest::Client do
|
|
|
758
818
|
expect(client.http_defaults[:open_timeout]).to eql(4)
|
|
759
819
|
end
|
|
760
820
|
|
|
761
|
-
specify '#http_request_timeout is
|
|
762
|
-
expect(client.http_defaults[:request_timeout]).to eql(
|
|
821
|
+
specify '#http_request_timeout is 10s' do
|
|
822
|
+
expect(client.http_defaults[:request_timeout]).to eql(10)
|
|
763
823
|
end
|
|
764
824
|
|
|
765
825
|
specify '#http_max_retry_count is 3' do
|
|
766
826
|
expect(client.http_defaults[:max_retry_count]).to eql(3)
|
|
767
827
|
end
|
|
768
828
|
|
|
769
|
-
specify '#http_max_retry_duration is
|
|
770
|
-
expect(client.http_defaults[:max_retry_duration]).to eql(
|
|
829
|
+
specify '#http_max_retry_duration is 15s' do
|
|
830
|
+
expect(client.http_defaults[:max_retry_duration]).to eql(15)
|
|
771
831
|
end
|
|
772
832
|
end
|
|
773
833
|
|
|
@@ -848,9 +908,10 @@ describe Ably::Rest::Client do
|
|
|
848
908
|
to_return(status: 201, body: '{}', headers: { 'Content-Type' => 'application/json' })
|
|
849
909
|
end
|
|
850
910
|
|
|
851
|
-
it 'sends a protocol version and lib version header' do
|
|
911
|
+
it 'sends a protocol version and lib version header (#G4, #RSC7a, #RSC7b)' do
|
|
852
912
|
client.channels.get('foo').publish("event")
|
|
853
913
|
expect(publish_message_stub).to have_been_requested
|
|
914
|
+
expect(Ably::PROTOCOL_VERSION).to eql('1.0')
|
|
854
915
|
end
|
|
855
916
|
end
|
|
856
917
|
end
|