ably-rest 0.8.5 → 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/SPEC.md +1380 -631
  4. data/ably-rest.gemspec +11 -5
  5. data/lib/submodules/ably-ruby/.travis.yml +1 -1
  6. data/lib/submodules/ably-ruby/CHANGELOG.md +42 -48
  7. data/lib/submodules/ably-ruby/ably.gemspec +7 -1
  8. data/lib/submodules/ably-ruby/lib/ably.rb +2 -0
  9. data/lib/submodules/ably-ruby/lib/ably/auth.rb +155 -47
  10. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +2 -0
  11. data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +2 -3
  12. data/lib/submodules/ably-ruby/lib/ably/models/connection_details.rb +54 -0
  13. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +14 -4
  14. data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +13 -7
  15. data/lib/submodules/ably-ruby/lib/ably/models/token_request.rb +1 -2
  16. data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +3 -2
  17. data/lib/submodules/ably-ruby/lib/ably/modules/message_emitter.rb +1 -3
  18. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +2 -2
  19. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +6 -0
  20. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +15 -4
  21. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +2 -0
  22. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +10 -3
  23. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +11 -1
  24. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +62 -6
  25. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +58 -54
  26. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +18 -5
  27. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +9 -1
  28. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +32 -14
  29. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -1
  30. data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
  31. data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +251 -11
  32. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +12 -2
  33. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +316 -24
  34. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +93 -1
  35. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +177 -86
  36. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +284 -60
  37. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +45 -6
  38. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +4 -0
  39. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +181 -49
  40. data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +13 -0
  41. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +222 -4
  42. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +132 -1
  43. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +129 -28
  44. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +7 -7
  45. data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +10 -0
  46. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +41 -17
  47. data/lib/submodules/ably-ruby/spec/spec_helper.rb +1 -0
  48. data/lib/submodules/ably-ruby/spec/support/debug_failure_helper.rb +16 -0
  49. data/lib/submodules/ably-ruby/spec/unit/models/connection_details_spec.rb +60 -0
  50. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +45 -0
  51. data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +3 -1
  52. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +6 -5
  53. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +5 -1
  54. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +5 -1
  55. data/lib/submodules/ably-ruby/spec/unit/realtime/realtime_spec.rb +5 -1
  56. metadata +57 -13
@@ -1,3 +1,3 @@
1
1
  module Ably
2
- VERSION = '0.8.5'
2
+ VERSION = '0.8.6'
3
3
  end
@@ -70,15 +70,6 @@ describe Ably::Realtime::Auth, :event_machine do
70
70
  end
71
71
  end
72
72
 
73
- context '#token' do
74
- let(:client_options) { default_options.merge(token: random_str) }
75
-
76
- it 'contains the current token after auth' do
77
- expect(auth.token).to_not be_nil
78
- stop_reactor
79
- end
80
- end
81
-
82
73
  context '#current_token_details' do
83
74
  it 'contains the current token after auth' do
84
75
  expect(auth.current_token_details).to be_nil
@@ -99,6 +90,7 @@ describe Ably::Realtime::Auth, :event_machine do
99
90
  context '#options (auth_options)' do
100
91
  let(:auth_url) { "https://echo.ably.io/?type=text" }
101
92
  let(:auth_params) { { :body => random_str } }
93
+ let(:client_options) { default_options.merge(auto_connect: false) }
102
94
 
103
95
  it 'contains the configured auth options' do
104
96
  auth.authorise({}, auth_url: auth_url, auth_params: auth_params) do
@@ -193,6 +185,75 @@ describe Ably::Realtime::Auth, :event_machine do
193
185
  stop_reactor
194
186
  end
195
187
  end
