ably-rest 1.0.5 → 1.1.3

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.
Files changed (118) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +6 -3
  3. data/CHANGELOG.md +1 -1
  4. data/LICENSE +1 -1
  5. data/README.md +26 -7
  6. data/SPEC.md +2003 -1605
  7. data/ably-rest.gemspec +4 -2
  8. data/lib/submodules/ably-ruby/.editorconfig +14 -0
  9. data/lib/submodules/ably-ruby/.travis.yml +10 -8
  10. data/lib/submodules/ably-ruby/CHANGELOG.md +97 -1
  11. data/lib/submodules/ably-ruby/LICENSE +1 -3
  12. data/lib/submodules/ably-ruby/README.md +12 -7
  13. data/lib/submodules/ably-ruby/Rakefile +32 -0
  14. data/lib/submodules/ably-ruby/SPEC.md +1277 -835
  15. data/lib/submodules/ably-ruby/ably.gemspec +17 -11
  16. data/lib/submodules/ably-ruby/lib/ably/auth.rb +34 -8
  17. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +10 -4
  18. data/lib/submodules/ably-ruby/lib/ably/logger.rb +8 -2
  19. data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +1 -1
  20. data/lib/submodules/ably-ruby/lib/ably/models/connection_state_change.rb +1 -1
  21. data/lib/submodules/ably-ruby/lib/ably/models/device_details.rb +87 -0
  22. data/lib/submodules/ably-ruby/lib/ably/models/device_push_details.rb +86 -0
  23. data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +23 -2
  24. data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +12 -12
  25. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +6 -4
  26. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +6 -4
  27. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +32 -2
  28. data/lib/submodules/ably-ruby/lib/ably/models/push_channel_subscription.rb +89 -0
  29. data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +2 -2
  30. data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +2 -2
  31. data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +2 -2
  32. data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +2 -2
  33. data/lib/submodules/ably-ruby/lib/ably/modules/exception_codes.rb +128 -0
  34. data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +15 -2
  35. data/lib/submodules/ably-ruby/lib/ably/modules/safe_deferrable.rb +1 -1
  36. data/lib/submodules/ably-ruby/lib/ably/modules/safe_yield.rb +1 -1
  37. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +5 -5
  38. data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +2 -2
  39. data/lib/submodules/ably-ruby/lib/ably/realtime.rb +1 -0
  40. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +2 -2
  41. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +27 -105
  42. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +4 -8
  43. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +2 -2
  44. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/publisher.rb +74 -0
  45. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/push_channel.rb +62 -0
  46. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +91 -3
  47. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +9 -4
  48. data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
  49. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +45 -26
  50. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +25 -9
  51. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +2 -2
  52. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +7 -7
  53. data/lib/submodules/ably-ruby/lib/ably/realtime/presence/members_map.rb +9 -9
  54. data/lib/submodules/ably-ruby/lib/ably/realtime/push.rb +40 -0
  55. data/lib/submodules/ably-ruby/lib/ably/realtime/push/admin.rb +61 -0
  56. data/lib/submodules/ably-ruby/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
  57. data/lib/submodules/ably-ruby/lib/ably/realtime/push/device_registrations.rb +105 -0
  58. data/lib/submodules/ably-ruby/lib/ably/rest.rb +1 -0
  59. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +54 -18
  60. data/lib/submodules/ably-ruby/lib/ably/rest/channel/push_channel.rb +62 -0
  61. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +171 -41
  62. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +17 -1
  63. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +1 -0
  64. data/lib/submodules/ably-ruby/lib/ably/rest/push.rb +42 -0
  65. data/lib/submodules/ably-ruby/lib/ably/rest/push/admin.rb +54 -0
  66. data/lib/submodules/ably-ruby/lib/ably/rest/push/channel_subscriptions.rb +121 -0
  67. data/lib/submodules/ably-ruby/lib/ably/rest/push/device_registrations.rb +103 -0
  68. data/lib/submodules/ably-ruby/lib/ably/version.rb +7 -2
  69. data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +253 -49
  70. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +33 -21
  71. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +180 -62
  72. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +155 -2
  73. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +293 -13
  74. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +142 -39
  75. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +38 -36
  76. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +12 -3
  77. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +207 -173
  78. data/lib/submodules/ably-ruby/spec/acceptance/realtime/push_admin_spec.rb +736 -0
  79. data/lib/submodules/ably-ruby/spec/acceptance/realtime/push_spec.rb +27 -0
  80. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +62 -51
  81. data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +2 -2
  82. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +79 -4
  83. data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +6 -0
  84. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +318 -74
  85. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +158 -6
  86. data/lib/submodules/ably-ruby/spec/acceptance/rest/push_admin_spec.rb +952 -0
  87. data/lib/submodules/ably-ruby/spec/acceptance/rest/push_spec.rb +25 -0
  88. data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +1 -1
  89. data/lib/submodules/ably-ruby/spec/run_parallel_tests +33 -0
  90. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +1 -9
  91. data/lib/submodules/ably-ruby/spec/spec_helper.rb +3 -1
  92. data/lib/submodules/ably-ruby/spec/support/debug_failure_helper.rb +9 -5
  93. data/lib/submodules/ably-ruby/spec/support/event_emitter_helper.rb +31 -0
  94. data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +1 -1
  95. data/lib/submodules/ably-ruby/spec/support/test_app.rb +2 -2
  96. data/lib/submodules/ably-ruby/spec/support/test_logger_helper.rb +42 -0
  97. data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +11 -12
  98. data/lib/submodules/ably-ruby/spec/unit/models/device_details_spec.rb +102 -0
  99. data/lib/submodules/ably-ruby/spec/unit/models/device_push_details_spec.rb +101 -0
  100. data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +51 -3
  101. data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +17 -2
  102. data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +1 -1
  103. data/lib/submodules/ably-ruby/spec/unit/models/push_channel_subscription_spec.rb +86 -0
  104. data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +2 -2
  105. data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +1 -1
  106. data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +3 -3
  107. data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +10 -10
  108. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +1 -1
  109. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +13 -1
  110. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +2 -2
  111. data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +1 -1
  112. data/lib/submodules/ably-ruby/spec/unit/realtime/push_channel_spec.rb +36 -0
  113. data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +30 -1
  114. data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +30 -0
  115. data/lib/submodules/ably-ruby/spec/unit/rest/push_channel_spec.rb +36 -0
  116. data/lib/submodules/ably-ruby/spec/unit/util/pub_sub_spec.rb +3 -3
  117. data/spec/spec_helper.rb +1 -0
  118. metadata +51 -10
