ably-rest 0.8.3 → 0.8.5
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/.travis.yml +1 -0
- data/lib/submodules/ably-ruby/CHANGELOG.md +10 -0
- data/lib/submodules/ably-ruby/README.md +1 -1
- data/lib/submodules/ably-ruby/Rakefile +1 -1
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +24 -20
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +3 -0
- data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/models/connection_state_change.rb +43 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +2 -1
- data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +8 -6
- data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +4 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +4 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +35 -4
- data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +13 -13
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +13 -5
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +27 -7
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +22 -12
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +16 -10
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +5 -4
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +42 -24
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +25 -17
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +4 -4
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +3 -2
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +15 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +9 -9
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +168 -21
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channels_spec.rb +6 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +6 -5
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +29 -19
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +150 -35
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +146 -23
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +2 -2
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +44 -24
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +77 -46
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +31 -3
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +15 -5
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +9 -7
- data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +30 -4
- data/lib/submodules/ably-ruby/spec/support/protocol_helper.rb +9 -6
- data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/models/channel_state_change_spec.rb +44 -0
- data/lib/submodules/ably-ruby/spec/unit/models/connection_state_change_spec.rb +54 -0
- data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +8 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +18 -0
- metadata +6 -2
|
@@ -41,23 +41,25 @@ module Ably::Realtime
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
before_transition(to: [:connected]) do |connection, current_transition|
|
|
44
|
-
connection.manager.connected current_transition.metadata
|
|
44
|
+
connection.manager.connected current_transition.metadata.protocol_message
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
after_transition(to: [:connected]) do |connection, current_transition|
|
|
48
|
-
|
|
49
|
-
if is_error_type?(
|
|
50
|
-
connection.logger.warn "ConnectionManager: Connected with error - #{
|
|
51
|
-
connection.emit :error,
|
|
48
|
+
error = current_transition.metadata.reason
|
|
49
|
+
if is_error_type?(error)
|
|
50
|
+
connection.logger.warn "ConnectionManager: Connected with error - #{error.message}"
|
|
51
|
+
connection.emit :error, error
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
after_transition(to: [:disconnected, :suspended], from: [:connecting]) do |connection, current_transition|
|
|
56
|
-
|
|
56
|
+
err = error_from_state_change(current_transition)
|
|
57
|
+
connection.manager.respond_to_transport_disconnected_when_connecting err
|
|
57
58
|
end
|
|
58
59
|
|
|
59
|
-
after_transition(to: [:disconnected], from: [:connected]) do |connection, current_transition|
|
|
60
|
-
|
|
60
|
+
after_transition(to: [:disconnected, :suspended], from: [:connected]) do |connection, current_transition|
|
|
61
|
+
err = error_from_state_change(current_transition)
|
|
62
|
+
connection.manager.respond_to_transport_disconnected_whilst_connected err
|
|
61
63
|
end
|
|
62
64
|
|
|
63
65
|
after_transition(to: [:disconnected, :suspended]) do |connection|
|
|
@@ -65,7 +67,8 @@ module Ably::Realtime
|
|
|
65
67
|
end
|
|
66
68
|
|
|
67
69
|
before_transition(to: [:failed]) do |connection, current_transition|
|
|
68
|
-
|
|
70
|
+
err = error_from_state_change(current_transition)
|
|
71
|
+
connection.manager.fail err
|
|
69
72
|
end
|
|
70
73
|
|
|
71
74
|
after_transition(to: [:closing], from: [:initialized, :disconnected, :suspended]) do |connection|
|
|
@@ -82,24 +85,29 @@ module Ably::Realtime
|
|
|
82
85
|
|
|
83
86
|
# Transitions responsible for updating connection#error_reason
|
|
84
87
|
before_transition(to: [:disconnected, :suspended, :failed]) do |connection, current_transition|
|
|
85
|
-
|
|
88
|
+
err = error_from_state_change(current_transition)
|
|
89
|
+
connection.set_failed_connection_error_reason err
|
|
86
90
|
end
|
|
87
91
|
|
|
88
92
|
before_transition(to: [:connected, :closed]) do |connection, current_transition|
|
|
89
|
-
|
|
90
|
-
current_transition.metadata.error
|
|
91
|
-
else
|
|
92
|
-
current_transition.metadata
|
|
93
|
-
end
|
|
93
|
+
err = error_from_state_change(current_transition)
|
|
94
94
|
|
|
95
|
-
if
|
|
96
|
-
connection.set_failed_connection_error_reason
|
|
95
|
+
if err
|
|
96
|
+
connection.set_failed_connection_error_reason err
|
|
97
97
|
else
|
|
98
98
|
# Connected & Closed are "healthy" final states so reset the error reason
|
|
99
99
|
connection.clear_error_reason
|
|
100
100
|
end
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
+
def self.error_from_state_change(current_transition)
|
|
104
|
+
# ConnectionStateChange object is always passed in current_transition metadata object
|
|
105
|
+
connection_state_change = current_transition.metadata
|
|
106
|
+
# Reason attribute contains errors
|
|
107
|
+
err = connection_state_change && connection_state_change.reason
|
|
108
|
+
err if is_error_type?(err)
|
|
109
|
+
end
|
|
110
|
+
|
|
103
111
|
private
|
|
104
112
|
def connection
|
|
105
113
|
object
|
|
@@ -405,7 +405,7 @@ module Ably::Realtime
|
|
|
405
405
|
deferrable_succeed deferrable, &success_block
|
|
406
406
|
end
|
|
407
407
|
|
|
408
|
-
protocol_message.errback do |
|
|
408
|
+
protocol_message.errback do |error|
|
|
409
409
|
change_state failed_state, error if failed_state
|
|
410
410
|
deferrable_fail deferrable, error
|
|
411
411
|
end
|
|
@@ -419,8 +419,8 @@ module Ably::Realtime
|
|
|
419
419
|
end
|
|
420
420
|
|
|
421
421
|
def deferrable_fail(deferrable, *args, &block)
|
|
422
|
-
safe_yield block,
|
|
423
|
-
EventMachine.next_tick { deferrable.fail
|
|
422
|
+
safe_yield block, *args if block_given?
|
|
423
|
+
EventMachine.next_tick { deferrable.fail *args } # allow errback to be added to the returned Deferrable
|
|
424
424
|
deferrable
|
|
425
425
|
end
|
|
426
426
|
|
|
@@ -431,7 +431,7 @@ module Ably::Realtime
|
|
|
431
431
|
ensure_channel_attached(deferrable) do
|
|
432
432
|
send_presence_protocol_message(action, client_id, options).tap do |protocol_message|
|
|
433
433
|
protocol_message.callback { |message| deferrable_succeed deferrable, &success_block }
|
|
434
|
-
protocol_message.errback { |
|
|
434
|
+
protocol_message.errback { |error| deferrable_fail deferrable, error }
|
|
435
435
|
end
|
|
436
436
|
end
|
|
437
437
|
end
|
|
@@ -34,6 +34,7 @@ module Ably
|
|
|
34
34
|
#
|
|
35
35
|
# @param name [String, Array<Ably::Models::Message|Hash>, nil] The event name of the message to publish, or an Array of [Ably::Model::Message] objects or [Hash] objects with +:name+ and +:data+ pairs
|
|
36
36
|
# @param data [String, ByteArray, nil] The message payload unless an Array of [Ably::Model::Message] objects passed in the first argument
|
|
37
|
+
# @param attributes [Hash, nil] Optional additional message attributes such as :client_id or :connection_id, applied when name attribute is nil or a string
|
|
37
38
|
# @return [Boolean] true if the message was published, otherwise false
|
|
38
39
|
#
|
|
39
40
|
# @example
|
|
@@ -54,13 +55,13 @@ module Ably
|
|
|
54
55
|
# ]
|
|
55
56
|
# channel.publish messages
|
|
56
57
|
#
|
|
57
|
-
def publish(name, data = nil)
|
|
58
|
+
def publish(name, data = nil, attributes = {})
|
|
58
59
|
messages = if name.kind_of?(Enumerable)
|
|
59
60
|
name
|
|
60
61
|
else
|
|
61
62
|
ensure_utf_8 :name, name, allow_nil: true
|
|
62
63
|
ensure_supported_payload data
|
|
63
|
-
[{ name: name, data: data }]
|
|
64
|
+
[{ name: name, data: data }.merge(attributes)]
|
|
64
65
|
end
|
|
65
66
|
|
|
66
67
|
payload = messages.map do |message|
|
|
@@ -144,7 +144,7 @@ module Ably
|
|
|
144
144
|
|
|
145
145
|
token_params = options.delete(:token_params) || {}
|
|
146
146
|
@options = options
|
|
147
|
-
@auth = Auth.new(self,
|
|
147
|
+
@auth = Auth.new(self, token_params, options)
|
|
148
148
|
@channels = Ably::Rest::Channels.new(self)
|
|
149
149
|
@encoders = []
|
|
150
150
|
|
|
@@ -358,7 +358,7 @@ module Ably
|
|
|
358
358
|
yield
|
|
359
359
|
rescue Ably::Exceptions::TokenExpired => e
|
|
360
360
|
if auth.token_renewable?
|
|
361
|
-
auth.authorise force: true
|
|
361
|
+
auth.authorise({}, force: true)
|
|
362
362
|
yield
|
|
363
363
|
else
|
|
364
364
|
raise e
|
|
@@ -37,6 +37,21 @@ module Ably::Util
|
|
|
37
37
|
@options = DEFAULTS.merge(options).freeze
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
# Obtain a default CipherParams. This uses default algorithm, mode and
|
|
41
|
+
# padding and key length. A key and IV are generated using the default
|
|
42
|
+
# system SecureRandom; the key may be obtained from the returned CipherParams
|
|
43
|
+
# for out-of-band distribution to other clients.
|
|
44
|
+
#
|
|
45
|
+
# @return [Hash] CipherParam options Hash with attributes :key, :algorithn, :mode, :key_length
|
|
46
|
+
#
|
|
47
|
+
def self.get_default_params(key = nil)
|
|
48
|
+
params = DEFAULTS.merge(key: key)
|
|
49
|
+
params[:key_length] = key.unpack('b*').first.length if params[:key]
|
|
50
|
+
cipher_type = "#{params[:algorithm]}-#{params[:key_length]}-#{params[:mode]}"
|
|
51
|
+
params[:key] = OpenSSL::Cipher.new(cipher_type.upcase).random_key unless params[:key]
|
|
52
|
+
params
|
|
53
|
+
end
|
|
54
|
+
|
|
40
55
|
# Encrypt payload using configured Cipher
|
|
41
56
|
#
|
|
42
57
|
# @param [String] payload the payload to be encrypted
|
|
@@ -8,7 +8,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
|
8
8
|
vary_by_protocol do
|
|
9
9
|
let(:default_options) { { key: api_key, environment: environment, protocol: protocol } }
|
|
10
10
|
let(:client_options) { default_options }
|
|
11
|
-
let(:client) { Ably::Realtime::Client.new(client_options) }
|
|
11
|
+
let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
|
|
12
12
|
let(:auth) { client.auth }
|
|
13
13
|
|
|
14
14
|
context 'with basic auth' do
|
|
@@ -101,7 +101,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
|
101
101
|
let(:auth_params) { { :body => random_str } }
|
|
102
102
|
|
|
103
103
|
it 'contains the configured auth options' do
|
|
104
|
-
auth.authorise(auth_url: auth_url, auth_params: auth_params) do
|
|
104
|
+
auth.authorise({}, auth_url: auth_url, auth_params: auth_params) do
|
|
105
105
|
expect(auth.options[:auth_url]).to eql(auth_url)
|
|
106
106
|
stop_reactor
|
|
107
107
|
end
|
|
@@ -112,7 +112,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
|
112
112
|
let(:custom_ttl) { 33 }
|
|
113
113
|
|
|
114
114
|
it 'contains the configured auth options' do
|
|
115
|
-
auth.authorise(
|
|
115
|
+
auth.authorise(ttl: custom_ttl) do
|
|
116
116
|
expect(auth.token_params[:ttl]).to eql(custom_ttl)
|
|
117
117
|
stop_reactor
|
|
118
118
|
end
|
|
@@ -144,7 +144,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
|
144
144
|
|
|
145
145
|
context '#create_token_request' do
|
|
146
146
|
it 'returns a token request asynchronously' do
|
|
147
|
-
auth.create_token_request(
|
|
147
|
+
auth.create_token_request(ttl: custom_ttl) do |token_request|
|
|
148
148
|
expect(token_request).to be_a(Ably::Models::TokenRequest)
|
|
149
149
|
expect(token_request.ttl).to eql(custom_ttl)
|
|
150
150
|
stop_reactor
|
|
@@ -154,7 +154,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
|
154
154
|
|
|
155
155
|
context '#create_token_request_async' do
|
|
156
156
|
it 'returns a token request synchronously' do
|
|
157
|
-
auth.create_token_request_sync(
|
|
157
|
+
auth.create_token_request_sync(ttl: custom_ttl).tap do |token_request|
|
|
158
158
|
expect(token_request).to be_a(Ably::Models::TokenRequest)
|
|
159
159
|
expect(token_request.ttl).to eql(custom_ttl)
|
|
160
160
|
stop_reactor
|
|
@@ -164,7 +164,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
|
164
164
|
|
|
165
165
|
context '#request_token' do
|
|
166
166
|
it 'returns a token asynchronously' do
|
|
167
|
-
auth.request_token(
|
|
167
|
+
auth.request_token(client_id: custom_client_id, ttl: custom_ttl) do |token_details|
|
|
168
168
|
expect(token_details).to be_a(Ably::Models::TokenDetails)
|
|
169
169
|
expect(token_details.expires.to_i).to be_within(3).of(Time.now.to_i + custom_ttl)
|
|
170
170
|
expect(token_details.client_id).to eql(custom_client_id)
|
|
@@ -175,7 +175,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
|
175
175
|
|
|
176
176
|
context '#request_token_async' do
|
|
177
177
|
it 'returns a token synchronously' do
|
|
178
|
-
auth.request_token_sync(
|
|
178
|
+
auth.request_token_sync(ttl: custom_ttl, client_id: custom_client_id).tap do |token_details|
|
|
179
179
|
expect(token_details).to be_a(Ably::Models::TokenDetails)
|
|
180
180
|
expect(token_details.expires.to_i).to be_within(3).of(Time.now.to_i + custom_ttl)
|
|
181
181
|
expect(token_details.client_id).to eql(custom_client_id)
|
|
@@ -186,7 +186,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
|
186
186
|
|
|
187
187
|
context '#authorise' do
|
|
188
188
|
it 'returns a token asynchronously' do
|
|
189
|
-
auth.authorise(
|
|
189
|
+
auth.authorise(ttl: custom_ttl, client_id: custom_client_id) do |token_details|
|
|
190
190
|
expect(token_details).to be_a(Ably::Models::TokenDetails)
|
|
191
191
|
expect(token_details.expires.to_i).to be_within(3).of(Time.now.to_i + custom_ttl)
|
|
192
192
|
expect(token_details.client_id).to eql(custom_client_id)
|
|
@@ -197,7 +197,7 @@ describe Ably::Realtime::Auth, :event_machine do
|
|
|
197
197
|
|
|
198
198
|
context '#authorise_async' do
|
|
199
199
|
it 'returns a token synchronously' do
|
|
200
|
-
auth.authorise_sync(
|
|
200
|
+
auth.authorise_sync(ttl: custom_ttl, client_id: custom_client_id).tap do |token_details|
|
|
201
201
|
expect(auth.authorise_sync).to be_a(Ably::Models::TokenDetails)
|
|
202
202
|
expect(token_details.expires.to_i).to be_within(3).of(Time.now.to_i + custom_ttl)
|
|
203
203
|
expect(token_details.client_id).to eql(custom_client_id)
|
|
@@ -5,11 +5,11 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
|
|
|
5
5
|
vary_by_protocol do
|
|
6
6
|
let(:default_options) { options.merge(key: api_key, environment: environment, protocol: protocol) }
|
|
7
7
|
|
|
8
|
-
let(:client) { Ably::Realtime::Client.new(default_options) }
|
|
8
|
+
let(:client) { auto_close Ably::Realtime::Client.new(default_options) }
|
|
9
9
|
let(:channel) { client.channel(channel_name) }
|
|
10
10
|
let(:rest_channel) { client.rest_client.channel(channel_name) }
|
|
11
11
|
|
|
12
|
-
let(:client2) { Ably::Realtime::Client.new(default_options) }
|
|
12
|
+
let(:client2) { auto_close Ably::Realtime::Client.new(default_options) }
|
|
13
13
|
let(:channel2) { client2.channel(channel_name) }
|
|
14
14
|
|
|
15
15
|
let(:channel_name) { "persisted:#{random_str(2)}" }
|
|
@@ -6,7 +6,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
6
6
|
let(:default_options) { { key: api_key, environment: environment, protocol: protocol } }
|
|
7
7
|
let(:client_options) { default_options }
|
|
8
8
|
|
|
9
|
-
let(:client) { Ably::Realtime::Client.new(client_options) }
|
|
9
|
+
let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
|
|
10
10
|
let(:channel_name) { random_str }
|
|
11
11
|
let(:payload) { random_str }
|
|
12
12
|
let(:channel) { client.channel(channel_name) }
|
|
@@ -15,7 +15,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
15
15
|
describe 'initialization' do
|
|
16
16
|
context 'with :auto_connect option set to false on connection' do
|
|
17
17
|
let(:client) do
|
|
18
|
-
Ably::Realtime::Client.new(default_options.merge(auto_connect: false))
|
|
18
|
+
auto_close Ably::Realtime::Client.new(default_options.merge(auto_connect: false))
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
it 'remains initialized when accessing a channel' do
|
|
@@ -80,7 +80,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
it 'calls the SafeDeferrable callback on success' do
|
|
83
|
-
channel.attach.callback do
|
|
83
|
+
channel.attach.callback do
|
|
84
84
|
expect(channel).to be_a(Ably::Realtime::Channel)
|
|
85
85
|
expect(channel.state).to eq(:attached)
|
|
86
86
|
stop_reactor
|
|
@@ -92,7 +92,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
92
92
|
|
|
93
93
|
it 'reattaches' do
|
|
94
94
|
channel.attach do
|
|
95
|
-
channel.transition_state_machine :failed, RuntimeError.new
|
|
95
|
+
channel.transition_state_machine :failed, reason: RuntimeError.new
|
|
96
96
|
expect(channel).to be_failed
|
|
97
97
|
channel.attach do
|
|
98
98
|
expect(channel).to be_attached
|
|
@@ -131,7 +131,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
131
131
|
|
|
132
132
|
it 'attaches all channels', em_timeout: 15 do
|
|
133
133
|
connection_count.times.map do
|
|
134
|
-
Ably::Realtime::Client.new(default_options)
|
|
134
|
+
auto_close Ably::Realtime::Client.new(default_options)
|
|
135
135
|
end.each do |client|
|
|
136
136
|
channel_count.times.map do |index|
|
|
137
137
|
client.channel("channel-#{index}").attach do
|
|
@@ -148,21 +148,21 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
148
148
|
|
|
149
149
|
context 'failure as a result of insufficient key permissions' do
|
|
150
150
|
let(:restricted_client) do
|
|
151
|
-
Ably::Realtime::Client.new(default_options.merge(key: restricted_api_key, log_level: :fatal))
|
|
151
|
+
auto_close Ably::Realtime::Client.new(default_options.merge(key: restricted_api_key, log_level: :fatal))
|
|
152
152
|
end
|
|
153
153
|
let(:restricted_channel) { restricted_client.channel("cannot_subscribe") }
|
|
154
154
|
|
|
155
155
|
it 'emits failed event' do
|
|
156
156
|
restricted_channel.attach
|
|
157
|
-
restricted_channel.on(:failed) do |
|
|
157
|
+
restricted_channel.on(:failed) do |connection_state|
|
|
158
158
|
expect(restricted_channel.state).to eq(:failed)
|
|
159
|
-
expect(
|
|
159
|
+
expect(connection_state.reason.status).to eq(401)
|
|
160
160
|
stop_reactor
|
|
161
161
|
end
|
|
162
162
|
end
|
|
163
163
|
|
|
164
164
|
it 'calls the errback of the returned Deferrable' do
|
|
165
|
-
restricted_channel.attach.errback do |
|
|
165
|
+
restricted_channel.attach.errback do |error|
|
|
166
166
|
expect(restricted_channel.state).to eq(:failed)
|
|
167
167
|
expect(error.status).to eq(401)
|
|
168
168
|
stop_reactor
|
|
@@ -192,7 +192,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
192
192
|
restricted_channel.once(:failed) do
|
|
193
193
|
restricted_client.close do
|
|
194
194
|
# A direct call to #authorise is synchronous
|
|
195
|
-
restricted_client.auth.authorise(key: api_key)
|
|
195
|
+
restricted_client.auth.authorise({}, key: api_key)
|
|
196
196
|
|
|
197
197
|
restricted_client.connect do
|
|
198
198
|
restricted_channel.once(:attached) do
|
|
@@ -220,9 +220,10 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
220
220
|
end
|
|
221
221
|
|
|
222
222
|
it 'detaches from a channel and calls the provided block' do
|
|
223
|
-
channel.attach do
|
|
224
|
-
|
|
225
|
-
|
|
223
|
+
channel.attach do
|
|
224
|
+
expect(channel.state).to eq(:attached)
|
|
225
|
+
channel.detach do
|
|
226
|
+
expect(channel.state).to eq(:detached)
|
|
226
227
|
stop_reactor
|
|
227
228
|
end
|
|
228
229
|
end
|
|
@@ -249,7 +250,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
249
250
|
|
|
250
251
|
it 'calls the Deferrable callback on success' do
|
|
251
252
|
channel.attach do
|
|
252
|
-
channel.detach.callback do
|
|
253
|
+
channel.detach.callback do
|
|
253
254
|
expect(channel).to be_a(Ably::Realtime::Channel)
|
|
254
255
|
expect(channel.state).to eq(:detached)
|
|
255
256
|
stop_reactor
|
|
@@ -262,7 +263,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
262
263
|
|
|
263
264
|
it 'raises an exception' do
|
|
264
265
|
channel.attach do
|
|
265
|
-
channel.transition_state_machine :failed, RuntimeError.new
|
|
266
|
+
channel.transition_state_machine :failed, reason: RuntimeError.new
|
|
266
267
|
expect(channel).to be_failed
|
|
267
268
|
expect { channel.detach }.to raise_error Ably::Exceptions::InvalidStateChange
|
|
268
269
|
stop_reactor
|
|
@@ -433,6 +434,19 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
433
434
|
end
|
|
434
435
|
end
|
|
435
436
|
end
|
|
437
|
+
|
|
438
|
+
context 'and additional attributes' do
|
|
439
|
+
let(:client_id) { random_str }
|
|
440
|
+
|
|
441
|
+
it 'publishes the message with the attributes and return true indicating success' do
|
|
442
|
+
channel.publish(name, data, client_id: client_id) do
|
|
443
|
+
channel.history do |page|
|
|
444
|
+
expect(page.items.first.client_id).to eql(client_id)
|
|
445
|
+
stop_reactor
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
end
|
|
436
450
|
end
|
|
437
451
|
|
|
438
452
|
context 'with an array of Hash objects with :name and :data attributes' do
|
|
@@ -550,7 +564,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
550
564
|
|
|
551
565
|
it 'publishes all messages, all success callbacks are called, and a history request confirms all messages were published' do
|
|
552
566
|
connection_count.times.map do
|
|
553
|
-
Ably::Realtime::Client.new(client_options)
|
|
567
|
+
auto_close Ably::Realtime::Client.new(client_options)
|
|
554
568
|
end.each do |client|
|
|
555
569
|
channel = client.channels.get(channel_name)
|
|
556
570
|
messages.each do |message|
|
|
@@ -666,7 +680,8 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
666
680
|
context 'an :attached channel' do
|
|
667
681
|
it 'transitions state to :failed' do
|
|
668
682
|
channel.attach do
|
|
669
|
-
channel.on(:failed) do |
|
|
683
|
+
channel.on(:failed) do |connection_state_change|
|
|
684
|
+
error = connection_state_change.reason
|
|
670
685
|
expect(error).to be_a(Ably::Exceptions::ConnectionFailed)
|
|
671
686
|
expect(error.code).to eql(80002)
|
|
672
687
|
stop_reactor
|
|
@@ -688,7 +703,8 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
688
703
|
|
|
689
704
|
it 'updates the channel error_reason' do
|
|
690
705
|
channel.attach do
|
|
691
|
-
channel.on(:failed) do |
|
|
706
|
+
channel.on(:failed) do |connection_state_change|
|
|
707
|
+
error = connection_state_change.reason
|
|
692
708
|
expect(error).to be_a(Ably::Exceptions::ConnectionFailed)
|
|
693
709
|
expect(error.code).to eql(80002)
|
|
694
710
|
stop_reactor
|
|
@@ -734,7 +750,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
734
750
|
fake_error connection_error
|
|
735
751
|
end
|
|
736
752
|
|
|
737
|
-
channel.transition_state_machine :failed, original_error
|
|
753
|
+
channel.transition_state_machine :failed, reason: original_error
|
|
738
754
|
end
|
|
739
755
|
end
|
|
740
756
|
end
|
|
@@ -783,8 +799,8 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
783
799
|
end
|
|
784
800
|
|
|
785
801
|
context 'a :failed channel' do
|
|
786
|
-
let(:original_error) { RuntimeError.new }
|
|
787
802
|
let(:client_options) { default_options.merge(log_level: :fatal) }
|
|
803
|
+
let(:original_error) { Ably::Models::ErrorInfo.new(message: 'Error') }
|
|
788
804
|
|
|
789
805
|
it 'remains in the :failed state and retains the error_reason' do
|
|
790
806
|
channel.attach do
|
|
@@ -801,7 +817,7 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
801
817
|
client.connection.close
|
|
802
818
|
end
|
|
803
819
|
|
|
804
|
-
channel.transition_state_machine :failed, original_error
|
|
820
|
+
channel.transition_state_machine :failed, reason: original_error
|
|
805
821
|
end
|
|
806
822
|
end
|
|
807
823
|
end
|
|
@@ -830,6 +846,75 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
830
846
|
end
|
|
831
847
|
end
|
|
832
848
|
end
|
|
849
|
+
|
|
850
|
+
context ':suspended' do
|
|
851
|
+
context 'an :attached channel' do
|
|
852
|
+
let(:client_options) { default_options.merge(log_level: :fatal) }
|
|
853
|
+
|
|
854
|
+
it 'transitions state to :detached' do
|
|
855
|
+
channel.attach do
|
|
856
|
+
channel.on(:detached) do
|
|
857
|
+
stop_reactor
|
|
858
|
+
end
|
|
859
|
+
client.connection.transition_state_machine :suspended
|
|
860
|
+
end
|
|
861
|
+
end
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
context 'a :detached channel' do
|
|
865
|
+
it 'remains in the :detached state' do
|
|
866
|
+
channel.attach do
|
|
867
|
+
channel.detach do
|
|
868
|
+
channel.on(:detached) { raise 'Detached state should not have been reached' }
|
|
869
|
+
channel.on(:error) { raise 'Error should not have been emitted' }
|
|
870
|
+
|
|
871
|
+
EventMachine.add_timer(1) do
|
|
872
|
+
expect(channel).to be_detached
|
|
873
|
+
stop_reactor
|
|
874
|
+
end
|
|
875
|
+
|
|
876
|
+
client.connection.transition_state_machine :suspended
|
|
877
|
+
end
|
|
878
|
+
end
|
|
879
|
+
end
|
|
880
|
+
end
|
|
881
|
+
|
|
882
|
+
context 'a :failed channel' do
|
|
883
|
+
let(:original_error) { RuntimeError.new }
|
|
884
|
+
let(:client_options) { default_options.merge(log_level: :fatal) }
|
|
885
|
+
|
|
886
|
+
it 'remains in the :failed state and retains the error_reason' do
|
|
887
|
+
channel.attach do
|
|
888
|
+
channel.once(:error) do
|
|
889
|
+
channel.on(:detached) { raise 'Detached state should not have been reached' }
|
|
890
|
+
channel.on(:error) { raise 'Error should not have been emitted' }
|
|
891
|
+
|
|
892
|
+
EventMachine.add_timer(1) do
|
|
893
|
+
expect(channel).to be_failed
|
|
894
|
+
expect(channel.error_reason).to eql(original_error)
|
|
895
|
+
stop_reactor
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
client.connection.transition_state_machine :suspended
|
|
899
|
+
end
|
|
900
|
+
|
|
901
|
+
channel.transition_state_machine :failed, reason: original_error
|
|
902
|
+
end
|
|
903
|
+
end
|
|
904
|
+
end
|
|
905
|
+
|
|
906
|
+
context 'a channel ATTACH request when connection SUSPENDED' do
|
|
907
|
+
it 'raises an exception' do
|
|
908
|
+
client.connect do
|
|
909
|
+
client.connection.once(:suspended) do
|
|
910
|
+
expect { channel.attach }.to raise_error Ably::Exceptions::InvalidStateChange
|
|
911
|
+
stop_reactor
|
|
912
|
+
end
|
|
913
|
+
client.connection.transition_state_machine :suspended
|
|
914
|
+
end
|
|
915
|
+
end
|
|
916
|
+
end
|
|
917
|
+
end
|
|
833
918
|
end
|
|
834
919
|
|
|
835
920
|
describe '#presence' do
|
|
@@ -838,5 +923,67 @@ describe Ably::Realtime::Channel, :event_machine do
|
|
|
838
923
|
stop_reactor
|
|
839
924
|
end
|
|
840
925
|
end
|
|
926
|
+
|
|
927
|
+
context 'channel state change' do
|
|
928
|
+
it 'emits a ChannelStateChange object' do
|
|
929
|
+
channel.on(:attached) do |channel_state_change|
|
|
930
|
+
expect(channel_state_change).to be_a(Ably::Models::ChannelStateChange)
|
|
931
|
+
stop_reactor
|
|
932
|
+
end
|
|
933
|
+
channel.attach
|
|
934
|
+
end
|
|
935
|
+
|
|
936
|
+
context 'ChannelStateChange object' do
|
|
937
|
+
it 'has current state' do
|
|
938
|
+
channel.on(:attached) do |channel_state_change|
|
|
939
|
+
expect(channel_state_change.current).to eq(:attached)
|
|
940
|
+
stop_reactor
|
|
941
|
+
end
|
|
942
|
+
channel.attach
|
|
943
|
+
end
|
|
944
|
+
|
|
945
|
+
it 'has a previous state' do
|
|
946
|
+
channel.on(:attached) do |channel_state_change|
|
|
947
|
+
expect(channel_state_change.previous).to eq(:attaching)
|
|
948
|
+
stop_reactor
|
|
949
|
+
end
|
|
950
|
+
channel.attach
|
|
951
|
+
end
|
|
952
|
+
|
|
953
|
+
it 'contains a private API protocol_message attribute that is used for special state change events', :api_private do
|
|
954
|
+
channel.on(:attached) do |channel_state_change|
|
|
955
|
+
expect(channel_state_change.protocol_message).to be_a(Ably::Models::ProtocolMessage)
|
|
956
|
+
expect(channel_state_change.reason).to be_nil
|
|
957
|
+
stop_reactor
|
|
958
|
+
end
|
|
959
|
+
channel.attach
|
|
960
|
+
end
|
|
961
|
+
|
|
962
|
+
it 'has an empty reason when there is no error' do
|
|
963
|
+
channel.on(:detached) do |channel_state_change|
|
|
964
|
+
expect(channel_state_change.reason).to be_nil
|
|
965
|
+
stop_reactor
|
|
966
|
+
end
|
|
967
|
+
channel.attach do
|
|
968
|
+
channel.detach
|
|
969
|
+
end
|
|
970
|
+
end
|
|
971
|
+
|
|
972
|
+
context 'on failure' do
|
|
973
|
+
let(:client_options) { default_options.merge(log_level: :none) }
|
|
974
|
+
|
|
975
|
+
it 'has a reason Error object when there is an error on the channel' do
|
|
976
|
+
channel.on(:failed) do |channel_state_change|
|
|
977
|
+
expect(channel_state_change.reason).to be_a(Ably::Exceptions::BaseAblyException)
|
|
978
|
+
stop_reactor
|
|
979
|
+
end
|
|
980
|
+
channel.attach do
|
|
981
|
+
error = Ably::Exceptions::ConnectionFailed.new('forced failure', 500, 50000)
|
|
982
|
+
client.connection.manager.error_received_from_server error
|
|
983
|
+
end
|
|
984
|
+
end
|
|
985
|
+
end
|
|
986
|
+
end
|
|
987
|
+
end
|
|
841
988
|
end
|
|
842
989
|
end
|