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