@@ -77,7 +77,13 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
77
77
  limit.times do |index|
78
78
  expect(next_page.items[index].data).to eql("history#{index + limit}")
79
79
  end
80
- expect(next_page).to be_last
80
+ if next_page.has_next?
81
+ next_page.next do |last|
82
+ expect(last.items.length).to eql(0)
83
+ end
84
+ else
85
+ expect(next_page).to be_last
86
+ end
81
87
 
82
88
  stop_reactor
83
89
  end
@@ -106,22 +112,26 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
106
112
 
107
113
  context 'in multiple ProtocolMessages', em_timeout: (30 / 10) + 5 do
108
114
  it 'retrieves limited history forwards with pagination' do
109
- messages_sent.times do |index|
110
- EventMachine.add_timer(index.to_f / rate_per_second) do
111
- channel.publish('event', "history#{index}") do
112
- next unless index == messages_sent - 1
113
- ensure_message_history_direction_and_paging_is_correct :forwards
115
+ channel.attach do
116
+ messages_sent.times do |index|
117
+ EventMachine.add_timer(index.to_f / rate_per_second) do
118
+ channel.publish('event', "history#{index}") do
119
+ next unless index == messages_sent - 1
120
+ ensure_message_history_direction_and_paging_is_correct :forwards
121
+ end
114
122
  end
115
123
  end
116
124
  end
117
125
  end
118
126
 
119
127
  it 'retrieves limited history backwards with pagination' do
