ably 1.1.0 → 1.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 41a1cf12a01ccf1b9ecf3523790c45d77c08815d23d1cd3b23058dd456377a0b
4
- data.tar.gz: e5174d825c354bc813819c3e0a0ab7341c46b8e04864ac24575c475cd773ad54
3
+ metadata.gz: 26f56201f9faae28b9b74ef9223e8d50c049a25d065f80d8612ce0013da46783
4
+ data.tar.gz: f74af9b0f0178576e41094fccf80821983da0b896e6bd7667fe534abe0d096bb
5
5
  SHA512:
6
- metadata.gz: 8327568876690de6bbc5e95d3ce7759f7856b73d91e8726f5880291cb5a5579d962cd4b93b4d87b497d9e395a7971f515b926c2f54e220b1ba2667744bc891dd
7
- data.tar.gz: 13752c5b6f79067275b192a55d14019ace0781eb061844248faf56b878d9afd78229396e82c11d171851f5570164921d9729e3ca1560c297e179e556ba87ed2e
6
+ metadata.gz: 2a4c6c4006a176c01eacd9f38d9f11a61fb7f64880a764a663eca26e2ed2b7806203f972edf7cb5f0dec1034e6776d6b6dac459766ba920cc09ea156022640a9
7
+ data.tar.gz: 59d33ebc03521cf47449140715b5506dca17ac6b3708b914b6b0987d038c56667231086c8ff81c8d740d8a62c4474ac78c9839360b795e2d5c8f779ad972e3a5
@@ -5,11 +5,14 @@ env:
5
5
  language: ruby
6
6
  rvm:
7
7
  - 1.9.3
8
- - 2.0.0
9
8
  - 2.1.10
10
- - 2.2.0
11
- - 2.3.6
12
- - 2.4.4
9
+ - 2.2.10
10
+ - 2.3.8
11
+ - 2.5.5
12
+ - 2.6.0
13
+ - 2.6.1
14
+ - 2.6.2
15
+ - 2.6.3
13
16
  script: spec/run_parallel_tests
14
17
  notifications:
15
18
  slack:
@@ -1,7 +1,24 @@
1
1
  # Change Log
2
2
 
3
- ## [v1.1.0](https://github.com/ably/ably-ruby/tree/v1.1.0)
3
+ ## [v1.1.1](https://github.com/ably/ably-ruby/tree/v1.1.1)
4
4
 