188
+
189
+ context 'when implicitly called, with an explicit ClientOptions client_id' do
190
+ let(:client_id) { random_str }
191
+ let(:client_options) { default_options.merge(auth_callback: Proc.new { auth_token_object }, client_id: client_id, log_level: :none) }
192
+ let(:rest_auth_client) { Ably::Rest::Client.new(default_options.merge(key: api_key, client_id: 'invalid')) }
193
+
194
+ context 'and an incompatible client_id in a TokenDetails object passed to the auth callback' do
195
+ let(:auth_token_object) { rest_auth_client.auth.request_token }
196
+
197
+ it 'rejects a TokenDetails object with an incompatible client_id and raises an exception' do
198
+ client.connect
199
+ client.connection.on(:error) do |error|
200
+ expect(error).to be_a(Ably::Exceptions::IncompatibleClientId)
201
+ EventMachine.add_timer(0.1) do
202
+ expect(client.connection).to be_failed
203
+ stop_reactor
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ context 'and an incompatible client_id in a TokenRequest object passed to the auth callback and raises an exception' do
210
+ let(:auth_token_object) { rest_auth_client.auth.create_token_request }
211
+
212
+ it 'rejects a TokenRequests object with an incompatible client_id and raises an exception' do
213
+ client.connect
214
+ client.connection.on(:error) do |error|
215
+ expect(error).to be_a(Ably::Exceptions::IncompatibleClientId)
216
+ EventMachine.add_timer(0.1) do
217
+ expect(client.connection).to be_failed
218
+ stop_reactor
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ context 'when explicitly called, with an explicit ClientOptions client_id' do
226
+ let(:auth_proc) do
227
+ Proc.new do
228
+ if !@requested
229
+ @requested = true
230
+ valid_auth_token
231
+ else
232
+ invalid_auth_token
233
+ end
234
+ end
235
+ end
236
+
237
+ let(:client_id) { random_str }
238
+ let(:client_options) { default_options.merge(auth_callback: auth_proc, client_id: client_id, log_level: :none) }
239
+ let(:valid_auth_token) { Ably::Rest::Client.new(default_options.merge(key: api_key, client_id: client_id)).auth.request_token }
240
+ let(:invalid_auth_token) { Ably::Rest::Client.new(default_options.merge(key: api_key, client_id: 'invalid')).auth.request_token }
241
+
242
+ context 'and an incompatible client_id in a TokenDetails object passed to the auth callback' do
243
+ it 'rejects a TokenDetails object with an incompatible client_id and raises an exception' do
244
+ client.connection.once(:connected) do
245
+ client.auth.authorise({}, force: true)
246
+ client.connection.on(:error) do |error|
247
+ expect(error).to be_a(Ably::Exceptions::IncompatibleClientId)
248
+ EventMachine.add_timer(0.1) do
249
+ expect(client.connection).to be_failed
250
+ stop_reactor
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
196
257
  end
197
258
 
198
259
  context '#authorise_async' do
@@ -216,7 +277,7 @@ describe Ably::Realtime::Auth, :event_machine do
216
277
  end
217
278
  end
218
279
 
219
- context '#auth_params' do
280
+ context '#auth_params_sync' do
220
281
  it 'returns the auth params synchronously' do
221
282
  expect(auth.auth_params_sync).to be_a(Hash)
222
283
  stop_reactor
@@ -232,11 +293,190 @@ describe Ably::Realtime::Auth, :event_machine do
232
293
  end
233
294
  end
234
295
 
235
- context '#auth_header' do
296
+ context '#auth_header_sync' do
236
297
  it 'returns an auth header synchronously' do
237
298
  expect(auth.auth_header_sync).to be_a(String)
238
299
  stop_reactor
239
300
  end
240
301
  end