120
- messages_sent.times.to_a.reverse.each do |index|
121
- EventMachine.add_timer((messages_sent - index).to_f / rate_per_second) do
122
- channel.publish('event', "history#{index}") do
123
- next unless index == 0
124
- ensure_message_history_direction_and_paging_is_correct :backwards if index == 0
128
+ channel.attach do
129
+ messages_sent.times.to_a.reverse.each do |index|
130
+ EventMachine.add_timer((messages_sent - index).to_f / rate_per_second) do
131
+ channel.publish('event', "history#{index}") do
132
+ next unless index == 0
133
+ ensure_message_history_direction_and_paging_is_correct :backwards if index == 0
134
+ end
125
135
  end
126
136
  end
127
137
  end
@@ -133,18 +143,20 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
133
143
  let(:messages_per_batch) { 10 }
134
144
 
135
145
  it 'return the same results with unique matching message IDs' do
136
- batches.times do |batch|
137
- EventMachine.add_timer(batch.to_f / batches.to_f) do
138
- messages_per_batch.times { channel.publish('event', 'data') }
146
+ channel.attach do
147
+ batches.times do |batch|
148
+ EventMachine.add_timer(batch.to_f / batches.to_f) do
149
+ messages_per_batch.times { |index| channel.publish('event') }
150
+ end
139
151
  end
140
- end
141
152
 
142
- channel.subscribe('event') do |message|
143
- messages << message
144
- if messages.count == batches * messages_per_batch
145
- channel.history do |page|
146
- expect(page.items.map(&:id).sort).to eql(messages.map(&:id).sort)
147
- stop_reactor
153
+ channel.subscribe('event') do |message|
154
+ messages << message
155
+ if messages.count == batches * messages_per_batch
156
+ channel.history do |page|
157
+ expect(page.items.map(&:id).sort).to eql(messages.map(&:id).sort)
158
+ stop_reactor
159
+ end
148
160
  end
149
161
  end
150
162
  end
@@ -13,6 +13,9 @@ describe Ably::Realtime::Channel, :event_machine do
13
13
  let(:channel) { client.channel(channel_name) }
14
14
  let(:messages) { [] }
15
15
 
16
+ let(:sub_client) { auto_close Ably::Realtime::Client.new(client_options) }
17
+ let(:sub_channel) { sub_client.channel(channel_name) }
18
+
16
19
  def disconnect_transport
17
20
  connection.transport.unbind
18
21
  end
@@ -276,8 +279,7 @@ describe Ably::Realtime::Channel, :event_machine do
276
279
  key: restricted_api_key,
277
280
  log_level: :fatal,
278
281
  use_token_auth: true,
279
- # TODO: Use wildcard / default when intersection issue resolved, realtime#780
280
- default_token_params: { capability: { "canpublish:foo" => ["publish"] } }
282
+ default_token_params: { capability: { "canpublish:foo" => ["*"] } }
281
283
  )
282
284
  end
283
285
  let(:restricted_client) do
@@ -726,7 +728,7 @@ describe Ably::Realtime::Channel, :event_machine do
726
728
  let(:name) { random_str }
727
729
  let(:data) { random_str }
728
730
 
729
- context 'when attached' do
731
+ context 'when channel is attached (#RTL6c1)' do
730
732
  it 'publishes messages' do
731
733
  channel.attach do
732
734
  3.times { channel.publish('event', payload) }
@@ -738,81 +740,173 @@ describe Ably::Realtime::Channel, :event_machine do
738
740
  end
739
741
  end
740
742
 
741
- context 'when not yet attached' do
742
- it 'publishes queued messages once attached' do
743
- 3.times { channel.publish('event', random_str) }
744
- channel.subscribe do |message|
745
- messages << message if message.name == 'event'
746
- stop_reactor if messages.count == 3
743
+ context 'when channel is not attached in state Initializing (#RTL6c1)' do
744
+ it 'publishes messages immediately and does not implicitly attach (#RTL6c1)' do
745
+ sub_channel.attach do
746
+ sub_channel.subscribe do |message|
747
+ messages << message if message.name == 'event'
748
+ if messages.count == 3
749
+ EventMachine.add_timer(1) do
750
+ expect(channel.state).to eq(:initialized)
751
+ stop_reactor
752
+ end
753
+ end
754
+ end
755
+ 3.times { channel.publish('event', random_str) }
747
756
  end
748
757
  end
758
+ end
749
759
 
