ably-rest 0.8.9 → 0.8.13
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/README.md +54 -21
- data/ably-rest.gemspec +6 -2
- data/lib/ably-rest.rb +2 -0
- data/lib/submodules/ably-ruby/CHANGELOG.md +42 -4
- data/lib/submodules/ably-ruby/README.md +2 -3
- data/lib/submodules/ably-ruby/ably.gemspec +6 -2
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +80 -21
- data/lib/submodules/ably-ruby/lib/ably/modules/message_emitter.rb +5 -2
- data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +22 -4
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +8 -6
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +4 -2
- data/lib/submodules/ably-ruby/lib/ably/version.rb +3 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +189 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +19 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +20 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +132 -10
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +19 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +122 -4
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +17 -0
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +3 -3
- data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +28 -0
- metadata +2 -2
@@ -67,9 +67,9 @@ module Ably
|
|
67
67
|
# token_details #=> Ably::Models::TokenDetails
|
68
68
|
# end
|
69
69
|
#
|
70
|
-
def authorise(token_params =
|
70
|
+
def authorise(token_params = nil, auth_options = nil, &success_callback)
|
71
71
|
async_wrap(success_callback) do
|
72
|
-
auth_sync.authorise(token_params, auth_options)
|
72
|
+
auth_sync.authorise(token_params, auth_options, &method(:upgrade_authentication_block).to_proc)
|
73
73
|
end.tap do |deferrable|
|
74
74
|
deferrable.errback do |error|
|
75
75
|
client.connection.transition_state_machine :failed, reason: error if error.kind_of?(Ably::Exceptions::IncompatibleClientId)
|
@@ -82,8 +82,8 @@ module Ably
|
|
82
82
|
# @option (see Ably::Auth#authorise)
|
83
83
|
# @return [Ably::Models::TokenDetails]
|
84
84
|
#
|
85
|
-
def authorise_sync(token_params =
|
86
|
-
auth_sync.authorise(token_params, auth_options)
|
85
|
+
def authorise_sync(token_params = nil, auth_options = nil)
|
86
|
+
auth_sync.authorise(token_params, auth_options, &method(:upgrade_authentication_block).to_proc)
|
87
87
|
end
|
88
88
|
|
89
89
|
# def_delegator :auth_sync, :request_token, :request_token_sync
|
@@ -196,6 +196,24 @@ module Ably
|
|
196
196
|
def client
|
197
197
|
@client
|
198
198
|
end
|
199
|
+
|
200
|
+
# If authorise is called with true, this block is executed so that it
|
201
|
+
# can perform the authentication upgrade
|
202
|
+
def upgrade_authentication_block(new_token)
|
203
|
+
# This block is called if the authorisation was forced
|
204
|
+
if client.connection.connected? || client.connection.connecting?
|
205
|
+
logger.debug "Realtime::Auth - authorise called with { force: true } so forcibly disconnecting transport to initiate auth upgrade"
|
206
|
+
block = Proc.new do
|
207
|
+
if client.connection.transport
|
208
|
+
logger.debug "Realtime::Auth - current transport disconnected"
|
209
|
+
client.connection.transport.disconnect
|
210
|
+
else
|
211
|
+
EventMachine.add_timer(0.1, &block)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
block.call
|
215
|
+
end
|
216
|
+
end
|
199
217
|
end
|
200
218
|
end
|
201
219
|
end
|
@@ -144,7 +144,7 @@ module Ably::Realtime
|
|
144
144
|
end
|
145
145
|
|
146
146
|
def process_connection_error(protocol_message)
|
147
|
-
connection.manager.error_received_from_server
|
147
|
+
connection.manager.error_received_from_server(protocol_message.error || Ably::Models::ErrorInfo.new(message: 'Error reason unknown'))
|
148
148
|
end
|
149
149
|
|
150
150
|
def process_connected_message(protocol_message)
|
@@ -194,15 +194,15 @@ module Ably
|
|
194
194
|
|
195
195
|
# Sends a ping to Ably and yields the provided block when a heartbeat ping request is echoed from the server.
|
196
196
|
# This can be useful for measuring true roundtrip client to Ably server latency for a simple message, or checking that an underlying transport is responding currently.
|
197
|
-
# The elapsed
|
197
|
+
# The elapsed time in seconds is passed as an argument to the block and represents the time taken to echo a ping heartbeat once the connection is in the `:connected` state.
|
198
198
|
#
|
199
|
-
# @yield [Integer] if a block is passed to this method, then this block will be called once the ping heartbeat is received with the time elapsed in
|
199
|
+
# @yield [Integer] if a block is passed to this method, then this block will be called once the ping heartbeat is received with the time elapsed in seconds.
|
200
200
|
# If the ping is not received within an acceptable timeframe, the block will be called with +nil+ as he first argument
|
201
201
|
#
|
202
202
|
# @example
|
203
203
|
# client = Ably::Rest::Client.new(key: 'key.id:secret')
|
204
|
-
# client.connection.ping do |
|
205
|
-
# puts "Ping took #{
|
204
|
+
# client.connection.ping do |elapsed_s|
|
205
|
+
# puts "Ping took #{elapsed_s}s"
|
206
206
|
# end
|
207
207
|
#
|
208
208
|
# @return [void]
|
@@ -219,7 +219,7 @@ module Ably
|
|
219
219
|
if protocol_message.action == Ably::Models::ProtocolMessage::ACTION.Heartbeat
|
220
220
|
finished = true
|
221
221
|
__incoming_protocol_msgbus__.unsubscribe(:protocol_message, &wait_for_ping)
|
222
|
-
time_passed =
|
222
|
+
time_passed = Time.now.to_f - started.to_f
|
223
223
|
safe_yield block, time_passed if block_given?
|
224
224
|
end
|
225
225
|
end
|
@@ -387,7 +387,9 @@ module Ably
|
|
387
387
|
auth_deferrable.callback do |auth_params|
|
388
388
|
url_params = auth_params.merge(
|
389
389
|
format: client.protocol,
|
390
|
-
echo: client.echo_messages
|
390
|
+
echo: client.echo_messages,
|
391
|
+
v: Ably::PROTOCOL_VERSION,
|
392
|
+
lib: Ably::LIB_VERSION_ID,
|
391
393
|
)
|
392
394
|
|
393
395
|
url_params['clientId'] = client.auth.client_id if client.auth.has_client_id?
|
@@ -402,7 +402,7 @@ module Ably::Realtime
|
|
402
402
|
@renewing_token = true
|
403
403
|
logger.info "ConnectionManager: Token has expired and is renewable, renewing token now"
|
404
404
|
|
405
|
-
client.auth.authorise(
|
405
|
+
client.auth.authorise(nil, force: true).tap do |authorise_deferrable|
|
406
406
|
authorise_deferrable.callback do |token_details|
|
407
407
|
logger.info 'ConnectionManager: Token renewed succesfully following expiration'
|
408
408
|
|
@@ -120,7 +120,7 @@ module Ably
|
|
120
120
|
|
121
121
|
options = options.clone
|
122
122
|
if options.kind_of?(String)
|
123
|
-
options = if options.match(/^[\w]{2,}\.[\w]{2,}:[\w]{2,}$/)
|
123
|
+
options = if options.match(/^[\w-]{2,}\.[\w-]{2,}:[\w-]{2,}$/)
|
124
124
|
{ key: options }
|
125
125
|
else
|
126
126
|
{ token: options }
|
@@ -352,6 +352,8 @@ module Ably
|
|
352
352
|
unless options[:send_auth_header] == false
|
353
353
|
request.headers[:authorization] = auth.auth_header
|
354
354
|
end
|
355
|
+
request.headers['X-Ably-Version'] = Ably::PROTOCOL_VERSION
|
356
|
+
request.headers['X-Ably-Lib'] = Ably::LIB_VERSION_ID
|
355
357
|
end
|
356
358
|
|
357
359
|
rescue Faraday::TimeoutError, Faraday::ClientError, Ably::Exceptions::ServerError => error
|
@@ -376,7 +378,7 @@ module Ably
|
|
376
378
|
yield
|
377
379
|
rescue Ably::Exceptions::TokenExpired => e
|
378
380
|
if auth.token_renewable?
|
379
|
-
auth.authorise(
|
381
|
+
auth.authorise(nil, force: true)
|
380
382
|
yield
|
381
383
|
else
|
382
384
|
raise e
|
@@ -254,6 +254,195 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
254
254
|
end
|
255
255
|
end
|
256
256
|
end
|
257
|
+
|
258
|
+
context 'with force: true to trigger an authentication upgrade' do
|
259
|
+
let(:rest_client) { Ably::Rest::Client.new(default_options) }
|
260
|
+
let(:client_publisher) { auto_close Ably::Realtime::Client.new(default_options) }
|
261
|
+
let(:basic_capability) { JSON.dump("foo" => ["subscribe"]) }
|
262
|
+
let(:basic_token_cb) { Proc.new do
|
263
|
+
rest_client.auth.create_token_request({ capability: basic_capability })
|
264
|
+
end }
|
265
|
+
let(:upgraded_capability) { JSON.dump({ "foo" => ["subscribe", "publish"] }) }
|
266
|
+
let(:upgraded_token_cb) { Proc.new do
|
267
|
+
rest_client.auth.create_token_request({ capability: upgraded_capability })
|
268
|
+
end }
|
269
|
+
let(:identified_token_cb) { Proc.new do
|
270
|
+
rest_client.auth.create_token_request({ client_id: 'bob' })
|
271
|
+
end }
|
272
|
+
let(:downgraded_capability) { JSON.dump({ "bar" => ["subscribe"] }) }
|
273
|
+
let(:downgraded_token_cb) { Proc.new do
|
274
|
+
rest_client.auth.create_token_request({ capability: downgraded_capability })
|
275
|
+
end }
|
276
|
+
|
277
|
+
let(:client_options) { default_options.merge(auth_callback: basic_token_cb) }
|
278
|
+
|
279
|
+
it 'forces the connection to disconnect and reconnect with a new token when in the CONNECTED state' do
|
280
|
+
client.connection.once(:connected) do
|
281
|
+
existing_token = client.auth.current_token_details
|
282
|
+
client.auth.authorise(nil, force: true)
|
283
|
+
client.connection.once(:disconnected) do
|
284
|
+
client.connection.once(:connected) do
|
285
|
+
expect(existing_token).to_not eql(client.auth.current_token_details)
|
286
|
+
stop_reactor
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
it 'forces the connection to disconnect and reconnect with a new token when in the CONNECTING state' do
|
293
|
+
client.connection.once(:connecting) do
|
294
|
+
existing_token = client.auth.current_token_details
|
295
|
+
client.auth.authorise(nil, force: true)
|
296
|
+
client.connection.once(:disconnected) do
|
297
|
+
client.connection.once(:connected) do
|
298
|
+
expect(existing_token).to_not eql(client.auth.current_token_details)
|
299
|
+
stop_reactor
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
context 'when client is identified' do
|
306
|
+
let(:client_options) { default_options.merge(auth_callback: basic_token_cb, log_level: :none) }
|
307
|
+
|
308
|
+
let(:basic_token_cb) { Proc.new do
|
309
|
+
rest_client.auth.create_token_request({ client_id: 'mike', capability: basic_capability })
|
310
|
+
end }
|
311
|
+
|
312
|
+
it 'transisitions the connection state to FAILED if the client_id changes' do
|
313
|
+
client.connection.once(:connected) do
|
314
|
+
client.auth.authorise(nil, auth_callback: identified_token_cb, force: true)
|
315
|
+
client.connection.once(:failed) do
|
316
|
+
expect(client.connection.error_reason.message).to match(/incompatible.*client ID/)
|
317
|
+
stop_reactor
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
context 'when upgrading capabilities' do
|
324
|
+
let(:client_options) { default_options.merge(auth_callback: basic_token_cb, log_level: :error) }
|
325
|
+
|
326
|
+
it 'is allowed' do
|
327
|
+
client.connection.once(:connected) do
|
328
|
+
channel = client.channels.get('foo')
|
329
|
+
channel.publish('not-allowed').errback do |error|
|
330
|
+
expect(error.code).to eql(40160)
|
331
|
+
expect(error.message).to match(/permission denied/)
|
332
|
+
client.auth.authorise(nil, auth_callback: upgraded_token_cb, force: true)
|
333
|
+
client.connection.once(:connected) do
|
334
|
+
expect(client.connection.error_reason).to be_nil
|
335
|
+
channel.subscribe('allowed') do |message|
|
336
|
+
stop_reactor
|
337
|
+
end
|
338
|
+
channel.publish 'allowed'
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
context 'when downgrading capabilities' do
|
346
|
+
let(:client_options) { default_options.merge(auth_callback: basic_token_cb, log_level: :none) }
|
347
|
+
|
348
|
+
it 'is allowed and channels are detached' do
|
349
|
+
client.connection.once(:connected) do
|
350
|
+
channel = client.channels.get('foo')
|
351
|
+
channel.attach do
|
352
|
+
client.auth.authorise(nil, auth_callback: downgraded_token_cb, force: true)
|
353
|
+
channel.once(:failed) do
|
354
|
+
expect(channel.error_reason.code).to eql(40160)
|
355
|
+
expect(channel.error_reason.message).to match(/Channel denied access/)
|
356
|
+
stop_reactor
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
it 'ensures message delivery continuity whilst upgrading' do
|
364
|
+
received_messages = []
|
365
|
+
subscriber_channel = client.channels.get('foo')
|
366
|
+
publisher_channel = client_publisher.channels.get('foo')
|
367
|
+
subscriber_channel.attach do
|
368
|
+
subscriber_channel.subscribe do |message|
|
369
|
+
received_messages << message
|
370
|
+
end
|
371
|
+
publisher_channel.attach do
|
372
|
+
publisher_channel.publish('foo') do
|
373
|
+
EventMachine.add_timer(2) do
|
374
|
+
expect(received_messages.length).to eql(1)
|
375
|
+
client.auth.authorise(nil, force: true)
|
376
|
+
client.connection.once(:disconnected) do
|
377
|
+
publisher_channel.publish('bar') do
|
378
|
+
expect(received_messages.length).to eql(1)
|
379
|
+
end
|
380
|
+
end
|
381
|
+
client.connection.once(:connected) do
|
382
|
+
EventMachine.add_timer(2) do
|
383
|
+
expect(received_messages.length).to eql(2)
|
384
|
+
stop_reactor
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
it 'does not change the connection state if current connection state is closing' do
|
394
|
+
client.connection.once(:connected) do
|
395
|
+
client.connection.once(:closing) do
|
396
|
+
client.auth.authorise(nil, force: true)
|
397
|
+
client.connection.once(:connected) do
|
398
|
+
raise "Should not reconnect following auth force: true"
|
399
|
+
end
|
400
|
+
EventMachine.add_timer(4) do
|
401
|
+
expect(client.connection).to be_closed
|
402
|
+
stop_reactor
|
403
|
+
end
|
404
|
+
end
|
405
|
+
client.connection.close
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
it 'does not change the connection state if current connection state is closed' do
|
410
|
+
client.connection.once(:connected) do
|
411
|
+
client.connection.once(:closed) do
|
412
|
+
client.auth.authorise(nil, force: true)
|
413
|
+
client.connection.once(:connected) do
|
414
|
+
raise "Should not reconnect following auth force: true"
|
415
|
+
end
|
416
|
+
EventMachine.add_timer(4) do
|
417
|
+
expect(client.connection).to be_closed
|
418
|
+
stop_reactor
|
419
|
+
end
|
420
|
+
end
|
421
|
+
client.connection.close
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
context 'when state is failed' do
|
426
|
+
let(:client_options) { default_options.merge(auth_callback: basic_token_cb, log_level: :none) }
|
427
|
+
|
428
|
+
it 'does not change the connection state' do
|
429
|
+
client.connection.once(:connected) do
|
430
|
+
client.connection.once(:failed) do
|
431
|
+
client.auth.authorise(nil, force: true)
|
432
|
+
client.connection.once(:connected) do
|
433
|
+
raise "Should not reconnect following auth force: true"
|
434
|
+
end
|
435
|
+
EventMachine.add_timer(4) do
|
436
|
+
expect(client.connection).to be_failed
|
437
|
+
stop_reactor
|
438
|
+
end
|
439
|
+
end
|
440
|
+
protocol_message = Ably::Models::ProtocolMessage.new(action: Ably::Models::ProtocolMessage::ACTION.Error.to_i)
|
441
|
+
client.connection.__incoming_protocol_msgbus__.publish :protocol_message, protocol_message
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|
445
|
+
end
|
257
446
|
end
|
258
447
|
|
259
448
|
context '#authorise_async' do
|
@@ -908,6 +908,25 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
908
908
|
end
|
909
909
|
end
|
910
910
|
|
911
|
+
context 'with a callback that raises an exception' do
|
912
|
+
let(:exception) { StandardError.new("Intentional error") }
|
913
|
+
|
914
|
+
it 'logs the error and continues' do
|
915
|
+
emitted_exception = false
|
916
|
+
expect(client.logger).to receive(:error).with(/#{exception.message}/)
|
917
|
+
channel.subscribe('click') do |message|
|
918
|
+
emitted_exception = true
|
919
|
+
raise exception
|
920
|
+
end
|
921
|
+
channel.publish('click', 'data') do
|
922
|
+
EventMachine.add_timer(1) do
|
923
|
+
expect(emitted_exception).to eql(true)
|
924
|
+
stop_reactor
|
925
|
+
end
|
926
|
+
end
|
927
|
+
end
|
928
|
+
end
|
929
|
+
|
911
930
|
context 'many times with different event names' do
|
912
931
|
it 'filters events accordingly to each callback' do
|
913
932
|
click_callback = proc { |message| messages << message }
|
@@ -1356,5 +1356,25 @@ describe Ably::Realtime::Connection, :event_machine do
|
|
1356
1356
|
end
|
1357
1357
|
end
|
1358
1358
|
end
|
1359
|
+
|
1360
|
+
context 'version params' do
|
1361
|
+
it 'sends the protocol version param v' do
|
1362
|
+
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
1363
|
+
uri = URI.parse(url)
|
1364
|
+
expect(CGI::parse(uri.query)['v'][0]).to eql(Ably::PROTOCOL_VERSION)
|
1365
|
+
stop_reactor
|
1366
|
+
end
|
1367
|
+
client
|
1368
|
+
end
|
1369
|
+
|
1370
|
+
it 'sends the lib version param lib' do
|
1371
|
+
expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
|
1372
|
+
uri = URI.parse(url)
|
1373
|
+
expect(CGI::parse(uri.query)['lib'][0]).to eql("ruby-#{Ably::VERSION}")
|
1374
|
+
stop_reactor
|
1375
|
+
end
|
1376
|
+
client
|
1377
|
+
end
|
1378
|
+
end
|
1359
1379
|
end
|
1360
1380
|
end
|
@@ -483,11 +483,13 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
483
483
|
payload_description = "#{payload.class}#{" #{payload.encoding}" if payload.kind_of?(String)}"
|
484
484
|
|
485
485
|
it "delivers a #{payload_description} payload to the receiver" do
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
486
|
+
encrypted_channel_client2.attach do
|
487
|
+
encrypted_channel_client1.publish 'example', payload
|
488
|
+
encrypted_channel_client2.subscribe do |message|
|
489
|
+
expect(message.data).to eql(payload)
|
490
|
+
expect(message.encoding).to be_nil
|
491
|
+
stop_reactor
|
492
|
+
end
|
491
493
|
end
|
492
494
|
end
|
493
495
|
end
|
@@ -520,11 +522,13 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
520
522
|
let(:payload) { MessagePack.pack({ 'key' => random_str }) }
|
521
523
|
|
522
524
|
it 'delivers the message but still encrypted with a value in the #encoding attribute' do
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
525
|
+
unencrypted_channel_client2.attach do
|
526
|
+
encrypted_channel_client1.publish 'example', payload
|
527
|
+
unencrypted_channel_client2.subscribe do |message|
|
528
|
+
expect(message.data).to_not eql(payload)
|
529
|
+
expect(message.encoding).to match(/^cipher\+aes-256-cbc/)
|
530
|
+
stop_reactor
|
531
|
+
end
|
528
532
|
end
|
529
533
|
end
|
530
534
|
|
@@ -732,4 +736,122 @@ describe 'Ably::Realtime::Channel Message', :event_machine do
|
|
732
736
|
end
|
733
737
|
end
|
734
738
|
end
|
739
|
+
|
740
|
+
context 'message encoding interoperability' do
|
741
|
+
let(:client_options) { { key: api_key, environment: environment, protocol: :json } }
|
742
|
+
let(:channel_name) { "subscribe_send_text-#{random_str}" }
|
743
|
+
|
744
|
+
fixtures_path = File.expand_path('../../../../lib/submodules/ably-common/test-resources/messages-encoding.json', __FILE__)
|
745
|
+
|
746
|
+
context 'over a JSON transport' do
|
747
|
+
let(:realtime_client) do
|
748
|
+
auto_close Ably::Realtime::Client.new(client_options)
|
749
|
+
end
|
750
|
+
let(:rest_client) do
|
751
|
+
Ably::Rest::Client.new(client_options)
|
752
|
+
end
|
753
|
+
let(:realtime_channel) { realtime_client.channels.get(channel_name) }
|
754
|
+
|
755
|
+
JSON.parse(File.read(fixtures_path))['messages'].each do |encoding_spec|
|
756
|
+
context "when decoding #{encoding_spec['expectedType']}" do
|
757
|
+
it 'ensures that client libraries have compatible encoding and decoding using common fixtures' do
|
758
|
+
realtime_channel.attach do
|
759
|
+
realtime_channel.subscribe do |message|
|
760
|
+
if encoding_spec['expectedHexValue']
|
761
|
+
expect(message.data.unpack('H*').first).to eql(encoding_spec['expectedHexValue'])
|
762
|
+
else
|
763
|
+
expect(message.data).to eql(encoding_spec['expectedValue'])
|
764
|
+
end
|
765
|
+
stop_reactor
|
766
|
+
end
|
767
|
+
|
768
|
+
raw_message = { "data" => encoding_spec['data'], "encoding" => encoding_spec['encoding'] }
|
769
|
+
rest_client.post("/channels/#{channel_name}/messages", JSON.dump(raw_message))
|
770
|
+
end
|
771
|
+
end
|
772
|
+
end
|
773
|
+
|
774
|
+
context "when encoding #{encoding_spec['expectedType']}" do
|
775
|
+
it 'ensures that client libraries have compatible encoding and decoding using common fixtures' do
|
776
|
+
data = if encoding_spec['expectedHexValue']
|
777
|
+
encoding_spec['expectedHexValue'].scan(/../).map { |x| x.hex }.pack('c*')
|
778
|
+
else
|
779
|
+
encoding_spec['expectedValue']
|
780
|
+
end
|
781
|
+
|
782
|
+
realtime_channel.publish("event", data) do
|
783
|
+
response = rest_client.get("/channels/#{channel_name}/messages")
|
784
|
+
message = response.body[0]
|
785
|
+
expect(message['encoding']).to eql(encoding_spec['encoding'])
|
786
|
+
if message['encoding'] == 'json'
|
787
|
+
expect(JSON.parse(encoding_spec['data'])).to eql(JSON.parse(message['data']))
|
788
|
+
else
|
789
|
+
expect(encoding_spec['data']).to eql(message['data'])
|
790
|
+
end
|
791
|
+
stop_reactor
|
792
|
+
end
|
793
|
+
end
|
794
|
+
end
|
795
|
+
end
|
796
|
+
end
|
797
|
+
|
798
|
+
context 'over a MsgPack transport' do
|
799
|
+
JSON.parse(File.read(fixtures_path))['messages'].each do |encoding_spec|
|
800
|
+
context "when publishing a #{encoding_spec['expectedType']} using JSON protocol" do
|
801
|
+
let(:rest_publish_client) do
|
802
|
+
Ably::Rest::Client.new(client_options.merge(protocol: :json))
|
803
|
+
end
|
804
|
+
let(:realtime_subscribe_client) do
|
805
|
+
Ably::Realtime::Client.new(client_options.merge(protocol: :msgpack))
|
806
|
+
end
|
807
|
+
let(:realtime_subscribe_channel) { realtime_subscribe_client.channels.get(channel_name) }
|
808
|
+
|
809
|
+
it 'receives the message over MsgPack and the data matches' do
|
810
|
+
expect(realtime_subscribe_client).to be_protocol_binary
|
811
|
+
|
812
|
+
realtime_subscribe_channel.attach do
|
813
|
+
realtime_subscribe_channel.subscribe do |message|
|
814
|
+
if encoding_spec['expectedHexValue']
|
815
|
+
expect(message.data.unpack('H*').first).to eql(encoding_spec['expectedHexValue'])
|
816
|
+
else
|
817
|
+
expect(message.data).to eql(encoding_spec['expectedValue'])
|
818
|
+
end
|
819
|
+
stop_reactor
|
820
|
+
end
|
821
|
+
|
822
|
+
raw_message = { "data" => encoding_spec['data'], "encoding" => encoding_spec['encoding'] }
|
823
|
+
rest_publish_client.post("/channels/#{channel_name}/messages", JSON.dump(raw_message))
|
824
|
+
end
|
825
|
+
end
|
826
|
+
end
|
827
|
+
|
828
|
+
context "when retrieving a #{encoding_spec['expectedType']} using JSON protocol" do
|
829
|
+
let(:rest_publish_client) do
|
830
|
+
Ably::Rest::Client.new(client_options.merge(protocol: :msgpack))
|
831
|
+
end
|
832
|
+
let(:rest_retrieve_client) do
|
833
|
+
Ably::Rest::Client.new(client_options.merge(protocol: :json))
|
834
|
+
end
|
835
|
+
let(:rest_publish_channel) { rest_publish_client.channels.get(channel_name) }
|
836
|
+
|
837
|
+
it 'is compatible with a publishes using MsgPack' do
|
838
|
+
expect(rest_publish_client).to be_protocol_binary
|
839
|
+
|
840
|
+
data = if encoding_spec['expectedHexValue']
|
841
|
+
encoding_spec['expectedHexValue'].scan(/../).map { |x| x.hex }.pack('c*')
|
842
|
+
else
|
843
|
+
encoding_spec['expectedValue']
|
844
|
+
end
|
845
|
+
rest_publish_channel.publish "event", data
|
846
|
+
|
847
|
+
response = rest_retrieve_client.get("/channels/#{channel_name}/messages")
|
848
|
+
message = response.body[0]
|
849
|
+
expect(message['encoding']).to eql(encoding_spec['encoding'])
|
850
|
+
expect(encoding_spec['data']).to eql(message['data'])
|
851
|
+
stop_reactor
|
852
|
+
end
|
853
|
+
end
|
854
|
+
end
|
855
|
+
end
|
856
|
+
end
|
735
857
|
end
|