302
+
303
+ describe '#client_id_validated?' do
304
+ let(:auth) { Ably::Rest::Client.new(default_options.merge(key: api_key)).auth }
305
+
306
+ context 'when using basic auth' do
307
+ let(:client_options) { default_options.merge(key: api_key) }
308
+
309
+ context 'before connected' do
310
+ it 'is false as basic auth users do not have an identity' do
311
+ expect(client.auth).to_not be_client_id_validated
312
+ stop_reactor
313
+ end
314
+ end
315
+
316
+ context 'once connected' do
317
+ it 'is true' do
318
+ client.connection.once(:connected) do
319
+ expect(client.auth).to be_client_id_validated
320
+ stop_reactor
321
+ end
322
+ end
323
+
324
+ it 'contains a validated wildcard client_id' do
325
+ client.connection.once(:connected) do
326
+ expect(client.auth.client_id).to eql('*')
327
+ stop_reactor
328
+ end
329
+ end
330
+ end
331
+ end
332
+
333
+ context 'when using a token string' do
334
+ context 'with a valid client_id' do
335
+ let(:client_options) { default_options.merge(token: auth.request_token(client_id: 'present').token) }
336
+
337
+ context 'before connected' do
338
+ it 'is false as identification is not possible from an opaque token string' do
339
+ expect(client.auth).to_not be_client_id_validated
340
+ stop_reactor
341
+ end
342
+
343
+ specify '#client_id is nil' do
344
+ expect(client.auth.client_id).to be_nil
345
+ stop_reactor
346
+ end
347
+ end
348
+
349
+ context 'once connected' do
350
+ it 'is true' do
351
+ client.connection.once(:connected) do
352
+ expect(client.auth).to be_client_id_validated
353
+ stop_reactor
354
+ end
355
+ end
356
+
357
+ specify '#client_id is populated' do
358
+ client.connection.once(:connected) do
359
+ expect(client.auth.client_id).to eql('present')
360
+ stop_reactor
361
+ end
362
+ end
363
+ end
364
+ end
365
+
366
+ context 'with no client_id (anonymous)' do
367
+ let(:client_options) { default_options.merge(token: auth.request_token(client_id: nil).token) }
368
+
369
+ context 'before connected' do
370
+ it 'is false as identification is not possible from an opaque token string' do
371
+ expect(client.auth).to_not be_client_id_validated
372
+ stop_reactor
373
+ end
374
+ end
375
+
376
+ context 'once connected' do
377
+ it 'is true' do
378
+ client.connection.once(:connected) do
379
+ expect(client.auth).to be_client_id_validated
380
+ stop_reactor
381
+ end
382
+ end
383
+ end
384
+ end
385
+
386
+ context 'with a wildcard client_id (anonymous)' do
387
+ let(:client_options) { default_options.merge(token: auth.request_token(client_id: '*').token) }
388
+
389
+ context 'before connected' do
390
+ it 'is false as identification is not possible from an opaque token string' do
391
+ expect(client.auth).to_not be_client_id_validated
392
+ stop_reactor
393
+ end
394
+ end
395
+
396
+ context 'once connected' do
397
+ it 'is true' do
398
+ client.connection.once(:connected) do
399
+ expect(client.auth).to be_client_id_validated
400
+ stop_reactor
401
+ end
402
+ end
403
+ end
404
+ end
405
+ end
406
+
407
+ context 'when using a token' do
408
+ context 'with a client_id' do
409
+ let(:client_options) { default_options.merge(token: auth.request_token(client_id: 'present')) }
410
+
411
+ it 'is true' do
412
+ expect(client.auth).to be_client_id_validated
413
+ stop_reactor
414
+ end
415
+
416
+ context 'once connected' do
417
+ it 'is true' do
418
+ client.connection.once(:connected) do
419
+ expect(client.auth).to be_client_id_validated
420
+ stop_reactor
421
+ end
422
+ end
423
+ end
424
+ end
425
+
426
+ context 'with no client_id (anonymous)' do
427
+ let(:client_options) { default_options.merge(token: auth.request_token(client_id: nil)) }
428
+
429
+ it 'is true' do
430
+ expect(client.auth).to be_client_id_validated
431
+ stop_reactor
432
+ end
433
+
434
+ context 'once connected' do
435
+ it 'is true' do
436
+ client.connection.once(:connected) do
437
+ expect(client.auth).to be_client_id_validated
438
+ stop_reactor
439
+ end
440
+ end
441
+ end
442
+ end
443
+
444
+ context 'with a wildcard client_id (anonymous)' do
445
+ let(:client_options) { default_options.merge(token: auth.request_token(client_id: '*')) }
446
+
447
+ it 'is true' do
448
+ expect(client.auth).to be_client_id_validated
449
+ stop_reactor
450
+ end
451
+
452
+ context 'once connected' do
453
+ it 'is true' do
454
+ client.connection.once(:connected) do
455
+ expect(client.auth).to be_client_id_validated
456
+ stop_reactor
457
+ end
458
+ end
459
+ end
460
+ end
461
+ end
462
+
463
+ context 'when using a token request with a client_id' do
464
+ let(:client_options) { default_options.merge(token: auth.create_token_request(client_id: 'present')) }
465
+
466
+ it 'is not true as identification is not confirmed until authenticated' do
467
+ expect(client.auth).to_not be_client_id_validated
468
+ stop_reactor
469
+ end
470
+
471
+ context 'once connected' do
472
+ it 'is true as identification is completed following CONNECTED ProtocolMessage' do
473
+ client.channel('test').publish('a') do
474
+ expect(client.auth).to be_client_id_validated
475
+ stop_reactor
476
+ end
477
+ end
478
+ end
479
+ end
480
+ end
241
481
  end