750
- it 'publishes queued messages within a single protocol message' do
751
- 3.times { channel.publish('event', random_str) }
752
- channel.subscribe do |message|
753
- messages << message if message.name == 'event'
754
- next unless messages.length == 3
755
-
756
- # All 3 messages should be batched into a single Protocol Message by the client library
757
- # message.id = "{protocol_message.id}:{protocol_message_index}"
758
- # Check that all messages share the same protocol_message.id
759
- message_id = messages.map { |msg| msg.id.split(':')[0...-1].join(':') }
760
- expect(message_id.uniq.count).to eql(1)
761
-
762
- # Check that messages use index 0,1,2 in the ID
763
- message_indexes = messages.map { |msg| msg.id.split(':').last }
764
- expect(message_indexes).to include("0", "1", "2")
765
- stop_reactor
760
+ context 'when channel is Attaching (#RTL6c1)' do
761
+ it 'publishes messages immediately (#RTL6c1)' do
762
+ sub_channel.attach do
763
+ channel.once(:attaching) do
764
+ outgoing_message_count = 0
765
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
766
+ if protocol_message.action == :message
767
+ raise "Expected channel state to be attaching when publishing messages, not #{channel.state}" unless channel.attaching?
768
+ outgoing_message_count += protocol_message.messages.count
769
+ end
770
+ end
771
+ sub_channel.subscribe do |message|
772
+ messages << message if message.name == 'event'
773
+ if messages.count == 3
774
+ expect(outgoing_message_count).to eql(3)
775
+ stop_reactor
776
+ end
777
+ end
778
+ 3.times { channel.publish('event', random_str) }
779
+ end
780
+ channel.attach
766
781
  end
767
782
  end
783
+ end
768
784
 
769
- context 'with :queue_messages client option set to false' do
770
- let(:client_options) { default_options.merge(queue_messages: false) }
771
-
772
- context 'and connection state initialized' do
773
- it 'fails the deferrable' do
774
- expect(client.connection).to be_initialized
775
- channel.publish('event').errback do |error|
776
- expect(error).to be_a(Ably::Exceptions::MessageQueueingDisabled)
777
- stop_reactor
785
+ context 'when channel is Detaching (#RTL6c1)' do
786
+ it 'publishes messages immediately (#RTL6c1)' do
787
+ sub_channel.attach do
788
+ channel.attach do
789
+ channel.once(:detaching) do
790
+ outgoing_message_count = 0
791
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
792
+ if protocol_message.action == :message
793
+ raise "Expected channel state to be attaching when publishing messages, not #{channel.state}" unless channel.detaching?
794
+ outgoing_message_count += protocol_message.messages.count
795
+ end
796
+ end
797
+ sub_channel.subscribe do |message|
798
+ messages << message if message.name == 'event'
799
+ if messages.count == 3
800
+ expect(outgoing_message_count).to eql(3)
801
+ stop_reactor
802
+ end
803
+ end
804
+ 3.times { channel.publish('event', random_str) }
778
805
  end
806
+ channel.detach
779
807
  end
780
808
  end
809
+ end
810
+ end
781
811
 
782
- context 'and connection state connecting' do
783
- it 'fails the deferrable' do
784
- client.connect
785
- EventMachine.next_tick do
786
- expect(client.connection).to be_connecting
787
- channel.publish('event').errback do |error|
788
- expect(error).to be_a(Ably::Exceptions::MessageQueueingDisabled)
789
- stop_reactor
812
+ context 'when channel is Detached (#RTL6c1)' do
813
+ it 'publishes messages immediately (#RTL6c1)' do
814
+ sub_channel.attach do
815
+ channel.attach
816
+ channel.once(:attached) do
817
+ channel.once(:detached) do
818
+ outgoing_message_count = 0
819
+ client.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
820
+ if protocol_message.action == :message
821
+ raise "Expected channel state to be attaching when publishing messages, not #{channel.state}" unless channel.detached?
822
+ outgoing_message_count += protocol_message.messages.count
823
+ end
824
+ end
825
+ sub_channel.subscribe do |message|
826
+ messages << message if message.name == 'event'
827
+ if messages.count == 3
828
+ expect(outgoing_message_count).to eql(3)
829
+ stop_reactor
830
+ end
790
831
  end