5
+ [Full Changelog](https://github.com/ably/ably-ruby/compare/v1.1.0...v1.1.1)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Support transient publishes as part of 1.1 spec [\#164](https://github.com/ably/ably-ruby/issues/164)
10
+
11
+ **Fixed bugs:**
12
+
13
+ - RTN16b recovery not fully implemented [\#180](https://github.com/ably/ably-ruby/issues/180)
14
+ - Publishing a high number of messages before connected results in lost messages [\#179](https://github.com/ably/ably-ruby/issues/179)
15
+
16
+ **Merged pull requests:**
17
+
18
+ - msgSerial fixes including connection recovery fix [\#181](https://github.com/ably/ably-ruby/pull/181) ([mattheworiordan](https://github.com/mattheworiordan))
19
+ - Known limitations section in README [\#177](https://github.com/ably/ably-ruby/pull/177) ([Srushtika](https://github.com/Srushtika))
20
+
21
+ ## [v1.1.0](https://github.com/ably/ably-ruby/tree/v1.1.0) (2019-02-06)
5
22
  [Full Changelog](https://github.com/ably/ably-ruby/compare/v1.0.7...v1.1.0)
6
23
 
7
24
  **Fixed bugs:**
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/ably.svg)](http://badge.fury.io/rb/ably)
4
4
  [![Coverage Status](https://coveralls.io/repos/ably/ably-ruby/badge.svg)](https://coveralls.io/r/ably/ably-ruby)
5
5
 
6
- A Ruby client library for [ably.io](https://www.ably.io), the realtime messaging service.
6
+ A Ruby client library for [ably.io](https://www.ably.io), the realtime messaging service. This library currently targets the [Ably 1.1 client library specification](https://www.ably.io/documentation/client-lib-development-guide/features/). You can jump to the '[Known Limitations](#known-limitations)' section to see the features this client library does not yet support or [view our client library SDKs feature support matrix](https://www.ably.io/download/sdk-feature-support-matrix) to see the list of all the available features.
7
7
 
8
8
  ## Supported platforms
9
9
 
@@ -13,6 +13,14 @@ We regression-test the SDK against a selection of Ruby versions (which we update
13
13
 
14
14
  If you find any compatibility issues, please [do raise an issue](https://github.com/ably/ably-ruby/issues/new) in this repository or [contact Ably customer support](https://support.ably.io/) for advice.
15
15
 
16
+ ## Known Limitations
17
+
18
+ This client library is currently *not compatible* with some of the Ably features:
19
+
20
+ | Feature |
21
+ | :--- |
22
+ | [Custom transportParams](https://www.ably.io/documentation/realtime/connection#client-options) |
23
+
16
24
  ## Documentation
17
25
 
18
26
  Visit https://www.ably.io/documentation for a complete API reference and more examples.
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.add_runtime_dependency 'faraday', '~> 0.12'
25
25
  spec.add_runtime_dependency 'excon', '~> 0.55'
26
26
 
27
- if RUBY_VERSION.match(/^1/)
27
+ if RUBY_VERSION.match(/^1\./)
28
28
  spec.add_runtime_dependency 'json', '< 2.0'
29
29
  else
30
30
  spec.add_runtime_dependency 'json'
@@ -33,15 +33,15 @@ Gem::Specification.new do |spec|
33
33
  spec.add_runtime_dependency 'msgpack', '>= 0.6.2'
34
34
  spec.add_runtime_dependency 'addressable', '>= 2.0.0'
35
35
 
36
- spec.add_development_dependency 'bundler', '~> 1.3'
37
36
  spec.add_development_dependency 'rake', '~> 11.3'
38
37
  spec.add_development_dependency 'redcarpet', '~> 3.3'
39
38
  spec.add_development_dependency 'rspec', '~> 3.3.0' # version lock, see config.around(:example, :event_machine) in event_machine_helper.rb
40
39
  spec.add_development_dependency 'rspec-retry', '~> 0.6'
41
40
  spec.add_development_dependency 'yard', '~> 0.9'
42
41
  spec.add_development_dependency 'rspec-instafail', '~> 1.0'
42
+ spec.add_development_dependency 'bundler', '>= 1.3.0'
43
43
 
44
- if RUBY_VERSION.match(/^1/)
44
+ if RUBY_VERSION.match(/^1\./)
45
45
  spec.add_development_dependency 'public_suffix', '~> 1.4.6' # Later versions do not support Ruby 1.9
46
46
  spec.add_development_dependency 'webmock', '2.2'
47
47
  spec.add_development_dependency 'parallel_tests', '~> 2.9.0'
@@ -110,9 +110,6 @@ module Ably
110
110
  end
111
111
 
112
112
  @rest_client = Ably::Rest::Client.new(options.merge(realtime_client: self))
113
- @auth = Ably::Realtime::Auth.new(self)
114
- @channels = Ably::Realtime::Channels.new(self)
115
- @connection = Ably::Realtime::Connection.new(self, options)
116
113
  @echo_messages = rest_client.options.fetch(:echo_messages, true) == false ? false : true
117
114
  @queue_messages = rest_client.options.fetch(:queue_messages, true) == false ? false : true
118
115
  @custom_realtime_host = rest_client.options[:realtime_host] || rest_client.options[:ws_host]
@@ -120,6 +117,10 @@ module Ably
120
117
  @recover = rest_client.options[:recover]
121
118
 
122
119
  raise ArgumentError, "Recovery key '#{recover}' is invalid" if recover && !recover.match(Connection::RECOVER_REGEX)
120
+
121
+ @auth = Ably::Realtime::Auth.new(self)
122
+ @channels = Ably::Realtime::Channels.new(self)
123
+ @connection = Ably::Realtime::Connection.new(self, options)
123
124
  end
124
125
 
125
126
  # Return a {Ably::Realtime::Channel Realtime Channel} for the given name
@@ -66,7 +66,7 @@ module Ably
66
66
  ensure_state_machine_emits 'Ably::Models::ConnectionStateChange'
67
67
 
68
68
  # Expected format for a connection recover key
69
- RECOVER_REGEX = /^(?<recover>[\w!-]+):(?<connection_serial>\-?\w+)$/
69
+ RECOVER_REGEX = /^(?<recover>[^:]+):(?<connection_serial>[^:]+):(?<msg_serial>\-?\d+)$/
70
70
 
71
71
  # Defaults for automatic connection recovery and timeouts
72
72
  DEFAULTS = {
@@ -137,7 +137,6 @@ module Ably
137
137
  @client = client
138
138
  @__outgoing_message_queue__ = []
139
139
  @__pending_message_ack_queue__ = []
140
- reset_client_serial
141
140
 
142
141
  @defaults = DEFAULTS.dup
143
142
  options.each do |key, val|
@@ -145,6 +144,17 @@ module Ably
145
144
  end if options.kind_of?(Hash)
146
145
  @defaults.freeze
147
146
 
147
+ # If a recover client options is provided, then we need to ensure that the msgSerial matches the
148
+ # recover serial immediately at client library instantiation. This is done immediately so that any queued
149
+ # publishes use the correct serial number for these queued messages as well.
150
+ # There is no harm if the msgSerial is higher than expected if the recover fails.
151
+ recovery_msg_serial = connection_recover_parts && connection_recover_parts[:msg_serial].to_i
152
+ if recovery_msg_serial
153
+ @client_msg_serial = recovery_msg_serial
154
+ else
155
+ reset_client_msg_serial
156
+ end
157
+
148
158
  Client::IncomingMessageDispatcher.new client, self
149
159
  Client::OutgoingMessageDispatcher.new client, self
150
160
 
@@ -303,18 +313,17 @@ module Ably
303
313
  # @!attribute [r] recovery_key
304
314
  # @return [String] recovery key that can be used by another client to recover this connection with the :recover option
305
315
  def recovery_key
306
- "#{key}:#{serial}" if connection_resumable?
316
+ "#{key}:#{serial}:#{client_msg_serial}" if connection_resumable?
307
317
  end
308
318
 
309
319
  # Following a new connection being made, the connection ID, connection key
310
- # and message serial need to match the details provided by the server.
320
+ # and connection serial need to match the details provided by the server.
311
321
  #
312
322
  # @return [void]
313
323
  # @api private
314
324
  def configure_new(connection_id, connection_key, connection_serial)
315
325
  @id = connection_id
316
326
  @key = connection_key
317
- @client_serial = connection_serial
318
327
 
319
328
  update_connection_serial connection_serial
320
329
  end
@@ -542,11 +551,11 @@ module Ably
542
551
  defaults.fetch(:realtime_request_timeout)
543
552
  end
544
553
 
545
- # Resets the client serial (msgSerial) sent to Ably for each new {Ably::Models::ProtocolMessage}
546
- # (see #client_serial)
554
+ # Resets the client message serial (msgSerial) sent to Ably for each new {Ably::Models::ProtocolMessage}
555
+ # (see #client_msg_serial)
547
556
  # @api private
548
- def reset_client_serial
549
- @client_serial = -1
557
+ def reset_client_msg_serial
558
+ @client_msg_serial = -1
550
559
  end
551
560
 
552
561
  # When a hearbeat or any other message from Ably is received
@@ -568,15 +577,15 @@ module Ably
568
577
 
569
578
  private
570
579
 
571
- # The client serial is incremented for every message that is published that requires an ACK.
580
+ # The client message serial (msgSerial) is incremented for every message that is published that requires an ACK.
572
581
  # Note that this is different to the connection serial that contains the last known serial number
573
582
  # received from the server.
574
583
  #
575
584
  # A message serial number does not guarantee a message has been received, only sent.
576
585
  # A connection serial guarantees the server has received the message and is thus used for connection recovery and resumes.
577
586
  # @return [Integer] starting at -1 indicating no messages sent, 0 when the first message is sent
578
- def client_serial
579
- @client_serial
587
+ def client_msg_serial
588
+ @client_msg_serial
580
589
  end
581
590
 
582
591
  def resume_callbacks
@@ -601,11 +610,11 @@ module Ably
601
610
  end
602
611
 
603
612
  def add_message_serial_to(protocol_message)
604
- @client_serial += 1
605
- protocol_message[:msgSerial] = client_serial
613
+ @client_msg_serial += 1
614
+ protocol_message[:msgSerial] = client_msg_serial
606
615
  yield
607
616
  rescue StandardError => e
608
- @client_serial -= 1
617
+ @client_msg_serial -= 1
609
618
  raise e
610
619
  end
611
620
 
@@ -100,13 +100,11 @@ module Ably::Realtime
100
100
  resend_pending_message_ack_queue
101
101
  else
102
102
  logger.debug { "ConnectionManager: Connection was not resumed, old connection ID #{connection.id} has been updated with new connection ID #{protocol_message.connection_id} and key #{protocol_message.connection_key}" }
103
- connection.reset_client_serial
104
103
  nack_messages_on_all_channels protocol_message.error
105
104
  force_reattach_on_channels protocol_message.error
106
105
  end
107
106
  else
108
107
  logger.debug { "ConnectionManager: New connection created with ID #{protocol_message.connection_id} and key #{protocol_message.connection_key}" }
109
- connection.reset_client_serial
110
108
  end
111
109
 
112
110
  reattach_suspended_channels protocol_message.error
@@ -1,5 +1,5 @@
1
1
  module Ably
2
- VERSION = '1.1.0'
2
+ VERSION = '1.1.1'
3
3
  PROTOCOL_VERSION = '1.1'
4
4
 
5
5
  # Allow a variant to be configured for all instances of this client library
@@ -661,17 +661,19 @@ describe Ably::Realtime::Auth, :event_machine do
661
661
  client.connection.once(:disconnected) { raise 'Upgrade does not require a disconnect' }
662
662
 
663
663
  channel = client.channels.get('foo')
664
- channel.publish('not-allowed').errback do |error|
665
- expect(error.code).to eql(40160)
666
- expect(error.message).to match(/permission denied/)
664
+ channel.attach do
665
+ channel.publish('not-allowed').errback do |error|
666
+ expect(error.code).to eql(40160)
667
+ expect(error.message).to match(/permission denied/)
667
668
 
668
- client.auth.authorize(nil, auth_callback: upgraded_token_cb)
669
- client.connection.once(:update) do
670
- expect(client.connection.error_reason).to be_nil
671
- channel.subscribe('now-allowed') do |message|
672
- stop_reactor
669
+ client.auth.authorize(nil, auth_callback: upgraded_token_cb)
670
+ client.connection.once(:update) do
671
+ expect(client.connection.error_reason).to be_nil
672
+ channel.subscribe('now-allowed') do |message|
673
+ stop_reactor
674
+ end
675
+ channel.publish 'now-allowed'
673
676
  end
674
- channel.publish 'now-allowed'
675
677
  end
676
678
  end
677
679
  end
@@ -112,22 +112,26 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
112
112
 
113
113
  context 'in multiple ProtocolMessages', em_timeout: (30 / 10) + 5 do
114
114
  it 'retrieves limited history forwards with pagination' do
115
- messages_sent.times do |index|
116
- EventMachine.add_timer(index.to_f / rate_per_second) do
117
- channel.publish('event', "history#{index}") do
118
- next unless index == messages_sent - 1
119
- 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
120
122
  end
121
123
  end
122
124
  end
123
125
  end
124
126
 
125
127
  it 'retrieves limited history backwards with pagination' do
126
- messages_sent.times.to_a.reverse.each do |index|
127
- EventMachine.add_timer((messages_sent - index).to_f / rate_per_second) do
128
- channel.publish('event', "history#{index}") do
129
- next unless index == 0
130
- 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
131
135
  end
132
136
  end
133
137
  end
@@ -139,18 +143,20 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
139
143
  let(:messages_per_batch) { 10 }
140
144
 
141
145
  it 'return the same results with unique matching message IDs' do
142
- batches.times do |batch|
143
- EventMachine.add_timer(batch.to_f / batches.to_f) do
144
- 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
145
151
  end
146
- end
147
152
 
148
- channel.subscribe('event') do |message|
149
- messages << message
150
- if messages.count == batches * messages_per_batch
151
- channel.history do |page|
152
- expect(page.items.map(&:id).sort).to eql(messages.map(&:id).sort)
153
- 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
154
160
  end
155
161
  end
156
162
  end
@@ -921,7 +921,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
921
921
  end
922
922
  end
923
923
 
924
- it 'retains the client_serial (#RTN15c2, #RTN15c3)' do
924
+ it 'retains the client_msg_serial (#RTN15c2, #RTN15c3)' do
925
925
  last_message = nil
926
926
  channel = client.channels.get("foo")
927
927
 
@@ -1103,7 +1103,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
1103
1103
  end
1104
1104
  end
1105
1105
 
1106
- it 'resets the client_serial (#RTN15c3)' do
1106
+ it 'continues to use the client_msg_serial (#RTN15c3)' do
1107
1107
  last_message = nil
1108
1108
  channel = client.channels.get("foo")
1109
1109
 
@@ -1121,7 +1121,7 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
1121
1121
  connection.once(:connected) do
1122
1122
  channel.publish("first on new connection") do
1123
1123
  # Message serial reset after failed resume
1124
- expect(last_message.message_serial).to eql(0)
1124
+ expect(last_message.message_serial).to eql(2)
1125
1125
  stop_reactor
1126
1126
  end
1127
1127
  end
@@ -264,7 +264,7 @@ describe Ably::Realtime::Connection, :event_machine do
264
264
  channel.subscribe('event') do |message|
265
265
  messages_received << message.data.to_i
266
266
  if messages_received.count == total_expected
267
- expect(messages_received).to match(total_expected.times)
267
+ expect(messages_received).to match(total_expected.times.to_a)
268
268
  expect(auth_requests.count).to eql(iteration + 1)
269
269
  EventMachine.add_timer(1) do
270
270
  channel.unsubscribe 'event'
@@ -649,16 +649,47 @@ describe Ably::Realtime::Connection, :event_machine do
649
649
  end
650
650
 
651
651
  it 'is set to 1 when the second message is received' do
652
- channel.publish('event', 'data') do
653
- channel.publish('event', 'data')
652
+ channel.attach do
653
+ messages = []
654
+ channel.subscribe do |message|
655
+ messages << message
656
+ if messages.length == 2
657
+ expect(connection.serial).to eql(1)
658
+ stop_reactor
659
+ end
660
+ end
661
+
662
+ channel.publish('event', 'data') do
663
+ channel.publish('event', 'data')
664
+ end
654
665
  end
666
+ end
667
+ end
655
668
 
656
- messages = []
657
- channel.subscribe do |message|
658
- messages << message
659
- if messages.length == 2
660
- expect(connection.serial).to eql(1)
661
- stop_reactor
669
+ describe '#msgSerial' do
670
+ context 'when messages are queued for publish before a connection is established' do
671
+ let(:batches) { 6 }
672
+ let(:messages_per_batch) { 10 }
673
+
674
+ let(:publishing_client) { auto_close Ably::Realtime::Client.new(default_options) }
675
+ let(:channel_name) { random_str }
676
+ let(:publishing_channel) { publishing_client.channels.get(channel_name) }
677
+ let(:receiving_channel) { client.channels.get(channel_name) }
678
+
679
+ it 'the msgSerial is always incrementing (and not reset when the new connection is established) ensuring messages are never de-duped by the realtime service' do
680
+ messages = []
681
+
682
+ receiving_channel.attach do
683
+ receiving_channel.subscribe('event') do |message|
684
+ messages << message
685
+ stop_reactor if messages.count == batches * messages_per_batch
686
+ end
687
+
688
+ batches.times do |batch|
689
+ EventMachine.add_timer(batch.to_f / batches.to_f) do
690
+ messages_per_batch.times { |index| publishing_channel.publish('event') }
691
+ end
692
+ end
662
693
  end
663
694
  end
664
695
  end
@@ -1005,10 +1036,9 @@ describe Ably::Realtime::Connection, :event_machine do
1005
1036
  let(:client_options) { default_options.merge(websocket_heartbeats_disabled: true) }
1006
1037
 
1007
1038
  it 'does not provide the heartbeats argument in the websocket connection params (#RTN23b)' do
1008
- skip 'Native heartbeats not yet supported in the WS driver https://github.com/ably/ably-ruby/issues/116'
1009
1039
  expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
1010
1040
  uri = URI.parse(url)
1011
- expect(CGI::parse(uri.query)['heartbeats'][0]).to be_nil
1041
+ expect(CGI::parse(uri.query)['heartbeats'][0]).to eql('true')
1012
1042
  stop_reactor
1013
1043
  end
1014
1044
  client
@@ -1126,7 +1156,7 @@ describe Ably::Realtime::Connection, :event_machine do
1126
1156
  expected_serial += 1 # attach message received
1127
1157
  expect(connection.serial).to eql(expected_serial)
1128
1158
 
1129
- expect(connection.recovery_key).to eql("#{connection.key}:#{connection.serial}")
1159
+ expect(connection.recovery_key).to eql("#{connection.key}:#{connection.serial}:#{connection.send(:client_msg_serial)}")
1130
1160
  stop_reactor
1131
1161
  end
1132
1162
  end
@@ -1237,6 +1267,78 @@ describe Ably::Realtime::Connection, :event_machine do
1237
1267
  end
1238
1268
  end
1239
1269
  end
1270
+
1271
+ context 'when messages have been published' do
1272
+ describe 'the new connection' do
1273
+ it 'uses the correct msgSerial from the old connection' do
1274
+ msg_serial, recovery_key, connection_id = nil, nil, nil
1275
+
1276
+ channel.attach do
1277
+ expect(connection.send(:client_msg_serial)).to eql(-1) # no messages published yet
1278
+ connection_id = client.connection.id
1279
+ connection.transport.__incoming_protocol_msgbus__
1280
+ channel.publish('event', 'message') do
1281
+ msg_serial = connection.send(:client_msg_serial)
1282
+ expect(msg_serial).to eql(0)
1283
+ recovery_key = client.connection.recovery_key
1284
+ connection.transition_state_machine! :failed
1285
+ end
1286
+ end
1287
+
1288
+ connection.on(:failed) do
1289
+ recover_client = auto_close Ably::Realtime::Client.new(default_options.merge(recover: recovery_key))
1290
+ recover_client_channel = recover_client.channel(channel_name)
1291
+ recover_client_channel.attach do
1292
+ expect(recover_client.connection.id).to eql(connection_id)
1293
+ expect(recover_client.connection.send(:client_msg_serial)).to eql(msg_serial)
1294
+ stop_reactor
1295
+ end
1296
+ end
1297
+ end
1298
+ end
1299
+ end
1300
+
1301
+ context 'when messages are published before the new connection is recovered' do
1302
+ describe 'the new connection' do
1303
+ it 'uses the correct msgSerial from the old connection for the queued messages' do
1304
+ msg_serial, recovery_key, connection_id = nil, nil, nil
1305
+
1306
+ channel.attach do
1307
+ expect(connection.send(:client_msg_serial)).to eql(-1) # no messages published yet
1308
+ connection_id = client.connection.id
1309
+ connection.transport.__incoming_protocol_msgbus__
1310
+ channel.publish('event', 'message-1') do
1311
+ msg_serial = connection.send(:client_msg_serial)
1312
+ expect(msg_serial).to eql(0)
1313
+ recovery_key = client.connection.recovery_key
1314
+ connection.transition_state_machine! :failed
1315
+ end
1316
+ end
1317
+
1318
+ connection.on(:failed) do
1319
+ recover_client = auto_close Ably::Realtime::Client.new(default_options.merge(recover: recovery_key))
1320
+ recover_client_channel = recover_client.channel(channel_name)
1321
+ expect(recover_client.connection.send(:client_msg_serial)).to eql(msg_serial)
1322
+
1323
+ recover_client.connection.once(:connecting) do
1324
+ recover_client_channel.publish('event', 'message-2')
1325
+ expect(recover_client.connection.send(:client_msg_serial)).to eql(msg_serial + 1)
1326
+ end
1327
+
1328
+ recover_client_channel.attach do
1329
+ expect(recover_client.connection.id).to eql(connection_id)
1330
+
1331
+ recover_client_channel.subscribe do |message|
1332
+ raise "Unexpected message #{message}" if message.data != 'message-2'
1333
+ EventMachine.add_timer(2) do
1334
+ stop_reactor
1335
+ end
1336
+ end
1337
+ end
1338
+ end
1339
+ end
1340
+ end
1341
+ end
1240
1342
  end
1241
1343
 
1242
1344
  context 'with :recover option' do
@@ -1250,7 +1352,7 @@ describe Ably::Realtime::Connection, :event_machine do
1250
1352
  end
1251
1353
 
1252
1354
  context 'with invalid formatted value sent to server' do
1253
- let(:client_options) { default_options.merge(recover: 'not-a-valid-connection-key:1', log_level: :none) }
1355
+ let(:client_options) { default_options.merge(recover: 'not-a-valid-connection-key:1:0', log_level: :none) }
1254
1356
 
1255
1357
  it 'sets the #error_reason and moves the connection to FAILED' do
1256
1358
  connection.once(:failed) do |state_change|
@@ -1265,7 +1367,7 @@ describe Ably::Realtime::Connection, :event_machine do
1265
1367
  end
1266
1368
 
1267
1369
  context 'with expired (missing) value sent to server' do
1268
- let(:client_options) { default_options.merge(recover: 'wVIsgTHAB1UvXh7z-1991d8586:0', log_level: :fatal) }
1370
+ let(:client_options) { default_options.merge(recover: 'wVIsgTHAB1UvXh7z-1991d8586:0:0', log_level: :fatal) }
1269
1371
 
1270
1372
  it 'connects but sets the error reason and includes the reason in the state change' do
1271
1373
  connection.once(:connected) do |state_change|