242
482
  end
@@ -186,9 +186,19 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
186
186
  messages.next do |next_page_messages|
187
187
  expect(next_page_messages.items.count).to eql(5)
188
188
  expect(next_page_messages.items.map(&:data).uniq.first).to eql(message_before_attach)
189
- expect(next_page_messages).to be_last
190
189
 
191
- stop_reactor
190
+ if next_page_messages.last?
191
+ expect(next_page_messages).to be_last
192
+ stop_reactor
193
+ else
194
+ # If previous page said there is another page it is plausible and correct that
195
+ # the next page is empty and then the last, if the limit was satisfied
196
+ next_page_messages.next do |empty_page|
197
+ expect(empty_page.items.count).to eql(0)
198
+ expect(empty_page).to be_last
199
+ stop_reactor
200
+ end
201
+ end
192
202
  end
193
203
  end
194
204
  end
@@ -504,55 +504,143 @@ describe Ably::Realtime::Channel, :event_machine do
504
504
  end
505
505
  end
506
506
 
507
+ context 'nil attributes' do
508
+ context 'when name is nil' do
509
+ let(:data) { random_str }
510
+
511
+ it 'publishes the message without a name attribute in the payload' do
512
+ published = false
513
+ channel.publish(nil, data) do
514
+ published = true
515
+ end
516
+
517
+ channel.subscribe do |message|
518
+ expect(message.name).to be_nil
519
+ channel.history do |page|
520
+ expect(page.items.first.name).to be_nil
521
+ expect(page.items.first.data).to eql(data)
522
+ EM.add_timer(0.5) do
523
+ expect(published).to eql(true)
524
+ stop_reactor
525
+ end
526
+ end
527
+ end
528
+ end
529
+ end
530
+
531
+ context 'when data is nil' do
532
+ let(:name) { random_str }
533
+
534
+ it 'publishes the message without a data attribute in the payload' do
535
+ published = false
536
+ channel.publish(name, nil) do
537
+ published = true
538
+ end
539
+
540
+ channel.subscribe do |message|
541
+ expect(message.data).to be_nil
542
+ channel.history do |page|
543
+ expect(page.items.first.name).to eql(name)
544
+ expect(page.items.first.data).to be_nil
545
+ EM.add_timer(0.5) do
546
+ expect(published).to eql(true)
547
+ stop_reactor
548
+ end
549
+ end
550
+ end
551
+ end
552
+ end
553
+
554
+ context 'with neither name or data attributes' do
555
+ let(:name) { random_str }
556
+
557
+ it 'publishes the message without any attributes in the payload' do
558
+ channel.publish(nil) do
559
+ channel.history do |page|
560
+ expect(page.items.first.name).to be_nil
561
+ expect(page.items.first.data).to be_nil
562
+ stop_reactor
563
+ end
564
+ end
565
+ end
566
+ end
567
+ end
568
+
507
569
  context 'with two invalid message out of 12' do
508
- let(:client_options) { default_options.merge(client_id: 'valid') }
570
+ let(:rest_client) { Ably::Rest::Client.new(default_options.merge(client_id: 'valid')) }
571
+
509
572
  let(:invalid_messages) do
510
573
  2.times.map do |index|
511
574
  Ably::Models::Message(name: index.to_s, data: { "index" => index + 10 }, client_id: 'prohibited')
512
575
  end
513
576
  end
514
577
 
515
- it 'calls the errback once' do
516
- skip 'Waiting for issue #256 to be resolved'
517
- channel.publish(messages + invalid_messages).tap do |deferrable|
518
- deferrable.callback do
519
- raise 'Publish should have failed'
520
- end
578
+ context 'before client_id is known (validated)' do
579
+ let(:client_options) { default_options.merge(token: rest_client.auth.request_token.token, log_level: :error) }
521
580
 
