ably-rest 0.7.1 → 0.7.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.
- checksums.yaml +13 -5
- data/.gitmodules +1 -1
- data/.rspec +1 -0
- data/.travis.yml +7 -3
- data/SPEC.md +495 -419
- data/ably-rest.gemspec +19 -5
- data/lib/ably-rest.rb +9 -1
- data/lib/submodules/ably-ruby/.gitignore +6 -0
- data/lib/submodules/ably-ruby/.rspec +1 -0
- data/lib/submodules/ably-ruby/.ruby-version.old +1 -0
- data/lib/submodules/ably-ruby/.travis.yml +10 -0
- data/lib/submodules/ably-ruby/Gemfile +4 -0
- data/lib/submodules/ably-ruby/LICENSE.txt +22 -0
- data/lib/submodules/ably-ruby/README.md +122 -0
- data/lib/submodules/ably-ruby/Rakefile +34 -0
- data/lib/submodules/ably-ruby/SPEC.md +1794 -0
- data/lib/submodules/ably-ruby/ably.gemspec +36 -0
- data/lib/submodules/ably-ruby/lib/ably.rb +12 -0
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +438 -0
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/logger.rb +102 -0
- data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +37 -0
- data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +223 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +132 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +108 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base64.rb +40 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/cipher.rb +83 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/json.rb +34 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/utf8.rb +26 -0
- data/lib/submodules/ably-ruby/lib/ably/models/nil_logger.rb +20 -0
- data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +173 -0
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +147 -0
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +210 -0
- data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +161 -0
- data/lib/submodules/ably-ruby/lib/ably/models/token.rb +74 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +15 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +62 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +100 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +202 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +128 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/event_machine_helpers.rb +26 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/http_helpers.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/message_pack.rb +14 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +153 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +57 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/statesman_monkey_patch.rb +33 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +74 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +64 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +298 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +92 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channels.rb +50 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +184 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +184 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +70 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +445 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +368 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +91 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +188 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/models/nil_channel.rb +30 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +564 -0
- data/lib/submodules/ably-ruby/lib/ably/rest.rb +43 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +104 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channels.rb +44 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +396 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/encoder.rb +49 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/external_exceptions.rb +24 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +17 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +58 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_json.rb +27 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +27 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +92 -0
- data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +105 -0
- data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +43 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +3 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +154 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +558 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +119 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +575 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +785 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +457 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +55 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +1001 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +23 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +27 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +564 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +165 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +134 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +41 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +273 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/encoders_spec.rb +185 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +247 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +292 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +172 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +15 -0
- data/lib/submodules/ably-ruby/spec/resources/crypto-data-128.json +56 -0
- data/lib/submodules/ably-ruby/spec/resources/crypto-data-256.json +56 -0
- data/lib/submodules/ably-ruby/spec/rspec_config.rb +57 -0
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +212 -0
- data/lib/submodules/ably-ruby/spec/shared/model_behaviour.rb +86 -0
- data/lib/submodules/ably-ruby/spec/shared/protocol_msgbus_behaviour.rb +36 -0
- data/lib/submodules/ably-ruby/spec/spec_helper.rb +20 -0
- data/lib/submodules/ably-ruby/spec/support/api_helper.rb +60 -0
- data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +104 -0
- data/lib/submodules/ably-ruby/spec/support/markdown_spec_formatter.rb +118 -0
- data/lib/submodules/ably-ruby/spec/support/private_api_formatter.rb +36 -0
- data/lib/submodules/ably-ruby/spec/support/protocol_helper.rb +32 -0
- data/lib/submodules/ably-ruby/spec/support/random_helper.rb +15 -0
- data/lib/submodules/ably-ruby/spec/support/rest_testapp_before_retry.rb +15 -0
- data/lib/submodules/ably-ruby/spec/support/test_app.rb +113 -0
- data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +68 -0
- data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +146 -0
- data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +18 -0
- data/lib/submodules/ably-ruby/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +349 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/base64_spec.rb +181 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/cipher_spec.rb +260 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/json_spec.rb +135 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/utf8_spec.rb +56 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +389 -0
- data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +288 -0
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +386 -0
- data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +315 -0
- data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +113 -0
- data/lib/submodules/ably-ruby/spec/unit/models/token_spec.rb +86 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +124 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/conversions_spec.rb +72 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +272 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +184 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +283 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +206 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +81 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +30 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +33 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +36 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +111 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/realtime_spec.rb +9 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/websocket_transport_spec.rb +25 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +109 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/channels_spec.rb +79 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +53 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/rest_spec.rb +10 -0
- data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +87 -0
- data/lib/submodules/ably-ruby/spec/unit/util/pub_sub_spec.rb +86 -0
- metadata +182 -27
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
require 'base64'
|
|
4
|
+
|
|
5
|
+
describe Ably::Models::MessageEncoders do
|
|
6
|
+
let(:default_client_options) { { api_key: api_key, environment: environment } }
|
|
7
|
+
let(:client) { Ably::Rest::Client.new(default_client_options.merge(protocol: protocol)) }
|
|
8
|
+
let(:channel_options) { {} }
|
|
9
|
+
let(:channel) { client.channel('test', channel_options) }
|
|
10
|
+
let(:response) { instance_double('Faraday::Response', status: 201) }
|
|
11
|
+
|
|
12
|
+
let(:cipher_params) { { key: random_str, algorithm: 'aes', mode: 'cbc', key_length: 128 } }
|
|
13
|
+
let(:crypto) { Ably::Util::Crypto.new(cipher_params) }
|
|
14
|
+
|
|
15
|
+
let(:utf_8_data) { random_str.encode(Encoding::UTF_8) }
|
|
16
|
+
let(:binary_data) { MessagePack.pack(random_str).encode(Encoding::ASCII_8BIT) }
|
|
17
|
+
let(:json_data) { { 'key' => random_str } }
|
|
18
|
+
|
|
19
|
+
after do
|
|
20
|
+
channel.publish 'event', published_data
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def on_publish
|
|
24
|
+
expect(client).to receive(:post) do |url, message|
|
|
25
|
+
yield(message['encoding'], message['data'])
|
|
26
|
+
end.and_return(response)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def decrypted(payload, options = {})
|
|
30
|
+
payload = Base64.decode64(payload) if options[:base64]
|
|
31
|
+
crypto.decrypt(payload)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context 'with binary transport protocol' do
|
|
35
|
+
let(:protocol) { :msgpack }
|
|
36
|
+
|
|
37
|
+
context 'without encryption' do
|
|
38
|
+
context 'with UTF-8 data' do
|
|
39
|
+
let(:published_data) { utf_8_data }
|
|
40
|
+
|
|
41
|
+
it 'does not apply any encoding' do
|
|
42
|
+
on_publish do |encoding, encoded_data|
|
|
43
|
+
expect(encoding).to be_nil
|
|
44
|
+
expect(encoded_data).to eql(published_data)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context 'with binary data' do
|
|
50
|
+
let(:published_data) { binary_data }
|
|
51
|
+
|
|
52
|
+
it 'does not apply any encoding' do
|
|
53
|
+
on_publish do |encoding, encoded_data|
|
|
54
|
+
expect(encoding).to be_nil
|
|
55
|
+
expect(encoded_data).to eql(published_data)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context 'with JSON data' do
|
|
61
|
+
let(:published_data) { json_data }
|
|
62
|
+
|
|
63
|
+
it 'stringifies the JSON and sets the encoding attribute to "json"' do
|
|
64
|
+
on_publish do |encoding, encoded_data|
|
|
65
|
+
expect(encoding).to eql('json')
|
|
66
|
+
expect(encoded_data).to eql(JSON.dump(published_data))
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context 'with encryption' do
|
|
73
|
+
let(:channel_options) { { encrypted: true, cipher_params: cipher_params } }
|
|
74
|
+
|
|
75
|
+
context 'with UTF-8 data' do
|
|
76
|
+
let(:published_data) { utf_8_data }
|
|
77
|
+
|
|
78
|
+
it 'applies utf-8 and cipher encoding and sets the encoding attribute to "utf-8/cipher+aes-128-cbc"' do
|
|
79
|
+
on_publish do |encoding, encoded_data|
|
|
80
|
+
expect(encoding).to eql('utf-8/cipher+aes-128-cbc')
|
|
81
|
+
expect(decrypted(encoded_data)).to eql(published_data)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
context 'with binary data' do
|
|
87
|
+
let(:published_data) { binary_data }
|
|
88
|
+
|
|
89
|
+
it 'applies cipher encoding and sets the encoding attribute to "cipher+aes-128-cbc"' do
|
|
90
|
+
on_publish do |encoding, encoded_data|
|
|
91
|
+
expect(encoding).to eql('cipher+aes-128-cbc')
|
|
92
|
+
expect(decrypted(encoded_data)).to eql(published_data)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
context 'with JSON data' do
|
|
98
|
+
let(:published_data) { json_data }
|
|
99
|
+
|
|
100
|
+
it 'applies json, utf-8 and cipher encoding and sets the encoding attribute to "json/utf-8/cipher+aes-128-cbc"' do
|
|
101
|
+
on_publish do |encoding, encoded_data|
|
|
102
|
+
expect(encoding).to eql('json/utf-8/cipher+aes-128-cbc')
|
|
103
|
+
expect(decrypted(encoded_data)).to eql(JSON.dump(published_data))
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
context 'with text transport protocol' do
|
|
111
|
+
let(:protocol) { :json }
|
|
112
|
+
|
|
113
|
+
context 'without encryption' do
|
|
114
|
+
context 'with UTF-8 data' do
|
|
115
|
+
let(:published_data) { utf_8_data }
|
|
116
|
+
|
|
117
|
+
it 'does not apply any encoding' do
|
|
118
|
+
on_publish do |encoding, encoded_data|
|
|
119
|
+
expect(encoding).to be_nil
|
|
120
|
+
expect(encoded_data).to eql(published_data)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
context 'with binary data' do
|
|
126
|
+
let(:published_data) { binary_data }
|
|
127
|
+
|
|
128
|
+
it 'applies a base64 encoding and sets the encoding attribute to "base64"' do
|
|
129
|
+
on_publish do |encoding, encoded_data|
|
|
130
|
+
expect(encoding).to eql('base64')
|
|
131
|
+
expect(Base64.decode64(encoded_data)).to eql(published_data)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
context 'with JSON data' do
|
|
137
|
+
let(:published_data) { json_data }
|
|
138
|
+
|
|
139
|
+
it 'stringifies the JSON and sets the encoding attribute to "json"' do
|
|
140
|
+
on_publish do |encoding, encoded_data|
|
|
141
|
+
expect(encoding).to eql('json')
|
|
142
|
+
expect(encoded_data).to eql(JSON.dump(published_data))
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
context 'with encryption' do
|
|
149
|
+
let(:channel_options) { { encrypted: true, cipher_params: cipher_params } }
|
|
150
|
+
|
|
151
|
+
context 'with UTF-8 data' do
|
|
152
|
+
let(:published_data) { utf_8_data }
|
|
153
|
+
|
|
154
|
+
it 'applies utf-8, cipher and base64 encodings and sets the encoding attribute to "utf-8/cipher+aes-128-cbc/base64"' do
|
|
155
|
+
on_publish do |encoding, encoded_data|
|
|
156
|
+
expect(encoding).to eql('utf-8/cipher+aes-128-cbc/base64')
|
|
157
|
+
expect(decrypted(encoded_data, base64: true)).to eql(published_data)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
context 'with binary data' do
|
|
163
|
+
let(:published_data) { binary_data }
|
|
164
|
+
|
|
165
|
+
it 'applies cipher and base64 encoding and sets the encoding attribute to "utf-8/cipher+aes-128-cbc/base64"' do
|
|
166
|
+
on_publish do |encoding, encoded_data|
|
|
167
|
+
expect(encoding).to eql('cipher+aes-128-cbc/base64')
|
|
168
|
+
expect(decrypted(encoded_data, base64: true)).to eql(published_data)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
context 'with JSON data' do
|
|
174
|
+
let(:published_data) { json_data }
|
|
175
|
+
|
|
176
|
+
it 'applies json, utf-8, cipher and base64 encoding and sets the encoding attribute to "json/utf-8/cipher+aes-128-cbc/base64"' do
|
|
177
|
+
on_publish do |encoding, encoded_data|
|
|
178
|
+
expect(encoding).to eql('json/utf-8/cipher+aes-128-cbc/base64')
|
|
179
|
+
expect(decrypted(encoded_data, base64: true)).to eql(JSON.dump(published_data))
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
describe Ably::Rest::Channel, 'messages' do
|
|
6
|
+
include Ably::Modules::Conversions
|
|
7
|
+
|
|
8
|
+
vary_by_protocol do
|
|
9
|
+
let(:default_client_options) { { api_key: api_key, environment: environment, protocol: protocol } }
|
|
10
|
+
let(:client_options) { default_client_options }
|
|
11
|
+
let(:client) { Ably::Rest::Client.new(client_options) }
|
|
12
|
+
let(:other_client) { Ably::Rest::Client.new(client_options) }
|
|
13
|
+
let(:channel) { client.channel('test') }
|
|
14
|
+
|
|
15
|
+
context 'publishing with an ASCII_8BIT message name' do
|
|
16
|
+
let(:message_name) { random_str.encode(Encoding::ASCII_8BIT) }
|
|
17
|
+
|
|
18
|
+
it 'is converted into UTF_8' do
|
|
19
|
+
channel.publish message_name, 'example'
|
|
20
|
+
message = channel.history.first
|
|
21
|
+
expect(message.name.encoding).to eql(Encoding::UTF_8)
|
|
22
|
+
expect(message.name.encode(Encoding::ASCII_8BIT)).to eql(message_name)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe 'encryption and encoding' do
|
|
27
|
+
let(:channel_name) { "persisted:#{random_str}" }
|
|
28
|
+
let(:cipher_options) { { key: random_str(32) } }
|
|
29
|
+
let(:encrypted_channel) { client.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
|
|
30
|
+
|
|
31
|
+
context 'with #publish and #history' do
|
|
32
|
+
shared_examples 'an Ably encrypter and decrypter' do |item, data|
|
|
33
|
+
let(:algorithm) { data['algorithm'].upcase }
|
|
34
|
+
let(:mode) { data['mode'].upcase }
|
|
35
|
+
let(:key_length) { data['keylength'] }
|
|
36
|
+
let(:secret_key) { Base64.decode64(data['key']) }
|
|
37
|
+
let(:iv) { Base64.decode64(data['iv']) }
|
|
38
|
+
|
|
39
|
+
let(:cipher_options) { { key: secret_key, iv: iv, algorithm: algorithm, mode: mode, key_length: key_length } }
|
|
40
|
+
|
|
41
|
+
let(:encoded) { item['encoded'] }
|
|
42
|
+
let(:encoded_data) { encoded['data'] }
|
|
43
|
+
let(:encoded_encoding) { encoded['encoding'] }
|
|
44
|
+
let(:encoded_data_decoded) do
|
|
45
|
+
if encoded_encoding == 'json'
|
|
46
|
+
JSON.parse(encoded_data)
|
|
47
|
+
elsif encoded_encoding == 'base64'
|
|
48
|
+
Base64.decode64(encoded_data)
|
|
49
|
+
else
|
|
50
|
+
encoded_data
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
let(:encrypted) { item['encrypted'] }
|
|
55
|
+
let(:encrypted_data) { encrypted['data'] }
|
|
56
|
+
let(:encrypted_encoding) { encrypted['encoding'] }
|
|
57
|
+
let(:encrypted_data_decoded) do
|
|
58
|
+
if encrypted_encoding.match(%r{/base64$})
|
|
59
|
+
Base64.decode64(encrypted_data)
|
|
60
|
+
else
|
|
61
|
+
encrypted_data
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'encrypts message automatically when published' do
|
|
66
|
+
expect(client).to receive(:post) do |path, message|
|
|
67
|
+
if protocol == :json
|
|
68
|
+
expect(message['encoding']).to eql(encrypted_encoding)
|
|
69
|
+
expect(Base64.decode64(message['data'])).to eql(encrypted_data_decoded)
|
|
70
|
+
else
|
|
71
|
+
# Messages sent over binary protocol will not have Base64 encoded data
|
|
72
|
+
expect(message['encoding']).to eql(encrypted_encoding.gsub(%r{/base64$}, ''))
|
|
73
|
+
expect(message['data']).to eql(encrypted_data_decoded)
|
|
74
|
+
end
|
|
75
|
+
end.and_return(double('Response', status: 201))
|
|
76
|
+
|
|
77
|
+
encrypted_channel.publish 'example', encoded_data_decoded
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'sends and retrieves messages that are encrypted & decrypted by the Ably library' do
|
|
81
|
+
encrypted_channel.publish 'example', encoded_data_decoded
|
|
82
|
+
|
|
83
|
+
message = encrypted_channel.history.first
|
|
84
|
+
expect(message.data).to eql(encoded_data_decoded)
|
|
85
|
+
expect(message.encoding).to be_nil
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
resources_root = File.expand_path('../../../resources', __FILE__)
|
|
90
|
+
|
|
91
|
+
def self.add_tests_for_data(data)
|
|
92
|
+
data['items'].each_with_index do |item, index|
|
|
93
|
+
context "item #{index} with encrypted encoding #{item['encrypted']['encoding']}" do
|
|
94
|
+
it_behaves_like 'an Ably encrypter and decrypter', item, data
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
context 'with AES-128-CBC using crypto-data-128.json fixtures' do
|
|
100
|
+
data = JSON.parse(File.read(File.join(resources_root, 'crypto-data-128.json')))
|
|
101
|
+
add_tests_for_data data
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
context 'with AES-256-CBC using crypto-data-256.json fixtures' do
|
|
105
|
+
data = JSON.parse(File.read(File.join(resources_root, 'crypto-data-256.json')))
|
|
106
|
+
add_tests_for_data data
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
context 'when publishing lots of messages' do
|
|
110
|
+
let(:data) { MessagePack.pack({ 'key' => random_str }) }
|
|
111
|
+
let(:message_count) { 20 }
|
|
112
|
+
|
|
113
|
+
it 'encrypts on #publish and decrypts on #history' do
|
|
114
|
+
message_count.times do |index|
|
|
115
|
+
encrypted_channel.publish index.to_s, "#{index}-#{data}"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
messages = encrypted_channel.history
|
|
119
|
+
|
|
120
|
+
expect(messages.count).to eql(message_count)
|
|
121
|
+
messages.each do |message|
|
|
122
|
+
expect(message.data).to eql("#{message.name}-#{data}")
|
|
123
|
+
expect(message.encoding).to be_nil
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
context 'when retrieving #history with a different protocol' do
|
|
129
|
+
let(:other_protocol) { protocol == :msgpack ? :json : :msgpack }
|
|
130
|
+
let(:other_client) { Ably::Rest::Client.new(default_client_options.merge(protocol: other_protocol)) }
|
|
131
|
+
let(:other_client_channel) { other_client.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
|
|
132
|
+
|
|
133
|
+
before do
|
|
134
|
+
expect(other_client.protocol_binary?).to_not eql(client.protocol_binary?)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
[MessagePack.pack({ 'key' => SecureRandom.hex }), 'ã unicode', { 'key' => SecureRandom.hex }].each do |payload|
|
|
138
|
+
payload_description = "#{payload.class}#{" #{payload.encoding}" if payload.kind_of?(String)}"
|
|
139
|
+
|
|
140
|
+
specify "delivers a #{payload_description} payload to the receiver" do
|
|
141
|
+
encrypted_channel.publish 'example', payload
|
|
142
|
+
|
|
143
|
+
message = other_client_channel.history.first
|
|
144
|
+
expect(message.data).to eql(payload)
|
|
145
|
+
expect(message.encoding).to be_nil
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
context 'when publishing on an unencrypted channel and retrieving with #history on an encrypted channel' do
|
|
151
|
+
let(:unencrypted_channel) { client.channel(channel_name) }
|
|
152
|
+
let(:other_client_encrypted_channel) { other_client.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
|
|
153
|
+
|
|
154
|
+
let(:payload) { MessagePack.pack({ 'key' => random_str }) }
|
|
155
|
+
|
|
156
|
+
it 'does not attempt to decrypt the message' do
|
|
157
|
+
unencrypted_channel.publish 'example', payload
|
|
158
|
+
|
|
159
|
+
message = other_client_encrypted_channel.history.first
|
|
160
|
+
expect(message.data).to eql(payload)
|
|
161
|
+
expect(message.encoding).to be_nil
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
context 'when publishing on an encrypted channel and retrieving with #history on an unencrypted channel' do
|
|
166
|
+
let(:client_options) { default_client_options.merge(log_level: :fatal) }
|
|
167
|
+
let(:cipher_options) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
|
|
168
|
+
let(:encrypted_channel) { client.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
|
|
169
|
+
let(:other_client_unencrypted_channel) { other_client.channel(channel_name) }
|
|
170
|
+
|
|
171
|
+
let(:payload) { MessagePack.pack({ 'key' => random_str }) }
|
|
172
|
+
|
|
173
|
+
before do
|
|
174
|
+
encrypted_channel.publish 'example', payload
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it 'retrieves the message that remains encrypted with an encrypted encoding attribute' do
|
|
178
|
+
message = other_client_unencrypted_channel.history.first
|
|
179
|
+
expect(message.data).to_not eql(payload)
|
|
180
|
+
expect(message.encoding).to match(/^cipher\+aes-256-cbc/)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it 'logs a Cipher exception' do
|
|
184
|
+
expect(other_client.logger).to receive(:error) do |message|
|
|
185
|
+
expect(message).to match(/Message cannot be decrypted/)
|
|
186
|
+
end
|
|
187
|
+
other_client_unencrypted_channel.history
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
context 'publishing on an encrypted channel and retrieving #history with a different algorithm on another client' do
|
|
192
|
+
let(:client_options) { default_client_options.merge(log_level: :fatal) }
|
|
193
|
+
let(:cipher_options_client1) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
|
|
194
|
+
let(:encrypted_channel_client1) { client.channel(channel_name, encrypted: true, cipher_params: cipher_options_client1) }
|
|
195
|
+
let(:cipher_options_client2) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 128 } }
|
|
196
|
+
let(:encrypted_channel_client2) { other_client.channel(channel_name, encrypted: true, cipher_params: cipher_options_client2) }
|
|
197
|
+
|
|
198
|
+
let(:payload) { MessagePack.pack({ 'key' => random_str }) }
|
|
199
|
+
|
|
200
|
+
before do
|
|
201
|
+
encrypted_channel_client1.publish 'example', payload
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it 'retrieves the message that remains encrypted with an encrypted encoding attribute' do
|
|
205
|
+
message = encrypted_channel_client2.history.first
|
|
206
|
+
expect(message.data).to_not eql(payload)
|
|
207
|
+
expect(message.encoding).to match(/^cipher\+aes-256-cbc/)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it 'logs a Cipher exception' do
|
|
211
|
+
expect(other_client.logger).to receive(:error) do |message|
|
|
212
|
+
expect(message).to match(/Cipher algorithm [\w-]+ does not match/)
|
|
213
|
+
end
|
|
214
|
+
encrypted_channel_client2.history
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
context 'publishing on an encrypted channel and subscribing with a different key on another client' do
|
|
219
|
+
let(:client_options) { default_client_options.merge(log_level: :fatal) }
|
|
220
|
+
let(:cipher_options_client1) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
|
|
221
|
+
let(:encrypted_channel_client1) { client.channel(channel_name, encrypted: true, cipher_params: cipher_options_client1) }
|
|
222
|
+
let(:cipher_options_client2) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
|
|
223
|
+
let(:encrypted_channel_client2) { other_client.channel(channel_name, encrypted: true, cipher_params: cipher_options_client2) }
|
|
224
|
+
|
|
225
|
+
let(:payload) { MessagePack.pack({ 'key' => random_str }) }
|
|
226
|
+
|
|
227
|
+
before do
|
|
228
|
+
encrypted_channel_client1.publish 'example', payload
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
it 'retrieves the message that remains encrypted with an encrypted encoding attribute' do
|
|
232
|
+
message = encrypted_channel_client2.history.first
|
|
233
|
+
expect(message.data).to_not eql(payload)
|
|
234
|
+
expect(message.encoding).to match(/^cipher\+aes-256-cbc/)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it 'logs a Cipher exception' do
|
|
238
|
+
expect(other_client.logger).to receive(:error) do |message|
|
|
239
|
+
expect(message).to match(/CipherError decrypting data/)
|
|
240
|
+
end
|
|
241
|
+
encrypted_channel_client2.history
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
describe Ably::Rest::Presence do
|
|
5
|
+
include Ably::Modules::Conversions
|
|
6
|
+
|
|
7
|
+
vary_by_protocol do
|
|
8
|
+
let(:default_options) { { api_key: api_key, environment: environment, protocol: protocol } }
|
|
9
|
+
let(:client_options) { default_options }
|
|
10
|
+
let(:client) do
|
|
11
|
+
Ably::Rest::Client.new(client_options)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
let(:fixtures) do
|
|
15
|
+
TestApp::APP_SPEC['channels'].first['presence'].map do |fixture|
|
|
16
|
+
IdiomaticRubyWrapper(fixture, stop_at: [:data])
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context 'tested against presence fixture data set up in test app' do
|
|
21
|
+
describe '#get' do
|
|
22
|
+
before(:context) do
|
|
23
|
+
# When this test is run as a part of a test suite, the presence data injected in the test app may have expired
|
|
24
|
+
reload_test_app
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
let(:channel) { client.channel('persisted:presence_fixtures') }
|
|
28
|
+
let(:presence) { channel.presence.get }
|
|
29
|
+
|
|
30
|
+
it 'returns current members on the channel with their action set to :present' do
|
|
31
|
+
expect(presence.size).to eql(4)
|
|
32
|
+
|
|
33
|
+
fixtures.each do |fixture|
|
|
34
|
+
presence_message = presence.find { |client| client.client_id == fixture[:client_id] }
|
|
35
|
+
expect(presence_message.data).to eq(fixture[:data])
|
|
36
|
+
expect(presence_message.action).to eq(:present)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context 'with :limit option' do
|
|
41
|
+
let(:page_size) { 2 }
|
|
42
|
+
let(:presence) { channel.presence.get(limit: page_size) }
|
|
43
|
+
|
|
44
|
+
it 'returns a paged response limiting number of members per page' do
|
|
45
|
+
expect(presence.size).to eql(2)
|
|
46
|
+
next_page = presence.next_page
|
|
47
|
+
expect(next_page.size).to eql(2)
|
|
48
|
+
expect(next_page).to be_last_page
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe '#history' do
|
|
54
|
+
before(:context) do
|
|
55
|
+
# When this test is run as a part of a test suite, the presence data injected in the test app may have expired
|
|
56
|
+
reload_test_app
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
let(:channel) { client.channel('persisted:presence_fixtures') }
|
|
60
|
+
let(:presence_history) { channel.presence.history }
|
|
61
|
+
|
|
62
|
+
it 'returns recent presence activity' do
|
|
63
|
+
expect(presence_history.size).to eql(4)
|
|
64
|
+
|
|
65
|
+
fixtures.each do |fixture|
|
|
66
|
+
presence_message = presence_history.find { |client| client.client_id == fixture['clientId'] }
|
|
67
|
+
expect(presence_message.data).to eq(fixture[:data])
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
context 'with options' do
|
|
72
|
+
let(:page_size) { 2 }
|
|
73
|
+
|
|
74
|
+
context 'direction: :forwards' do
|
|
75
|
+
let(:presence_history) { channel.presence.history(direction: :forwards) }
|
|
76
|
+
let(:paged_history_forward) { channel.presence.history(limit: page_size, direction: :forwards) }
|
|
77
|
+
|
|
78
|
+
it 'returns recent presence activity forwards with most recent history last' do
|
|
79
|
+
expect(paged_history_forward).to be_a(Ably::Models::PaginatedResource)
|
|
80
|
+
expect(paged_history_forward.size).to eql(2)
|
|
81
|
+
|
|
82
|
+
next_page = paged_history_forward.next_page
|
|
83
|
+
|
|
84
|
+
expect(paged_history_forward.first.id).to eql(presence_history.first.id)
|
|
85
|
+
expect(next_page.first.id).to eql(presence_history[page_size].id)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
context 'direction: :backwards' do
|
|
90
|
+
let(:presence_history) { channel.presence.history(direction: :backwards) }
|
|
91
|
+
let(:paged_history_backward) { channel.presence.history(limit: page_size, direction: :backwards) }
|
|
92
|
+
|
|
93
|
+
it 'returns recent presence activity backwards with most recent history first' do
|
|
94
|
+
expect(paged_history_backward).to be_a(Ably::Models::PaginatedResource)
|
|
95
|
+
expect(paged_history_backward.size).to eql(2)
|
|
96
|
+
|
|
97
|
+
next_page = paged_history_backward.next_page
|
|
98
|
+
|
|
99
|
+
expect(paged_history_backward.first.id).to eql(presence_history.first.id)
|
|
100
|
+
expect(next_page.first.id).to eql(presence_history[page_size].id)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
describe '#history' do
|
|
108
|
+
context 'with time range options' do
|
|
109
|
+
let(:channel_name) { "persisted:#{random_str(4)}" }
|
|
110
|
+
let(:presence) { client.channel(channel_name).presence }
|
|
111
|
+
let(:user) { 'appid.keyuid' }
|
|
112
|
+
let(:secret) { random_str(8) }
|
|
113
|
+
let(:endpoint) do
|
|
114
|
+
client.endpoint.tap do |client_end_point|
|
|
115
|
+
client_end_point.user = user
|
|
116
|
+
client_end_point.password = secret
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
let(:client) do
|
|
120
|
+
Ably::Rest::Client.new(api_key: "#{user}:#{secret}")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
[:start, :end].each do |option|
|
|
124
|
+
describe ":#{option}", :webmock do
|
|
125
|
+
let!(:history_stub) {
|
|
126
|
+
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence/history?#{option}=#{milliseconds}").
|
|
127
|
+
to_return(:body => '{}', :headers => { 'Content-Type' => 'application/json' })
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
before do
|
|
131
|
+
presence.history(options)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
context 'with milliseconds since epoch value' do
|
|
135
|
+
let(:milliseconds) { as_since_epoch(Time.now) }
|
|
136
|
+
let(:options) { { option => milliseconds } }
|
|
137
|
+
|
|
138
|
+
it 'uses this value in the history request' do
|
|
139
|
+
expect(history_stub).to have_been_requested
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
context 'with Time object value' do
|
|
144
|
+
let(:time) { Time.now }
|
|
145
|
+
let(:milliseconds) { as_since_epoch(time) }
|
|
146
|
+
let(:options) { { option => time } }
|
|
147
|
+
|
|
148
|
+
it 'converts the value to milliseconds since epoch in the hisotry request' do
|
|
149
|
+
expect(history_stub).to have_been_requested
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
describe 'decoding', :webmock do
|
|
158
|
+
let(:user) { 'appid.keyuid' }
|
|
159
|
+
let(:secret) { random_str(8) }
|
|
160
|
+
let(:endpoint) do
|
|
161
|
+
client.endpoint.tap do |client_end_point|
|
|
162
|
+
client_end_point.user = user
|
|
163
|
+
client_end_point.password = secret
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
let(:client) do
|
|
167
|
+
Ably::Rest::Client.new(client_options.merge(api_key: "#{user}:#{secret}"))
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
let(:data) { random_str(32) }
|
|
171
|
+
let(:channel_name) { "persisted:#{random_str(4)}" }
|
|
172
|
+
let(:cipher_options) { { key: random_str(32), algorithm: 'aes', mode: 'cbc', key_length: 256 } }
|
|
173
|
+
let(:presence) { client.channel(channel_name, encrypted: true, cipher_params: cipher_options).presence }
|
|
174
|
+
|
|
175
|
+
let(:crypto) { Ably::Util::Crypto.new(cipher_options) }
|
|
176
|
+
|
|
177
|
+
let(:content_type) do
|
|
178
|
+
if protocol == :msgpack
|
|
179
|
+
'application/x-msgpack'
|
|
180
|
+
else
|
|
181
|
+
'application/json'
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
context 'valid decodeable content' do
|
|
186
|
+
let(:serialized_encoded_message) do
|
|
187
|
+
if protocol == :msgpack
|
|
188
|
+
msg = Ably::Models::PresenceMessage.new({ action: :enter, data: crypto.encrypt(data), encoding: 'utf-8/cipher+aes-256-cbc' })
|
|
189
|
+
MessagePack.pack([msg.as_json])
|
|
190
|
+
else
|
|
191
|
+
msg = Ably::Models::PresenceMessage.new({ action: :enter, data: Base64.encode64(crypto.encrypt(data)), encoding: 'utf-8/cipher+aes-256-cbc/base64' })
|
|
192
|
+
[msg].to_json
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
context '#get' do
|
|
197
|
+
let!(:get_stub) {
|
|
198
|
+
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence").
|
|
199
|
+
to_return(:body => serialized_encoded_message, :headers => { 'Content-Type' => content_type })
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
after do
|
|
203
|
+
expect(get_stub).to have_been_requested
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
it 'automaticaly decodes presence messages' do
|
|
207
|
+
present = presence.get
|
|
208
|
+
expect(present.first.encoding).to be_nil
|
|
209
|
+
expect(present.first.data).to eql(data)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
context '#history' do
|
|
214
|
+
let!(:history_stub) {
|
|
215
|
+
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence/history").
|
|
216
|
+
to_return(:body => serialized_encoded_message, :headers => { 'Content-Type' => content_type })
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
after do
|
|
220
|
+
expect(history_stub).to have_been_requested
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
it 'automaticaly decodes presence messages' do
|
|
224
|
+
history = presence.history
|
|
225
|
+
expect(history.first.encoding).to be_nil
|
|
226
|
+
expect(history.first.data).to eql(data)
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
context 'invalid data' do
|
|
232
|
+
let(:serialized_encoded_message_with_invalid_encoding) do
|
|
233
|
+
if protocol == :msgpack
|
|
234
|
+
msg = Ably::Models::PresenceMessage.new({ action: :enter, data: crypto.encrypt(data), encoding: 'utf-8/cipher+aes-128-cbc' })
|
|
235
|
+
MessagePack.pack([msg.as_json])
|
|
236
|
+
else
|
|
237
|
+
msg = Ably::Models::PresenceMessage.new({ action: :enter, data: Base64.encode64(crypto.encrypt(data)), encoding: 'utf-8/cipher+aes-128-cbc/base64' })
|
|
238
|
+
[msg].to_json
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
context '#get' do
|
|
243
|
+
let(:client_options) { default_options.merge(log_level: :fatal) }
|
|
244
|
+
let!(:get_stub) {
|
|
245
|
+
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence").
|
|
246
|
+
to_return(:body => serialized_encoded_message_with_invalid_encoding, :headers => { 'Content-Type' => content_type })
|
|
247
|
+
}
|
|
248
|
+
let(:presence_message) { presence.get.first }
|
|
249
|
+
|
|
250
|
+
after do
|
|
251
|
+
expect(get_stub).to have_been_requested
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
it 'returns the messages still encoded' do
|
|
255
|
+
expect(presence_message.encoding).to match(/cipher\+aes-128-cbc/)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
it 'logs a cipher error' do
|
|
259
|
+
expect(client.logger).to receive(:error) do |message|
|
|
260
|
+
expect(message).to match(/Cipher algorithm [\w-]+ does not match/)
|
|
261
|
+
end
|
|
262
|
+
presence.get
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
context '#history' do
|
|
267
|
+
let(:client_options) { default_options.merge(log_level: :fatal) }
|
|
268
|
+
let!(:history_stub) {
|
|
269
|
+
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence/history").
|
|
270
|
+
to_return(:body => serialized_encoded_message_with_invalid_encoding, :headers => { 'Content-Type' => content_type })
|
|
271
|
+
}
|
|
272
|
+
let(:presence_message) { presence.history.first }
|
|
273
|
+
|
|
274
|
+
after do
|
|
275
|
+
expect(history_stub).to have_been_requested
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
it 'returns the messages still encoded' do
|
|
279
|
+
expect(presence_message.encoding).to match(/cipher\+aes-128-cbc/)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
it 'logs a cipher error' do
|
|
283
|
+
expect(client.logger).to receive(:error) do |message|
|
|
284
|
+
expect(message).to match(/Cipher algorithm [\w-]+ does not match/)
|
|
285
|
+
end
|
|
286
|
+
presence.history
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|