832
+ 3.times { channel.publish('event', random_str) }
833
+ end
834
+ channel.detach
835
+ end
836
+ end
837
+ end
838
+ end
839
+
840
+ context 'with :queue_messages client option set to false (#RTL6c4)' do
841
+ let(:client_options) { default_options.merge(queue_messages: false) }
842
+
843
+ context 'and connection state connected (#RTL6c4)' do
844
+ it 'publishes the message' do
845
+ client.connection.once(:connected) do
846
+ channel.publish('event')
847
+ stop_reactor
848
+ end
849
+ end
850
+ end
851
+
852
+ context 'and connection state initialized (#RTL6c4)' do
853
+ it 'fails the deferrable' do
854
+ expect(client.connection).to be_initialized
855
+ channel.publish('event').errback do |error|
856
+ expect(error).to be_a(Ably::Exceptions::MessageQueueingDisabled)
857
+ stop_reactor
858
+ end
859
+ end
860
+ end
861
+
862
+ context 'and connection state connecting (#RTL6c4)' do
863
+ it 'fails the deferrable' do
864
+ client.connect
865
+ EventMachine.next_tick do
866
+ expect(client.connection).to be_connecting
867
+ channel.publish('event').errback do |error|
868
+ expect(error).to be_a(Ably::Exceptions::MessageQueueingDisabled)
869
+ stop_reactor
791
870
  end
792
871
  end
793
872
  end
873
+ end
794
874
 
795
- context 'and connection state disconnected' do
875
+ [:disconnected, :suspended, :closing, :closed].each do |invalid_connection_state|
876
+ context "and connection state #{invalid_connection_state} (#RTL6c4)" do
796
877
  let(:client_options) { default_options.merge(queue_messages: false) }
797
878
  it 'fails the deferrable' do
798
879
  client.connection.once(:connected) do
799
- client.connection.once(:disconnected) do
800
- expect(client.connection).to be_disconnected
880
+ client.connection.once(invalid_connection_state) do
881
+ expect(client.connection.state).to eq(invalid_connection_state)
801
882
  channel.publish('event').errback do |error|
802
883
  expect(error).to be_a(Ably::Exceptions::MessageQueueingDisabled)
803
884
  stop_reactor
804
885
  end
805
886
  end
806
- client.connection.transition_state_machine :disconnected
887
+ if invalid_connection_state == :closed
888
+ connection.close
889
+ else
890
+ client.connection.transition_state_machine invalid_connection_state
891
+ end
807
892
  end
808
893
  end
809
894
  end
895
+ end
810
896
 
811
- context 'and connection state connected' do
812
- it 'publishes the message' do
813
- client.connection.once(:connected) do
814
- channel.publish('event')
815
- stop_reactor
897
+ context 'and the channel state is failed (#RTL6c4)' do
898
+ let(:client_options) { default_options.merge(queue_messages: false) }
899
+ it 'fails the deferrable' do
900
+ client.connection.once(:connected) do
901
+ channel.attach
902
+ channel.once(:attached) do
903
+ channel.once(:failed) do
904
+ channel.publish('event').errback do |error|
905
+ expect(error).to be_a(Ably::Exceptions::ChannelInactive)
906
+ stop_reactor
907
+ end
908
+ end
909
+ channel.transition_state_machine(:failed)
816
910
  end
817
911
  end
818
912
  end
@@ -914,9 +1008,6 @@ describe Ably::Realtime::Channel, :event_machine do
914
1008
 
915
1009
  it 'publishes the message without a name attribute in the payload' do
916
1010
  published = false
917
- channel.publish(nil, data) do
918
- published = true
919
- end
920
1011
 
921
1012
  channel.subscribe do |message|
922
1013
  expect(message.name).to be_nil
@@ -929,6 +1020,10 @@ describe Ably::Realtime::Channel, :event_machine do
929
1020
  end
930
1021
  end
931
1022
  end
1023
+
1024
+ channel.publish(nil, data) do
1025
+ published = true
1026
+ end
932
1027
  end
933
1028
  end
934
1029
 
@@ -937,9 +1032,6 @@ describe Ably::Realtime::Channel, :event_machine do
937
1032
 