522
- deferrable.errback do |error, message|
523
- # TODO: Review whether we should fail once or multiple times
524
- channel.history do |page|
525
- expect(page.items.count).to eql(0)
526
- stop_reactor
581
+ it 'calls the errback once' do
582
+ channel.publish(messages + invalid_messages).tap do |deferrable|
583
+ deferrable.callback do
584
+ raise 'Publish should have failed'
585
+ end
586
+
587
+ deferrable.errback do |error, message|
588
+ # TODO: Review whether we should fail once or multiple times
589
+ channel.history do |page|
590
+ expect(page.items.count).to eql(0)
591
+ stop_reactor
592
+ end
527
593
  end
528
594
  end
529
595
  end
530
596
  end
597
+
598
+ context 'when client_id is known (validated)' do
599
+ let(:client_options) { default_options.merge(client_id: 'valid') }
600
+
601
+ it 'raises an exception' do
602
+ expect { channel.publish(messages + invalid_messages) }.to raise_error Ably::Exceptions::IncompatibleClientId
603
+ stop_reactor
604
+ end
605
+ end
531
606
  end
532
607
 
533
608
  context 'only invalid messages' do
534
- let(:client_options) { default_options.merge(client_id: 'valid') }
609
+ let(:rest_client) { Ably::Rest::Client.new(default_options.merge(client_id: 'valid')) }
610
+
535
611
  let(:invalid_messages) do
536
612
  10.times.map do |index|
537
613
  Ably::Models::Message(name: index.to_s, data: { "index" => index + 10 }, client_id: 'prohibited')
538
614
  end
539
615
  end
540
616
 
541
- it 'calls the errback once' do
542
- skip 'Waiting for issue #256 to be resolved'
543
- channel.publish(invalid_messages).tap do |deferrable|
544
- deferrable.callback do
545
- raise 'Publish should have failed'
546
- end
617
+ context 'before client_id is known (validated)' do
618
+ let(:client_options) { default_options.merge(token: rest_client.auth.request_token.token, log_level: :error) }
547
619
 
548
- deferrable.errback do |error, message|
549
- channel.history do |page|
550
- expect(page.items.count).to eql(0)
551
- stop_reactor
620
+ it 'calls the errback once' do
621
+ channel.publish(invalid_messages).tap do |deferrable|
622
+ deferrable.callback do
623
+ raise 'Publish should have failed'
624
+ end
625
+
626
+ deferrable.errback do |error, message|
627
+ channel.history do |page|
628
+ expect(page.items.count).to eql(0)
629
+ stop_reactor
630
+ end
552
631
  end
553
632
  end
554
633
  end
555
634
  end
635
+
636
+ context 'when client_id is known (validated)' do
637
+ let(:client_options) { default_options.merge(client_id: 'valid') }
638
+
639
+ it 'raises an exception' do
640
+ expect { channel.publish(invalid_messages) }.to raise_error Ably::Exceptions::IncompatibleClientId
641
+ stop_reactor
642
+ end
643
+ end
556
644
  end
557
645
  end
558
646
 
@@ -581,6 +669,208 @@ describe Ably::Realtime::Channel, :event_machine do
581
669
  end
582
670
  end
583
671
  end
