ably 0.6.2 → 0.7.0
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/.rspec +1 -0
- data/.ruby-version.old +1 -0
- data/.travis.yml +0 -2
- data/Rakefile +22 -4
- data/SPEC.md +1676 -0
- data/ably.gemspec +1 -1
- data/lib/ably.rb +0 -8
- data/lib/ably/auth.rb +54 -46
- data/lib/ably/exceptions.rb +19 -5
- data/lib/ably/logger.rb +1 -1
- data/lib/ably/models/error_info.rb +1 -1
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +11 -9
- data/lib/ably/models/message.rb +15 -12
- data/lib/ably/models/message_encoders/base.rb +6 -5
- data/lib/ably/models/message_encoders/base64.rb +1 -0
- data/lib/ably/models/message_encoders/cipher.rb +6 -3
- data/lib/ably/models/message_encoders/json.rb +1 -0
- data/lib/ably/models/message_encoders/utf8.rb +2 -9
- data/lib/ably/models/nil_logger.rb +20 -0
- data/lib/ably/models/paginated_resource.rb +5 -2
- data/lib/ably/models/presence_message.rb +21 -12
- data/lib/ably/models/protocol_message.rb +22 -6
- data/lib/ably/modules/ably.rb +11 -0
- data/lib/ably/modules/async_wrapper.rb +2 -0
- data/lib/ably/modules/conversions.rb +23 -3
- data/lib/ably/modules/encodeable.rb +2 -1
- data/lib/ably/modules/enum.rb +2 -0
- data/lib/ably/modules/event_emitter.rb +7 -1
- data/lib/ably/modules/event_machine_helpers.rb +2 -0
- data/lib/ably/modules/http_helpers.rb +2 -0
- data/lib/ably/modules/model_common.rb +12 -2
- data/lib/ably/modules/state_emitter.rb +76 -0
- data/lib/ably/modules/state_machine.rb +53 -0
- data/lib/ably/modules/statesman_monkey_patch.rb +33 -0
- data/lib/ably/modules/uses_state_machine.rb +74 -0
- data/lib/ably/realtime.rb +4 -2
- data/lib/ably/realtime/channel.rb +51 -58
- data/lib/ably/realtime/channel/channel_manager.rb +91 -0
- data/lib/ably/realtime/channel/channel_state_machine.rb +68 -0
- data/lib/ably/realtime/client.rb +70 -26
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +31 -13
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
- data/lib/ably/realtime/connection.rb +135 -92
- data/lib/ably/realtime/connection/connection_manager.rb +216 -33
- data/lib/ably/realtime/connection/connection_state_machine.rb +30 -73
- data/lib/ably/realtime/models/nil_channel.rb +10 -1
- data/lib/ably/realtime/presence.rb +336 -92
- data/lib/ably/rest.rb +2 -2
- data/lib/ably/rest/channel.rb +13 -4
- data/lib/ably/rest/client.rb +138 -38
- data/lib/ably/rest/middleware/logger.rb +24 -3
- data/lib/ably/rest/presence.rb +12 -7
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/channel_history_spec.rb +101 -85
- data/spec/acceptance/realtime/channel_spec.rb +461 -120
- data/spec/acceptance/realtime/client_spec.rb +119 -0
- data/spec/acceptance/realtime/connection_failures_spec.rb +499 -0
- data/spec/acceptance/realtime/connection_spec.rb +571 -97
- data/spec/acceptance/realtime/message_spec.rb +347 -333
- data/spec/acceptance/realtime/presence_history_spec.rb +35 -40
- data/spec/acceptance/realtime/presence_spec.rb +769 -239
- data/spec/acceptance/realtime/stats_spec.rb +14 -22
- data/spec/acceptance/realtime/time_spec.rb +16 -20
- data/spec/acceptance/rest/auth_spec.rb +425 -364
- data/spec/acceptance/rest/base_spec.rb +108 -176
- data/spec/acceptance/rest/channel_spec.rb +89 -89
- data/spec/acceptance/rest/channels_spec.rb +30 -32
- data/spec/acceptance/rest/client_spec.rb +273 -0
- data/spec/acceptance/rest/encoders_spec.rb +185 -0
- data/spec/acceptance/rest/message_spec.rb +186 -163
- data/spec/acceptance/rest/presence_spec.rb +150 -111
- data/spec/acceptance/rest/stats_spec.rb +45 -40
- data/spec/acceptance/rest/time_spec.rb +8 -10
- data/spec/rspec_config.rb +10 -1
- data/spec/shared/client_initializer_behaviour.rb +212 -0
- data/spec/{support/model_helper.rb → shared/model_behaviour.rb} +6 -6
- data/spec/{support/protocol_msgbus_helper.rb → shared/protocol_msgbus_behaviour.rb} +1 -1
- data/spec/spec_helper.rb +9 -0
- data/spec/support/api_helper.rb +11 -0
- data/spec/support/event_machine_helper.rb +101 -3
- data/spec/support/markdown_spec_formatter.rb +90 -0
- data/spec/support/private_api_formatter.rb +36 -0
- data/spec/support/protocol_helper.rb +32 -0
- data/spec/support/random_helper.rb +15 -0
- data/spec/support/test_app.rb +4 -0
- data/spec/unit/auth_spec.rb +68 -0
- data/spec/unit/logger_spec.rb +77 -66
- data/spec/unit/models/error_info_spec.rb +1 -1
- data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +2 -3
- data/spec/unit/models/message_encoders/base64_spec.rb +2 -2
- data/spec/unit/models/message_encoders/cipher_spec.rb +2 -2
- data/spec/unit/models/message_encoders/utf8_spec.rb +2 -46
- data/spec/unit/models/message_spec.rb +160 -15
- data/spec/unit/models/paginated_resource_spec.rb +29 -27
- data/spec/unit/models/presence_message_spec.rb +163 -20
- data/spec/unit/models/protocol_message_spec.rb +43 -8
- data/spec/unit/modules/async_wrapper_spec.rb +2 -3
- data/spec/unit/modules/conversions_spec.rb +1 -1
- data/spec/unit/modules/enum_spec.rb +2 -3
- data/spec/unit/modules/event_emitter_spec.rb +62 -5
- data/spec/unit/modules/state_emitter_spec.rb +283 -0
- data/spec/unit/realtime/channel_spec.rb +107 -2
- data/spec/unit/realtime/channels_spec.rb +1 -0
- data/spec/unit/realtime/client_spec.rb +8 -48
- data/spec/unit/realtime/connection_spec.rb +3 -3
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +2 -2
- data/spec/unit/realtime/presence_spec.rb +13 -4
- data/spec/unit/realtime/realtime_spec.rb +0 -11
- data/spec/unit/realtime/websocket_transport_spec.rb +2 -2
- data/spec/unit/rest/channel_spec.rb +109 -0
- data/spec/unit/rest/channels_spec.rb +4 -3
- data/spec/unit/rest/client_spec.rb +30 -125
- data/spec/unit/rest/rest_spec.rb +10 -0
- data/spec/unit/util/crypto_spec.rb +10 -5
- data/spec/unit/util/pub_sub_spec.rb +5 -5
- metadata +44 -12
- data/spec/integration/modules/state_emitter_spec.rb +0 -80
- data/spec/integration/rest/auth.rb +0 -9
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'securerandom'
|
3
2
|
|
4
|
-
describe Ably::Models::IdiomaticRubyWrapper do
|
3
|
+
describe Ably::Models::IdiomaticRubyWrapper, :api_private do
|
5
4
|
include Ably::Modules::Conversions
|
6
5
|
|
7
6
|
let(:mixed_case_data) do
|
@@ -107,7 +106,7 @@ describe Ably::Models::IdiomaticRubyWrapper do
|
|
107
106
|
'lowercasestring' => 'lowercasestringValue'
|
108
107
|
}
|
109
108
|
end
|
110
|
-
let(:unique_value) {
|
109
|
+
let(:unique_value) { random_str }
|
111
110
|
|
112
111
|
subject { Ably::Models::IdiomaticRubyWrapper.new(data) }
|
113
112
|
|
@@ -5,7 +5,7 @@ require 'msgpack'
|
|
5
5
|
require 'ably/models/message_encoders/base64'
|
6
6
|
|
7
7
|
describe Ably::Models::MessageEncoders::Base64 do
|
8
|
-
let(:decoded_data) {
|
8
|
+
let(:decoded_data) { random_str(32) }
|
9
9
|
let(:base64_data) { Base64.encode64(decoded_data) }
|
10
10
|
let(:binary_data) { MessagePack.pack(decoded_data) }
|
11
11
|
let(:base64_binary_data) { Base64.encode64(binary_data) }
|
@@ -111,7 +111,7 @@ describe Ably::Models::MessageEncoders::Base64 do
|
|
111
111
|
end
|
112
112
|
|
113
113
|
context 'message with empty binary string payload' do
|
114
|
-
let(:message) { { data: ''.
|
114
|
+
let(:message) { { data: ''.encode(Encoding::ASCII_8BIT), encoding: nil } }
|
115
115
|
|
116
116
|
it 'leaves the message data intact' do
|
117
117
|
expect(message[:data]).to eql('')
|
@@ -3,11 +3,11 @@ require 'ably/models/message_encoders/cipher'
|
|
3
3
|
require 'msgpack'
|
4
4
|
|
5
5
|
describe Ably::Models::MessageEncoders::Cipher do
|
6
|
-
let(:secret_key) {
|
6
|
+
let(:secret_key) { random_str(64) }
|
7
7
|
let(:crypto_options) { { key: secret_key, algorithm: 'AES', mode: 'CBC', key_length: 128 } }
|
8
8
|
let(:crypto) { Ably::Util::Crypto.new(cipher_params) }
|
9
9
|
|
10
|
-
let(:decoded_data) {
|
10
|
+
let(:decoded_data) { random_str(32) }
|
11
11
|
let(:cipher_data) { crypto.encrypt(decoded_data) }
|
12
12
|
|
13
13
|
let(:binary_data) { MessagePack.pack(decoded_data) }
|
@@ -3,8 +3,8 @@ require 'spec_helper'
|
|
3
3
|
require 'ably/models/message_encoders/utf8'
|
4
4
|
|
5
5
|
describe Ably::Models::MessageEncoders::Utf8 do
|
6
|
-
let(:string_ascii) { 'string'.
|
7
|
-
let(:string_utf8) { 'string'.
|
6
|
+
let(:string_ascii) { 'string'.encode(Encoding::ASCII_8BIT) }
|
7
|
+
let(:string_utf8) { 'string'.encode(Encoding::UTF_8) }
|
8
8
|
|
9
9
|
let(:client) { instance_double('Ably::Realtime::Client') }
|
10
10
|
|
@@ -53,48 +53,4 @@ describe Ably::Models::MessageEncoders::Utf8 do
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
56
|
-
|
57
|
-
context '#encode' do
|
58
|
-
before do
|
59
|
-
subject.encode message, {}
|
60
|
-
end
|
61
|
-
|
62
|
-
context 'message with json payload' do
|
63
|
-
let(:message) { { data: string_ascii, encoding: 'json' } }
|
64
|
-
|
65
|
-
it 'sets the cencoding' do
|
66
|
-
expect(message[:data]).to eql(string_utf8)
|
67
|
-
expect(message[:data].encoding).to eql(Encoding::UTF_8)
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'adds the encoding' do
|
71
|
-
expect(message[:encoding]).to eql('json/utf-8')
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
|
76
|
-
context 'message with string payload and no encoding' do
|
77
|
-
let(:message) { { data: string_ascii, encoding: nil } }
|
78
|
-
|
79
|
-
it 'leaves the message data intact' do
|
80
|
-
expect(message[:data]).to eql(string_ascii)
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'leaves the encoding intact' do
|
84
|
-
expect(message[:encoding]).to eql(nil)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
context 'message with string payload and UTF-8 encoding' do
|
89
|
-
let(:message) { { data: string_ascii, encoding: 'utf-8' } }
|
90
|
-
|
91
|
-
it 'leaves the message data intact' do
|
92
|
-
expect(message[:data]).to eql(string_ascii)
|
93
|
-
end
|
94
|
-
|
95
|
-
it 'leaves the encoding intact' do
|
96
|
-
expect(message[:encoding]).to eql('utf-8')
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
56
|
end
|
@@ -1,5 +1,6 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
require 'spec_helper'
|
2
|
-
require '
|
3
|
+
require 'shared/model_behaviour'
|
3
4
|
require 'base64'
|
4
5
|
require 'msgpack'
|
5
6
|
|
@@ -16,13 +17,56 @@ describe Ably::Models::Message do
|
|
16
17
|
|
17
18
|
context '#timestamp' do
|
18
19
|
let(:model) { subject.new({}, protocol_message) }
|
19
|
-
|
20
|
+
|
21
|
+
it 'retrieves attribute :timestamp as Time object from ProtocolMessage' do
|
20
22
|
expect(model.timestamp).to be_a(Time)
|
21
23
|
expect(model.timestamp.to_i).to be_within(1).of(Time.now.to_i)
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
25
|
-
context '
|
27
|
+
context '#connection_id attribute' do
|
28
|
+
let(:protocol_connection_id) { random_str }
|
29
|
+
let(:protocol_message) { Ably::Models::ProtocolMessage.new('connectionId' => protocol_connection_id, action: 1, timestamp: protocol_message_timestamp) }
|
30
|
+
let(:model_connection_id) { random_str }
|
31
|
+
|
32
|
+
context 'when this model has a connectionId attribute' do
|
33
|
+
context 'but no protocol message' do
|
34
|
+
let(:model) { subject.new('connectionId' => model_connection_id ) }
|
35
|
+
|
36
|
+
it 'uses the model value' do
|
37
|
+
expect(model.connection_id).to eql(model_connection_id)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with a protocol message with a different connectionId' do
|
42
|
+
let(:model) { subject.new({ 'connectionId' => model_connection_id }, protocol_message) }
|
43
|
+
|
44
|
+
it 'uses the model value' do
|
45
|
+
expect(model.connection_id).to eql(model_connection_id)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when this model has no connectionId attribute' do
|
51
|
+
context 'and no protocol message' do
|
52
|
+
let(:model) { subject.new({ }) }
|
53
|
+
|
54
|
+
it 'uses the model value' do
|
55
|
+
expect(model.connection_id).to be_nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'with a protocol message with a connectionId' do
|
60
|
+
let(:model) { subject.new({ }, protocol_message) }
|
61
|
+
|
62
|
+
it 'uses the model value' do
|
63
|
+
expect(model.connection_id).to eql(protocol_connection_id)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'Java naming', :api_private do
|
26
70
|
let(:model) { subject.new({ clientId: 'joe' }, protocol_message) }
|
27
71
|
|
28
72
|
it 'converts the attribute to ruby symbol naming convention' do
|
@@ -30,7 +74,71 @@ describe Ably::Models::Message do
|
|
30
74
|
end
|
31
75
|
end
|
32
76
|
|
33
|
-
context '
|
77
|
+
context 'initialized with' do
|
78
|
+
%w(name client_id encoding).each do |attribute|
|
79
|
+
context ":#{attribute}" do
|
80
|
+
let(:encoded_value) { value.encode(encoding) }
|
81
|
+
let(:value) { random_str }
|
82
|
+
let(:options) { { attribute.to_sym => encoded_value } }
|
83
|
+
let(:model) { subject.new(options, protocol_message) }
|
84
|
+
let(:model_attribute) { model.public_send(attribute) }
|
85
|
+
|
86
|
+
context 'as UTF_8 string' do
|
87
|
+
let(:encoding) { Encoding::UTF_8 }
|
88
|
+
|
89
|
+
it 'is permitted' do
|
90
|
+
expect(model_attribute).to eql(encoded_value)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'remains as UTF-8' do
|
94
|
+
expect(model_attribute.encoding).to eql(encoding)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'as SHIFT_JIS string' do
|
99
|
+
let(:encoding) { Encoding::SHIFT_JIS }
|
100
|
+
|
101
|
+
it 'gets converted to UTF-8' do
|
102
|
+
expect(model_attribute.encoding).to eql(Encoding::UTF_8)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'is compatible with original encoding' do
|
106
|
+
expect(model_attribute.encode(encoding)).to eql(encoded_value)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'as ASCII_8BIT string' do
|
111
|
+
let(:encoding) { Encoding::ASCII_8BIT }
|
112
|
+
|
113
|
+
it 'gets converted to UTF-8' do
|
114
|
+
expect(model_attribute.encoding).to eql(Encoding::UTF_8)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'is compatible with original encoding' do
|
118
|
+
expect(model_attribute.encode(encoding)).to eql(encoded_value)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'as Integer' do
|
123
|
+
let(:encoded_value) { 1 }
|
124
|
+
|
125
|
+
it 'raises an argument error' do
|
126
|
+
expect { model_attribute }.to raise_error ArgumentError, /must be a String/
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'as Nil' do
|
131
|
+
let(:encoded_value) { nil }
|
132
|
+
|
133
|
+
it 'is permitted' do
|
134
|
+
expect(model_attribute).to be_nil
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context '#to_json', :api_private do
|
34
142
|
let(:json_object) { JSON.parse(model.to_json) }
|
35
143
|
|
36
144
|
context 'with valid data' do
|
@@ -50,7 +158,7 @@ describe Ably::Models::Message do
|
|
50
158
|
end
|
51
159
|
|
52
160
|
context 'with binary data' do
|
53
|
-
let(:data) { MessagePack.pack(
|
161
|
+
let(:data) { MessagePack.pack(random_str(32)) }
|
54
162
|
let(:model) { subject.new({ name: 'test', data: data }, protocol_message) }
|
55
163
|
|
56
164
|
it 'encodes as Base64 so that it can be converted to UTF-8 automatically by JSON#dump' do
|
@@ -63,13 +171,25 @@ describe Ably::Models::Message do
|
|
63
171
|
end
|
64
172
|
end
|
65
173
|
|
66
|
-
context 'from REST request with embedded fields' do
|
67
|
-
let(:id)
|
68
|
-
let(:
|
69
|
-
let(:
|
70
|
-
let(:
|
174
|
+
context 'from REST request with embedded fields', :api_private do
|
175
|
+
let(:id) { random_str }
|
176
|
+
let(:protocol_message_id) { random_str }
|
177
|
+
let(:message_time) { Time.now + 60 }
|
178
|
+
let(:message_timestamp) { as_since_epoch(message_time) }
|
179
|
+
let(:protocol_time) { Time.now }
|
180
|
+
let(:protocol_timestamp) { as_since_epoch(protocol_time) }
|
181
|
+
|
182
|
+
let(:protocol_message) do
|
183
|
+
Ably::Models::ProtocolMessage.new({
|
184
|
+
action: :message,
|
185
|
+
timestamp: protocol_timestamp,
|
186
|
+
id: protocol_message_id
|
187
|
+
})
|
188
|
+
end
|
71
189
|
|
72
190
|
context 'with protocol message' do
|
191
|
+
let(:model) { subject.new({ id: id, timestamp: message_timestamp }, protocol_message) }
|
192
|
+
|
73
193
|
specify '#id prefers embedded ID' do
|
74
194
|
expect(model.id).to eql(id)
|
75
195
|
end
|
@@ -80,6 +200,8 @@ describe Ably::Models::Message do
|
|
80
200
|
end
|
81
201
|
|
82
202
|
context 'without protocol message' do
|
203
|
+
let(:model) { subject.new(id: id, timestamp: message_timestamp) }
|
204
|
+
|
83
205
|
specify '#id uses embedded ID' do
|
84
206
|
expect(model.id).to eql(id)
|
85
207
|
end
|
@@ -90,10 +212,10 @@ describe Ably::Models::Message do
|
|
90
212
|
end
|
91
213
|
end
|
92
214
|
|
93
|
-
context 'part of ProtocolMessage' do
|
215
|
+
context 'part of ProtocolMessage', :api_private do
|
94
216
|
let(:ably_time) { Time.now + 5 }
|
95
|
-
let(:message_serial) {
|
96
|
-
let(:connection_id) {
|
217
|
+
let(:message_serial) { random_int_str(1_000_000) }
|
218
|
+
let(:connection_id) { random_str }
|
97
219
|
|
98
220
|
let(:message_0_payload) do
|
99
221
|
{
|
@@ -117,7 +239,7 @@ describe Ably::Models::Message do
|
|
117
239
|
}
|
118
240
|
end
|
119
241
|
|
120
|
-
let(:protocol_message_id) {
|
242
|
+
let(:protocol_message_id) { random_str }
|
121
243
|
let(:protocol_message) do
|
122
244
|
Ably::Models::ProtocolMessage.new({
|
123
245
|
action: :message,
|
@@ -150,9 +272,32 @@ describe Ably::Models::Message do
|
|
150
272
|
it 'should not allow changes to the payload' do
|
151
273
|
expect { message_0.data["test"] = true }.to raise_error RuntimeError, /can't modify frozen Hash/
|
152
274
|
end
|
275
|
+
|
276
|
+
context 'with identical message objects' do
|
277
|
+
let(:protocol_message) do
|
278
|
+
Ably::Models::ProtocolMessage.new({
|
279
|
+
action: :message,
|
280
|
+
timestamp: ably_time.to_i,
|
281
|
+
msg_serial: message_serial,
|
282
|
+
id: protocol_message_id,
|
283
|
+
messages: [
|
284
|
+
message_0_json, message_0_json, message_0_json
|
285
|
+
]
|
286
|
+
})
|
287
|
+
end
|
288
|
+
|
289
|
+
it 'provide a unique ID:index' do
|
290
|
+
expect(protocol_message.messages.map(&:id).uniq.count).to eql(3)
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'recognises the index based on the object ID as opposed to message payload' do
|
294
|
+
expect(protocol_message.messages.first.id).to match(/0$/)
|
295
|
+
expect(protocol_message.messages.last.id).to match(/2$/)
|
296
|
+
end
|
297
|
+
end
|
153
298
|
end
|
154
299
|
|
155
|
-
context 'Message conversion method' do
|
300
|
+
context 'Message conversion method', :api_private do
|
156
301
|
let(:json) { { name: 'test', data: 'conversion' } }
|
157
302
|
|
158
303
|
context 'with JSON' do
|
@@ -58,7 +58,7 @@ describe Ably::Models::PaginatedResource do
|
|
58
58
|
expect(subject.last[:id]).to eql(body[1][:id])
|
59
59
|
end
|
60
60
|
|
61
|
-
context 'with coercion' do
|
61
|
+
context 'with coercion', :api_private do
|
62
62
|
let(:paginated_resource_options) { { coerce_into: 'OpenStruct' } }
|
63
63
|
|
64
64
|
it 'returns coerced objects' do
|
@@ -67,7 +67,7 @@ describe Ably::Models::PaginatedResource do
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
context 'paged transformations' do
|
70
|
+
context 'paged transformations', :api_private do
|
71
71
|
let(:headers) do
|
72
72
|
{
|
73
73
|
'link' => [
|
@@ -114,43 +114,45 @@ describe Ably::Models::PaginatedResource do
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
117
|
-
|
118
|
-
|
117
|
+
if defined?(EventMachine)
|
118
|
+
context 'with option async_blocking_operations: true' do
|
119
|
+
include RSpec::EventMachine
|
119
120
|
|
120
|
-
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
context '#next_page' do
|
125
|
-
it 'returns a deferrable object' do
|
126
|
-
run_reactor do
|
127
|
-
expect(subject.next_page).to be_a(EventMachine::Deferrable)
|
128
|
-
stop_reactor
|
129
|
-
end
|
121
|
+
subject do
|
122
|
+
paginated_resource_class.new(http_response, full_url, paged_client, async_blocking_operations: true)
|
130
123
|
end
|
131
124
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
expect(
|
125
|
+
context '#next_page' do
|
126
|
+
it 'returns a deferrable object' do
|
127
|
+
run_reactor do
|
128
|
+
expect(subject.next_page).to be_a(EventMachine::Deferrable)
|
136
129
|
stop_reactor
|
137
130
|
end
|
138
131
|
end
|
139
|
-
end
|
140
|
-
end
|
141
132
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
deferrable = subject.first_page
|
147
|
-
deferrable.errback do |error|
|
148
|
-
expect(error).to be_a(Ably::Exceptions::InvalidPageError)
|
133
|
+
it 'allows a success callback block to be added' do
|
134
|
+
run_reactor do
|
135
|
+
subject.next_page do |paginated_resource|
|
136
|
+
expect(paginated_resource).to be_a(Ably::Models::PaginatedResource)
|
149
137
|
stop_reactor
|
150
138
|
end
|
151
139
|
end
|
152
140
|
end
|
153
141
|
end
|
142
|
+
|
143
|
+
context '#first_page' do
|
144
|
+
it 'calls the errback callback when first page headers are missing' do
|
145
|
+
run_reactor do
|
146
|
+
subject.next_page do |paginated_resource|
|
147
|
+
deferrable = subject.first_page
|
148
|
+
deferrable.errback do |error|
|
149
|
+
expect(error).to be_a(Ably::Exceptions::InvalidPageError)
|
150
|
+
stop_reactor
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
154
156
|
end
|
155
157
|
end
|
156
158
|
end
|
@@ -1,5 +1,6 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
require 'spec_helper'
|
2
|
-
require '
|
3
|
+
require 'shared/model_behaviour'
|
3
4
|
|
4
5
|
describe Ably::Models::PresenceMessage do
|
5
6
|
include Ably::Modules::Conversions
|
@@ -8,19 +9,87 @@ describe Ably::Models::PresenceMessage do
|
|
8
9
|
let(:protocol_message_timestamp) { as_since_epoch(Time.now) }
|
9
10
|
let(:protocol_message) { Ably::Models::ProtocolMessage.new(action: 1, timestamp: protocol_message_timestamp) }
|
10
11
|
|
11
|
-
it_behaves_like 'a model', with_simple_attributes: %w(client_id
|
12
|
+
it_behaves_like 'a model', with_simple_attributes: %w(client_id data encoding) do
|
12
13
|
let(:model_args) { [protocol_message] }
|
13
14
|
end
|
14
15
|
|
16
|
+
context '#connection_id attribute' do
|
17
|
+
let(:protocol_connection_id) { random_str }
|
18
|
+
let(:protocol_message) { Ably::Models::ProtocolMessage.new('connectionId' => protocol_connection_id, action: 1, timestamp: protocol_message_timestamp) }
|
19
|
+
let(:model_connection_id) { random_str }
|
20
|
+
|
21
|
+
context 'when this model has a connectionId attribute' do
|
22
|
+
context 'but no protocol message' do
|
23
|
+
let(:model) { subject.new('connectionId' => model_connection_id ) }
|
24
|
+
|
25
|
+
it 'uses the model value' do
|
26
|
+
expect(model.connection_id).to eql(model_connection_id)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'with a protocol message with a different connectionId' do
|
31
|
+
let(:model) { subject.new({ 'connectionId' => model_connection_id }, protocol_message) }
|
32
|
+
|
33
|
+
it 'uses the model value' do
|
34
|
+
expect(model.connection_id).to eql(model_connection_id)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when this model has no connectionId attribute' do
|
40
|
+
context 'and no protocol message' do
|
41
|
+
let(:model) { subject.new({ }) }
|
42
|
+
|
43
|
+
it 'uses the model value' do
|
44
|
+
expect(model.connection_id).to be_nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'with a protocol message with a connectionId' do
|
49
|
+
let(:model) { subject.new({ }, protocol_message) }
|
50
|
+
|
51
|
+
it 'uses the model value' do
|
52
|
+
expect(model.connection_id).to eql(protocol_connection_id)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context '#member_key attribute' do
|
59
|
+
let(:model) { subject.new(client_id: 'client_id', connection_id: 'connection_id') }
|
60
|
+
|
61
|
+
it 'is string in format connection_id:client_id' do
|
62
|
+
expect(model.member_key).to eql('connection_id:client_id')
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with the same client id across multiple connections' do
|
66
|
+
let(:connection_1) { subject.new({ client_id: 'same', connection_id: 'unique' }, protocol_message) }
|
67
|
+
let(:connection_2) { subject.new({ client_id: 'same', connection_id: 'different' }, protocol_message) }
|
68
|
+
|
69
|
+
it 'is unique' do
|
70
|
+
expect(connection_1.member_key).to_not eql(connection_2.member_key)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'with a single connection and different client_ids' do
|
75
|
+
let(:client_1) { subject.new({ client_id: 'unique', connection_id: 'same' }, protocol_message) }
|
76
|
+
let(:client_2) { subject.new({ client_id: 'different', connection_id: 'same' }, protocol_message) }
|
77
|
+
|
78
|
+
it 'is unique' do
|
79
|
+
expect(client_1.member_key).to_not eql(client_2.member_key)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
15
84
|
context '#timestamp' do
|
16
85
|
let(:model) { subject.new({}, protocol_message) }
|
17
|
-
it 'retrieves attribute :timestamp from ProtocolMessage' do
|
86
|
+
it 'retrieves attribute :timestamp as a Time object from ProtocolMessage' do
|
18
87
|
expect(model.timestamp).to be_a(Time)
|
19
88
|
expect(model.timestamp.to_i).to be_within(1).of(Time.now.to_i)
|
20
89
|
end
|
21
90
|
end
|
22
91
|
|
23
|
-
context 'Java naming' do
|
92
|
+
context 'Java naming', :api_private do
|
24
93
|
let(:model) { subject.new({ clientId: 'joe' }, protocol_message) }
|
25
94
|
|
26
95
|
it 'converts the attribute to ruby symbol naming convention' do
|
@@ -28,15 +97,25 @@ describe Ably::Models::PresenceMessage do
|
|
28
97
|
end
|
29
98
|
end
|
30
99
|
|
31
|
-
context 'with action' do
|
32
|
-
|
100
|
+
context 'with action', :api_private do
|
101
|
+
context 'absent' do
|
102
|
+
let(:model) { subject.new({ action: 0 }, protocol_message) }
|
103
|
+
|
104
|
+
it 'provides action as an Enum' do
|
105
|
+
expect(model.action).to eq(:absent)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'enter' do
|
110
|
+
let(:model) { subject.new({ action: 2 }, protocol_message) }
|
33
111
|
|
34
|
-
|
35
|
-
|
112
|
+
it 'provides action as an Enum' do
|
113
|
+
expect(model.action).to eq(:enter)
|
114
|
+
end
|
36
115
|
end
|
37
116
|
end
|
38
117
|
|
39
|
-
context 'without action' do
|
118
|
+
context 'without action', :api_private do
|
40
119
|
let(:model) { subject.new({}, protocol_message) }
|
41
120
|
|
42
121
|
it 'raises an exception when accessed' do
|
@@ -44,7 +123,71 @@ describe Ably::Models::PresenceMessage do
|
|
44
123
|
end
|
45
124
|
end
|
46
125
|
|
47
|
-
context '
|
126
|
+
context 'initialized with' do
|
127
|
+
%w(client_id connection_id encoding).each do |attribute|
|
128
|
+
context ":#{attribute}" do
|
129
|
+
let(:encoded_value) { value.encode(encoding) }
|
130
|
+
let(:value) { random_str }
|
131
|
+
let(:options) { { attribute.to_sym => encoded_value } }
|
132
|
+
let(:model) { subject.new(options, protocol_message) }
|
133
|
+
let(:model_attribute) { model.public_send(attribute) }
|
134
|
+
|
135
|
+
context 'as UTF_8 string' do
|
136
|
+
let(:encoding) { Encoding::UTF_8 }
|
137
|
+
|
138
|
+
it 'is permitted' do
|
139
|
+
expect(model_attribute).to eql(encoded_value)
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'remains as UTF-8' do
|
143
|
+
expect(model_attribute.encoding).to eql(Encoding::UTF_8)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'as SHIFT_JIS string' do
|
148
|
+
let(:encoding) { Encoding::SHIFT_JIS }
|
149
|
+
|
150
|
+
it 'gets converted to UTF-8' do
|
151
|
+
expect(model_attribute.encoding).to eql(Encoding::UTF_8)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'is compatible with original encoding' do
|
155
|
+
expect(model_attribute.encode(encoding)).to eql(encoded_value)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'as ASCII_8BIT string' do
|
160
|
+
let(:encoding) { Encoding::ASCII_8BIT }
|
161
|
+
|
162
|
+
it 'gets converted to UTF-8' do
|
163
|
+
expect(model_attribute.encoding).to eql(Encoding::UTF_8)
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'is compatible with original encoding' do
|
167
|
+
expect(model_attribute.encode(encoding)).to eql(encoded_value)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context 'as Integer' do
|
172
|
+
let(:encoded_value) { 1 }
|
173
|
+
|
174
|
+
it 'raises an argument error' do
|
175
|
+
expect { model_attribute }.to raise_error ArgumentError, /must be a String/
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'as Nil' do
|
180
|
+
let(:encoded_value) { nil }
|
181
|
+
|
182
|
+
it 'is permitted' do
|
183
|
+
expect(model_attribute).to be_nil
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
context '#to_json', :api_private do
|
48
191
|
let(:json_object) { JSON.parse(model.to_json) }
|
49
192
|
|
50
193
|
context 'with valid data' do
|
@@ -64,7 +207,7 @@ describe Ably::Models::PresenceMessage do
|
|
64
207
|
end
|
65
208
|
|
66
209
|
context 'with binary data' do
|
67
|
-
let(:data) { MessagePack.pack(
|
210
|
+
let(:data) { MessagePack.pack(random_str(32)) }
|
68
211
|
let(:model) { subject.new({ action: 'enter', data: data }, protocol_message) }
|
69
212
|
|
70
213
|
it 'encodes as Base64 so that it can be converted to UTF-8 automatically by JSON#dump' do
|
@@ -77,8 +220,8 @@ describe Ably::Models::PresenceMessage do
|
|
77
220
|
end
|
78
221
|
end
|
79
222
|
|
80
|
-
context 'from REST request with embedded fields' do
|
81
|
-
let(:id) {
|
223
|
+
context 'from REST request with embedded fields', :api_private do
|
224
|
+
let(:id) { random_str }
|
82
225
|
let(:message_time) { Time.now + 60 }
|
83
226
|
let(:timestamp) { as_since_epoch(message_time) }
|
84
227
|
let(:model) { subject.new(id: id, timestamp: timestamp) }
|
@@ -104,19 +247,19 @@ describe Ably::Models::PresenceMessage do
|
|
104
247
|
end
|
105
248
|
end
|
106
249
|
|
107
|
-
context 'part of ProtocolMessage' do
|
250
|
+
context 'part of ProtocolMessage', :api_private do
|
108
251
|
let(:ably_time) { Time.now + 5 }
|
109
|
-
let(:message_serial) {
|
110
|
-
let(:connection_id) {
|
252
|
+
let(:message_serial) { random_int_str(1_000_000) }
|
253
|
+
let(:connection_id) { random_str }
|
111
254
|
|
112
|
-
let(:presence_0_payload) {
|
255
|
+
let(:presence_0_payload) { random_str(8) }
|
113
256
|
let(:presence_0_json) do
|
114
257
|
{
|
115
258
|
client_id: 'zero',
|
116
259
|
data: presence_0_payload
|
117
260
|
}
|
118
261
|
end
|
119
|
-
let(:presence_1_payload) {
|
262
|
+
let(:presence_1_payload) { random_str(8) }
|
120
263
|
let(:presence_1_json) do
|
121
264
|
{
|
122
265
|
client_id: 'one',
|
@@ -124,7 +267,7 @@ describe Ably::Models::PresenceMessage do
|
|
124
267
|
}
|
125
268
|
end
|
126
269
|
|
127
|
-
let(:protocol_message_id) {
|
270
|
+
let(:protocol_message_id) { random_str }
|
128
271
|
let(:protocol_message) do
|
129
272
|
Ably::Models::ProtocolMessage.new({
|
130
273
|
action: :message,
|
@@ -151,7 +294,7 @@ describe Ably::Models::PresenceMessage do
|
|
151
294
|
end
|
152
295
|
end
|
153
296
|
|
154
|
-
context 'PresenceMessage conversion method' do
|
297
|
+
context 'PresenceMessage conversion method', :api_private do
|
155
298
|
let(:json) { { client_id: 'test' } }
|
156
299
|
|
157
300
|
context 'with JSON' do
|