938
1033
  it 'publishes the message without a data attribute in the payload' do
939
1034
  published = false
940
- channel.publish(name, nil) do
941
- published = true
942
- end
943
1035
 
944
1036
  channel.subscribe do |message|
945
1037
  expect(message.data).to be_nil
@@ -952,6 +1044,10 @@ describe Ably::Realtime::Channel, :event_machine do
952
1044
  end
953
1045
  end
954
1046
  end
1047
+
1048
+ channel.publish(name, nil) do
1049
+ published = true
1050
+ end
955
1051
  end
956
1052
  end
957
1053
 
@@ -1074,6 +1170,21 @@ describe Ably::Realtime::Channel, :event_machine do
1074
1170
  end
1075
1171
  end
1076
1172
 
1173
+ context 'with more than allowed messages in a single publish' do
1174
+ let(:channel_name) { random_str }
1175
+
1176
+ it 'rejects the publish' do
1177
+ messages = (Ably::Realtime::Connection::MAX_PROTOCOL_MESSAGE_BATCH_SIZE + 1).times.map do
1178
+ { name: 'foo' }
1179
+ end
1180
+
1181
+ channel.publish(messages).errback do |error|
1182
+ expect(error).to be_kind_of(Ably::Exceptions::InvalidRequest)
1183
+ stop_reactor
1184
+ end
1185
+ end
1186
+ end
1187
+
1077
1188
  context 'identified clients' do
1078
1189
  context 'when authenticated with a wildcard client_id' do
1079
1190
  let(:token) { Ably::Rest::Client.new(default_options).auth.request_token(client_id: '*') }
@@ -1342,7 +1453,7 @@ describe Ably::Realtime::Channel, :event_machine do
1342
1453
 
1343
1454
  context 'many times with different event names' do
1344
1455
  it 'filters events accordingly to each callback' do
1345
- click_callback = proc { |message| messages << message }
1456
+ click_callback = lambda { |message| messages << message }
1346
1457
 
1347
1458
  channel.subscribe('click', &click_callback)
1348
1459
  channel.subscribe('move', &click_callback)
@@ -1887,6 +1998,8 @@ describe Ably::Realtime::Channel, :event_machine do
1887
1998
  end
1888
1999
 
1889
2000
  context '#resume (#RTL2f)' do
2001
+ let(:client_options) { default_options.merge(log_level: :fatal) }
2002
+
1890
2003
  it 'is false when a channel first attaches' do
1891
2004
  channel.attach
1892
2005
  channel.on(:attached) do |channel_state_change|
@@ -1953,12 +2066,16 @@ describe Ably::Realtime::Channel, :event_machine do
1953
2066
  end
1954
2067
 
1955
2068
  context 'moves to' do
1956
- %w(suspended detached failed).each do |channel_state|
2069
+ %w(suspended failed).each do |channel_state|
1957
2070
  context(channel_state) do
2071
+ let(:client) do
2072
+ auto_close Ably::Realtime::Client.new(default_options.merge(log_level: :error))
2073
+ end
2074
+
1958
2075
  specify 'all queued messages fail with NACK (#RTL11)' do
1959
2076
  channel.attach do
1960
2077
  # Move to disconnected
1961
- disconnect_transport_proc = Proc.new do
2078
+ disconnect_transport_proc = lambda do
1962
2079
  if connection.transport
1963
2080
  connection.transport.close_connection_after_writing
1964
2081
  else
@@ -1981,7 +2098,8 @@ describe Ably::Realtime::Channel, :event_machine do
1981
2098
  specify 'all published messages awaiting an ACK do nothing (#RTL11a)' do
1982
2099
  connection_been_disconnected = false
1983
2100
 
1984
- channel.attach do
2101
+ channel.attach
2102
+ channel.once(:attached) do
1985
2103
  deferrable = channel.publish("foo")
1986
2104
  deferrable.errback do |error|
1987
2105
  fail "Message publish should not fail"
@@ -2090,7 +2208,7 @@ describe Ably::Realtime::Channel, :event_machine do
2090
2208
  it 'will move to the SUSPENDED state and then attempt to ATTACH with the ATTACHING state (#RTL13b)' do