672
+
673
+ context 'identified clients' do
674
+ context 'when authenticated with a wildcard client_id' do
675
+ let(:token) { Ably::Rest::Client.new(default_options).auth.request_token(client_id: '*') }
676
+ let(:client_options) { default_options.merge(key: nil, token: token) }
677
+ let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
678
+ let(:channel) { client.channels.get(channel_name) }
679
+
680
+ context 'with a valid client_id in the message' do
681
+ it 'succeeds' do
682
+ channel.publish([name: 'event', client_id: 'validClient']).tap do |deferrable|
683
+ deferrable.errback { raise 'Should have succeeded' }
684
+ end
685
+ channel.subscribe('event') do |message|
686
+ expect(message.client_id).to eql('validClient')
687
+ EM.add_timer(0.5) { stop_reactor }
688
+ end
689
+ end
690
+ end
691
+
692
+ context 'with a wildcard client_id in the message' do
693
+ it 'throws an exception' do
694
+ expect { channel.publish([name: 'event', client_id: '*']) }.to raise_error Ably::Exceptions::IncompatibleClientId
695
+ stop_reactor
696
+ end
697
+ end
698
+
699
+ context 'with an empty client_id in the message' do
700
+ it 'succeeds and publishes without a client_id' do
701
+ channel.publish([name: 'event', client_id: nil]).tap do |deferrable|
702
+ deferrable.errback { raise 'Should have succeeded' }
703
+ end
704
+ channel.subscribe('event') do |message|
705
+ expect(message.client_id).to be_nil
706
+ EM.add_timer(0.5) { stop_reactor }
707
+ end
708
+ end
709
+ end
710
+ end
711
+
712
+ context 'when authenticated with a Token string with an implicit client_id' do
713
+ let(:token) { Ably::Rest::Client.new(default_options).auth.request_token(client_id: 'valid').token }
714
+ let(:client_options) { default_options.merge(key: nil, token: token) }
715
+ let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
716
+ let(:channel) { client.channels.get(channel_name) }
717
+
718
+ context 'before the client is CONNECTED and the client\'s identity has been obtained' do
719
+ context 'with a valid client_id in the message' do
720
+ it 'succeeds' do
721
+ channel.publish([name: 'event', client_id: 'valid']).tap do |deferrable|
722
+ deferrable.errback { raise 'Should have succeeded' }
723
+ end
724
+ channel.subscribe('event') do |message|
725
+ expect(message.client_id).to eql('valid')
726
+ EM.add_timer(0.5) { stop_reactor }
727
+ end
728
+ end
729
+ end
730
+
731
+ context 'with an invalid client_id in the message' do
732
+ let(:client_options) { default_options.merge(key: nil, token: token, log_level: :error) }
733
+ it 'succeeds in the client library but then fails when delivered to Ably' do
734
+ channel.publish([name: 'event', client_id: 'invalid']).tap do |deferrable|
735
+ EM.add_timer(0.5) { stop_reactor }
736
+ end
737
+ channel.subscribe('event') do |message|
738
+ raise 'Message should not have been published'
739
+ end
740
+ end
741
+ end
742
+
743
+ context 'with an empty client_id in the message' do
744
+ it 'succeeds and publishes with an implicit client_id' do
745
+ channel.publish([name: 'event', client_id: nil]).tap do |deferrable|
746
+ deferrable.errback { raise 'Should have succeeded' }
747
+ end
748
+ channel.subscribe('event') do |message|
749
+ expect(message.client_id).to eql('valid')
750
+ EM.add_timer(0.5) { stop_reactor }
751
+ end
752
+ end
753
+ end
754
+ end
755
+
756
+ context 'after the client is CONNECTED and the client\'s identity is known' do
757
+ context 'with a valid client_id in the message' do
758
+ it 'succeeds' do
759
+ client.connection.once(:connected) do
760
+ channel.publish([name: 'event', client_id: 'valid']).tap do |deferrable|
761
+ deferrable.errback { raise 'Should have succeeded' }
762
+ end
763
+ channel.subscribe('event') do |message|
764
+ expect(message.client_id).to eql('valid')
765
+ EM.add_timer(0.5) { stop_reactor }
766
+ end
767
+ end
768
+ end
769
+ end
770
+
771
+ context 'with an invalid client_id in the message' do
772
+ it 'throws an exception' do
773
+ client.connection.once(:connected) do
774
+ expect { channel.publish([name: 'event', client_id: 'invalid']) }.to raise_error Ably::Exceptions::IncompatibleClientId
775
+ stop_reactor
776
+ end
777
+ end
778
+ end
779
+
780
+ context 'with an empty client_id in the message' do
781
+ it 'succeeds and publishes with an implicit client_id' do
782
+ client.connection.once(:connected) do
783
+ channel.publish([name: 'event', client_id: nil]).tap do |deferrable|
784
+ deferrable.errback { raise 'Should have succeeded' }
785
+ end
786
+ channel.subscribe('event') do |message|
787
+ expect(message.client_id).to eql('valid')
788
+ EM.add_timer(0.5) { stop_reactor }
789
+ end
790
+ end
791
+ end
792
+ end
793
+ end
794
+ end
795
+
796
+ context 'when authenticated with a valid client_id' do
797
+ let(:token) { Ably::Rest::Client.new(default_options).auth.request_token(client_id: 'valid') }
798
+ let(:client_options) { default_options.merge(key: nil, token: token) }
799
+ let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
800
+ let(:channel) { client.channels.get(channel_name) }
801
+
802
+ context 'with a valid client_id' do
803
+ it 'succeeds' do
804
+ channel.publish([name: 'event', client_id: 'valid']).tap do |deferrable|
805
+ deferrable.errback { raise 'Should have succeeded' }
806
+ end
807
+ channel.subscribe('event') do |message|
808
+ expect(message.client_id).to eql('valid')
809
+ EM.add_timer(0.5) { stop_reactor }
810
+ end
811
+ end
812
+ end
813
+
814
+ context 'with a wildcard client_id in the message' do
815
+ it 'throws an exception' do
816
+ expect { channel.publish([name: 'event', client_id: '*']) }.to raise_error Ably::Exceptions::IncompatibleClientId
817
+ stop_reactor
818
+ end
819
+ end
820
+
821
+ context 'with an invalid client_id in the message' do
822
+ it 'throws an exception' do
823
+ expect { channel.publish([name: 'event', client_id: 'invalid']) }.to raise_error Ably::Exceptions::IncompatibleClientId
824
+ stop_reactor
825
+ end
826
+ end
827
+
828
+ context 'with an empty client_id in the message' do
829
+ it 'succeeds and publishes with an implicit client_id' do
830
+ channel.publish([name: 'event', client_id: nil]).tap do |deferrable|
831
+ deferrable.errback { raise 'Should have succeeded' }
832
+ end
833
+ channel.subscribe('event') do |message|
834
+ expect(message.client_id).to eql('valid')
835
+ EM.add_timer(0.5) { stop_reactor }
836
+ end
837
+ end
838
+ end
839
+ end
840
+
841
+ context 'when anonymous and no client_id' do
842
+ let(:token) { Ably::Rest::Client.new(default_options).auth.request_token(client_id: nil) }
843
+ let(:client_options) { default_options.merge(key: nil, token: token) }
844
+ let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
845
+ let(:channel) { client.channels.get(channel_name) }
846
+
847
+ context 'with a client_id in the message' do
848
+ it 'throws an exception' do
849
+ expect { channel.publish([name: 'event', client_id: 'invalid']) }.to raise_error Ably::Exceptions::IncompatibleClientId
850
+ stop_reactor
851
+ end
852
+ end
853
+
854
+ context 'with a wildcard client_id in the message' do
855
+ it 'throws an exception' do
856
+ expect { channel.publish([name: 'event', client_id: '*']) }.to raise_error Ably::Exceptions::IncompatibleClientId
857
+ stop_reactor
858
+ end
859
+ end
860
+
861
+ context 'with an empty client_id in the message' do
862
+ it 'succeeds and publishes with an implicit client_id' do
863
+ channel.publish([name: 'event', client_id: nil]).tap do |deferrable|
864
+ deferrable.errback { raise 'Should have succeeded' }
865
+ end
866
+ channel.subscribe('event') do |message|
867
+ expect(message.client_id).to be_nil
868
+ EM.add_timer(0.5) { stop_reactor }
869
+ end
870
+ end
871
+ end
872
+ end
873
+ end
584
874
  end
585
875
 
586
876
  describe '#subscribe' do
@@ -881,7 +1171,7 @@ describe Ably::Realtime::Channel, :event_machine do
881
1171
 
882
1172
  context 'a :failed channel' do
883
1173
  let(:original_error) { RuntimeError.new }
884
- let(:client_options) { default_options.merge(log_level: :fatal) }
1174
+ let(:client_options) { default_options.merge(log_level: :fatal) }
885
1175
 
886
1176
  it 'remains in the :failed state and retains the error_reason' do
887
1177
  channel.attach do
@@ -904,6 +1194,8 @@ describe Ably::Realtime::Channel, :event_machine do
904
1194
  end
905
1195
 
906
1196
  context 'a channel ATTACH request when connection SUSPENDED' do
1197
+ let(:client_options) { default_options.merge(log_level: :fatal) }
1198
+
907
1199
  it 'raises an exception' do
908
1200
  client.connect do
909
1201
  client.connection.once(:suspended) do