2091
2209
  connection.once(:connected) do
2092
2210
  # Prevent any incoming or outgoing ATTACH/ATTACHED message from Ably
2093
- prevent_protocol_messages_proc = Proc.new do
2211
+ prevent_protocol_messages_proc = lambda do
2094
2212
  if client.connection.transport
2095
2213
  client.connection.transport.__incoming_protocol_msgbus__.unsubscribe
2096
2214
  client.connection.transport.__outgoing_protocol_msgbus__.unsubscribe
@@ -12,6 +12,7 @@ describe Ably::Realtime::Client, :event_machine do
12
12
  let(:auth_params) { subject.auth.auth_params_sync }
13
13
 
14
14
  subject { auto_close Ably::Realtime::Client.new(client_options) }
15
+ let(:sub_client) { auto_close Ably::Realtime::Client.new(client_options) }
15
16
 
16
17
  context 'initialization' do
17
18
  context 'basic auth' do
@@ -24,6 +25,22 @@ describe Ably::Realtime::Client, :event_machine do
24
25
  end
25
26
  end
26
27
 
28
+ context 'with an invalid API key' do
29
+ let(:custom_logger_object) { TestLogger.new }
30
+ let(:client) { Ably::Realtime::Client.new(client_options.merge(key: 'app.key:secret', logger: custom_logger_object)) }
31
+
32
+ it 'logs an entry with a help href url matching the code #TI5' do
33
+ client.connect
34
+ client.connection.once(:failed) do
35
+ expect(custom_logger_object.logs.find do |severity, message|
36
+ next unless %w(fatal error).include?(severity.to_s)
37
+ message.match(%r{https://help.ably.io/error/40400})
38
+ end).to_not be_nil
39
+ stop_reactor
40
+ end
41
+ end
42
+ end
43
+
27
44
  context ':tls option' do
28
45
  context 'set to false to force a plain-text connection' do
29
46
  let(:client_options) { default_options.merge(tls: false, log_level: :none) }
@@ -134,7 +151,7 @@ describe Ably::Realtime::Client, :event_machine do
134
151
 
135
152
  context 'with a wildcard client_id token' do
136
153
  subject { auto_close Ably::Realtime::Client.new(client_options) }
137
- let(:client_options) { default_options.merge(auth_callback: Proc.new { auth_token_object }, client_id: client_id) }
154
+ let(:client_options) { default_options.merge(auth_callback: lambda { |token_params| auth_token_object }, client_id: client_id) }
138
155
  let(:rest_auth_client) { Ably::Rest::Client.new(default_options.merge(key: api_key)) }
139
156
  let(:auth_token_object) { rest_auth_client.auth.request_token(client_id: '*') }
140
157
 
@@ -155,7 +172,7 @@ describe Ably::Realtime::Client, :event_machine do
155
172
  end
156
173
 
157
174
  context 'and client_id omitted in ClientOptions' do
158
- let(:client_options) { default_options.merge(auth_callback: Proc.new { auth_token_object }) }
175
+ let(:client_options) { default_options.merge(auth_callback: lambda { |token_params| auth_token_object }) }
159
176
 
160
177
  it 'uses the token provided clientId in the connection' do
161
178
  connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
@@ -281,5 +298,141 @@ describe Ably::Realtime::Client, :event_machine do
281
298
  end
282
299
  end
283
300
  end
301
+
302
+ context '#publish (#TBC)' do
303
+ let(:channel_name) { random_str }
304
+ let(:channel) { subject.channel(channel_name) }
305
+ let(:sub_channel) { sub_client.channel(channel_name) }
306
+ let(:event_name) { random_str }
307
+ let(:data) { random_str }
308
+ let(:extras) { { 'push' => { 'notification' => { 'title' => 'Testing' } } } }
309
+ let(:message) { Ably::Models::Message.new(name: event_name, data: data) }
310
+
311
+ specify 'publishing a message implicity connects and publishes the message successfully on the provided channel' do
312
+ sub_channel.attach do
313
+ sub_channel.subscribe do |msg|
314
+ expect(msg.name).to eql(event_name)
315
+ expect(msg.data).to eql(data)
316
+ stop_reactor
317
+ end
318
+
319
+ subject.publish channel_name, event_name, data
320
+ end
321
+ end
322
+
323
+ specify 'publishing does not result in a channel being created' do
324
+ subject.publish channel_name, event_name, data
325
+ subject.channels.fetch(channel_name) do
326
+ # Block called if channel does not exist
327
+ EventMachine.add_timer(1) do
328
+ subject.channels.fetch(channel_name) do
329
+ # Block called if channel does not exist
330
+ stop_reactor
331
+ end
332
+ end
333
+ end
334
+ end
335
+
336
+ context 'with extras' do
337
+ let(:channel_name) { "pushenabled:#{random_str}" }
338
+
339
+ specify 'publishing supports extras' do
340
+ sub_channel.attach do
341
+ sub_channel.subscribe do |msg|
342
+ expect(msg.extras).to eql(extras)
343
+ stop_reactor
344
+ end
345
+
346
+ subject.publish channel_name, event_name, {}, extras: extras
347
+ end
348
+ end
349
+ end
350
+
351
+ specify 'publishing supports an array of Message objects' do
352
+ sub_channel.attach do
353
+ sub_channel.subscribe do |msg|
354
+ expect(msg.name).to eql(event_name)
355
+ expect(msg.data).to eql(data)
356
+ stop_reactor
357
+ end
358
+
359
+ subject.publish channel_name, [message]
360
+ end
361
+ end
362
+
363
+ specify 'publishing supports an array of Hash objects' do
364
+ sub_channel.attach do
365
+ sub_channel.subscribe do |msg|
366
+ expect(msg.name).to eql(event_name)
367
+ expect(msg.data).to eql(data)
368
+ stop_reactor
369
+ end
370
+
371
+ subject.publish channel_name, [name: event_name, data: data]
372
+ end
373
+ end
374
+
375
+ specify 'publishing on a closed connection fails' do
376
+ subject.connection.once(:connected) do
377
+ subject.connection.once(:closed) do
378
+ subject.publish(channel_name, name: event_name).errback do |error|
379
+ expect(error).to be_kind_of(Ably::Exceptions::MessageQueueingDisabled)
380
+ stop_reactor
381
+ end
382
+ end
383
+ connection.close
384
+ end
385
+ end
386
+
387
+ context 'queue_messages ClientOption' do
388
+ context 'when true' do
389
+ subject { auto_close Ably::Realtime::Client.new(client_options.merge(auto_connect: false)) }
390
+
391
+ it 'will queue messages whilst connecting and publish once connected' do
392
+ sub_channel.attach do
393
+ sub_channel.subscribe do |msg|
394
+ expect(msg.name).to eql(event_name)
395
+ stop_reactor
396
+ end
397
+ subject.connection.once(:connecting) do
398
+ subject.publish channel_name, event_name
399
+ end
400
+ subject.connection.connect
401
+ end
402
+ end
403
+ end
404
+
405
+ context 'when false' do
406
+ subject { auto_close Ably::Realtime::Client.new(client_options.merge(auto_connect: false, queue_messages: false)) }
407
+
408
+ it 'will reject messages on an initializing connection' do
409
+ sub_channel.attach do
410
+ subject.connection.once(:connecting) do
411
+ subject.publish(channel_name, event_name).errback do |error|
412
+ expect(error).to be_kind_of(Ably::Exceptions::MessageQueueingDisabled)
413
+ stop_reactor
414
+ end
415
+ end
416
+ subject.connection.connect
417
+ end
418
+ end
419
+ end
420
+ end
421
+
422
+ context 'with more than allowed messages in a single publish' do
423
+ let(:channel_name) { random_str }
424
+
425
+ it 'rejects the publish' do
426
+ messages = (Ably::Realtime::Connection::MAX_PROTOCOL_MESSAGE_BATCH_SIZE + 1).times.map do
427
+ { name: 'foo' }
428
+ end
429
+
430
+ subject.publish(channel_name, messages).errback do |error|
431
+ expect(error).to be_kind_of(Ably::Exceptions::InvalidRequest)
432
+ stop_reactor
433
+ end
434
+ end
435
+ end
436
+ end
284
437
  end
285
438
  end