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,25 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'shared/protocol_msgbus_behaviour'
|
|
3
|
+
|
|
4
|
+
describe Ably::Realtime::Connection::WebsocketTransport, :api_private do
|
|
5
|
+
let(:client_ignored) { double('Ably::Realtime::Client').as_null_object }
|
|
6
|
+
let(:connection) { instance_double('Ably::Realtime::Connection', client: client_ignored, id: nil) }
|
|
7
|
+
let(:url) { 'http://ably.io/' }
|
|
8
|
+
|
|
9
|
+
let(:websocket_transport_without_eventmachine) do
|
|
10
|
+
Ably::Realtime::Connection::WebsocketTransport.send(:allocate).tap do |websocket_transport|
|
|
11
|
+
websocket_transport.send(:initialize, connection, url)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
before do
|
|
16
|
+
allow(Ably::Realtime::Connection::WebsocketTransport).to receive(:new).with(connection).and_return(websocket_transport_without_eventmachine)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
subject do
|
|
20
|
+
Ably::Realtime::Connection::WebsocketTransport.new(connection)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it_behaves_like 'an incoming protocol message bus'
|
|
24
|
+
it_behaves_like 'an outgoing protocol message bus'
|
|
25
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
describe Ably::Rest::Channels do
|
|
5
|
+
let(:client) { instance_double('Ably::Rest::Client', encoders: [], post: instance_double('Faraday::Response', status: 201)) }
|
|
6
|
+
let(:channel_name) { 'unique' }
|
|
7
|
+
|
|
8
|
+
subject { Ably::Rest::Channel.new(client, channel_name) }
|
|
9
|
+
|
|
10
|
+
describe '#initializer' do
|
|
11
|
+
let(:channel_name) { random_str.encode(encoding) }
|
|
12
|
+
|
|
13
|
+
context 'as UTF_8 string' do
|
|
14
|
+
let(:encoding) { Encoding::UTF_8 }
|
|
15
|
+
|
|
16
|
+
it 'is permitted' do
|
|
17
|
+
expect(subject.name).to eql(channel_name)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'remains as UTF-8' do
|
|
21
|
+
expect(subject.name.encoding).to eql(encoding)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context 'as SHIFT_JIS string' do
|
|
26
|
+
let(:encoding) { Encoding::SHIFT_JIS }
|
|
27
|
+
|
|
28
|
+
it 'gets converted to UTF-8' do
|
|
29
|
+
expect(subject.name.encoding).to eql(Encoding::UTF_8)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'is compatible with original encoding' do
|
|
33
|
+
expect(subject.name.encode(encoding)).to eql(channel_name)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context 'as ASCII_8BIT string' do
|
|
38
|
+
let(:encoding) { Encoding::ASCII_8BIT }
|
|
39
|
+
|
|
40
|
+
it 'gets converted to UTF-8' do
|
|
41
|
+
expect(subject.name.encoding).to eql(Encoding::UTF_8)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'is compatible with original encoding' do
|
|
45
|
+
expect(subject.name.encode(encoding)).to eql(channel_name)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context 'as Integer' do
|
|
50
|
+
let(:channel_name) { 1 }
|
|
51
|
+
|
|
52
|
+
it 'raises an argument error' do
|
|
53
|
+
expect { subject }.to raise_error ArgumentError, /must be a String/
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context 'as Nil' do
|
|
58
|
+
let(:channel_name) { nil }
|
|
59
|
+
|
|
60
|
+
it 'raises an argument error' do
|
|
61
|
+
expect { subject }.to raise_error ArgumentError, /must be a String/
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe '#publish name argument' do
|
|
67
|
+
let(:encoded_value) { random_str.encode(encoding) }
|
|
68
|
+
|
|
69
|
+
context 'as UTF_8 string' do
|
|
70
|
+
let(:encoding) { Encoding::UTF_8 }
|
|
71
|
+
|
|
72
|
+
it 'is permitted' do
|
|
73
|
+
expect(subject.publish(encoded_value, 'data')).to eql(true)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
context 'as SHIFT_JIS string' do
|
|
78
|
+
let(:encoding) { Encoding::SHIFT_JIS }
|
|
79
|
+
|
|
80
|
+
it 'is permitted' do
|
|
81
|
+
expect(subject.publish(encoded_value, 'data')).to eql(true)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context 'as ASCII_8BIT string' do
|
|
86
|
+
let(:encoding) { Encoding::ASCII_8BIT }
|
|
87
|
+
|
|
88
|
+
it 'is permitted' do
|
|
89
|
+
expect(subject.publish(encoded_value, 'data')).to eql(true)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context 'as Integer' do
|
|
94
|
+
let(:encoded_value) { 1 }
|
|
95
|
+
|
|
96
|
+
it 'raises an argument error' do
|
|
97
|
+
expect { subject.publish(encoded_value, 'data') }.to raise_error ArgumentError, /must be a String/
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
context 'as Nil' do
|
|
102
|
+
let(:encoded_value) { nil }
|
|
103
|
+
|
|
104
|
+
it 'raises an argument error' do
|
|
105
|
+
expect { subject.publish(encoded_value, 'data') }.to raise_error ArgumentError, /must be a String/
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
describe Ably::Rest::Channels do
|
|
5
|
+
let(:client) { instance_double('Ably::Rest::Client') }
|
|
6
|
+
let(:channel_name) { 'unique'.encode(Encoding::UTF_8) }
|
|
7
|
+
let(:options) { { 'bizarre' => 'value' } }
|
|
8
|
+
|
|
9
|
+
subject { Ably::Rest::Channels.new(client) }
|
|
10
|
+
|
|
11
|
+
context 'creating channels' do
|
|
12
|
+
it '#get creates a channel' do
|
|
13
|
+
expect(Ably::Rest::Channel).to receive(:new).with(client, channel_name, options)
|
|
14
|
+
subject.get(channel_name, options)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it '#get will reuse the channel object' do
|
|
18
|
+
channel = subject.get(channel_name, options)
|
|
19
|
+
expect(channel).to be_a(Ably::Rest::Channel)
|
|
20
|
+
expect(subject.get(channel_name, options).object_id).to eql(channel.object_id)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it '[] creates a channel' do
|
|
24
|
+
expect(Ably::Rest::Channel).to receive(:new).with(client, channel_name, options)
|
|
25
|
+
subject.get(channel_name, options)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context '#fetch' do
|
|
30
|
+
it 'retrieves a channel if it exists' do
|
|
31
|
+
channel = subject.get(channel_name, options)
|
|
32
|
+
expect(subject.fetch(channel_name)).to eql(channel)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'calls the block if channel is missing' do
|
|
36
|
+
block_called = false
|
|
37
|
+
subject.fetch(channel_name) { block_called = true }
|
|
38
|
+
expect(block_called).to eql(true)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
context 'destroying channels' do
|
|
43
|
+
it '#release releases the channel resoures' do
|
|
44
|
+
released_channel = subject.get(channel_name, options)
|
|
45
|
+
subject.release(channel_name)
|
|
46
|
+
expect(subject.get(channel_name, options).object_id).to_not eql(released_channel.object_id)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context 'is Enumerable' do
|
|
51
|
+
let(:channel_count) { 5 }
|
|
52
|
+
let(:mock_channel) { instance_double('Ably::Rest::Channel') }
|
|
53
|
+
|
|
54
|
+
before do
|
|
55
|
+
allow(Ably::Rest::Channel).to receive(:new).and_return(mock_channel)
|
|
56
|
+
channel_count.times { |index| subject.get("channel-#{index}") }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'allows enumeration' do
|
|
60
|
+
expect(subject.map.count).to eql(channel_count)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context '#each' do
|
|
64
|
+
it 'returns an enumerator' do
|
|
65
|
+
expect(subject.each).to be_a(Enumerator)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'yields each channel' do
|
|
69
|
+
subject.each do |channel|
|
|
70
|
+
expect(channel).to eql(mock_channel)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'provides #length' do
|
|
76
|
+
expect(subject.length).to eql(channel_count)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
require 'shared/client_initializer_behaviour'
|
|
4
|
+
|
|
5
|
+
describe Ably::Rest::Client do
|
|
6
|
+
subject do
|
|
7
|
+
Ably::Rest::Client.new(client_options)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it_behaves_like 'a client initializer'
|
|
11
|
+
|
|
12
|
+
context 'initializer options' do
|
|
13
|
+
context 'TLS' do
|
|
14
|
+
context 'disabled' do
|
|
15
|
+
let(:client_options) { { api_key: 'appid.keyuid:keysecret', tls: false } }
|
|
16
|
+
|
|
17
|
+
it 'fails for any operation with basic auth and attempting to send an API key over a non-secure connection' do
|
|
18
|
+
expect { subject.channel('a').publish('event', 'message') }.to raise_error(Ably::Exceptions::InsecureRequestError)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context ':use_token_auth' do
|
|
24
|
+
context 'set to false' do
|
|
25
|
+
context 'with an api_key with :tls => false' do
|
|
26
|
+
let(:client_options) { { use_token_auth: false, api_key: 'appid.keyuid:keysecret', tls: false } }
|
|
27
|
+
|
|
28
|
+
it 'fails for any operation with basic auth and attempting to send an API key over a non-secure connection' do
|
|
29
|
+
expect { subject.channel('a').publish('event', 'message') }.to raise_error(Ably::Exceptions::InsecureRequestError)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
context 'without an api_key' do
|
|
34
|
+
let(:client_options) { { use_token_auth: false } }
|
|
35
|
+
|
|
36
|
+
it 'fails as an api_key is required if not using token auth' do
|
|
37
|
+
expect { subject.channel('a').publish('event', 'message') }.to raise_error(ArgumentError)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
context 'set to true' do
|
|
43
|
+
context 'without an api_key or token_id' do
|
|
44
|
+
let(:client_options) { { use_token_auth: true, api_key: true } }
|
|
45
|
+
|
|
46
|
+
it 'fails as an api_key is required to issue tokens' do
|
|
47
|
+
expect { subject.channel('a').publish('event', 'message') }.to raise_error(ArgumentError)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
describe Ably::Rest do
|
|
5
|
+
let(:options) { { api_key: 'app.key:secret' } }
|
|
6
|
+
|
|
7
|
+
specify 'constructor returns an Ably::Rest::Client' do
|
|
8
|
+
expect(Ably::Rest.new(options)).to be_instance_of(Ably::Rest::Client)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'msgpack'
|
|
3
|
+
|
|
4
|
+
describe Ably::Util::Crypto do
|
|
5
|
+
let(:seret_key) { random_str }
|
|
6
|
+
let(:cipher_options) { { key: seret_key } }
|
|
7
|
+
subject { Ably::Util::Crypto.new(cipher_options) }
|
|
8
|
+
|
|
9
|
+
context 'defaults' do
|
|
10
|
+
let(:expected_defaults) do
|
|
11
|
+
{
|
|
12
|
+
algorithm: 'AES',
|
|
13
|
+
mode: 'CBC',
|
|
14
|
+
key_length: 128
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
specify 'match other client libraries' do
|
|
19
|
+
expect(Ably::Util::Crypto::DEFAULTS).to eql(expected_defaults)
|
|
20
|
+
expect(Ably::Util::Crypto::BLOCK_LENGTH).to eql(16)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context 'encrypts & decrypt' do
|
|
25
|
+
let(:string) { random_str }
|
|
26
|
+
let(:byte_array) { random_str.to_msgpack.unpack('C*') }
|
|
27
|
+
|
|
28
|
+
specify '#encrypt encrypts a string' do
|
|
29
|
+
encrypted = subject.encrypt(string)
|
|
30
|
+
expect(subject.decrypt(encrypted)).to eql(string)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
specify '#decrypt decrypts a string' do
|
|
34
|
+
encrypted = subject.encrypt(string)
|
|
35
|
+
expect(subject.decrypt(encrypted)).to eql(string)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context 'encrypting an empty string' do
|
|
40
|
+
let(:empty_string) { '' }
|
|
41
|
+
|
|
42
|
+
it 'raises an ArgumentError' do
|
|
43
|
+
expect { subject.encrypt(empty_string) }.to raise_error ArgumentError, /data must not be empty/
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context 'using shared client lib fixture data' do
|
|
48
|
+
let(:resources_root) { File.expand_path('../../../resources', __FILE__) }
|
|
49
|
+
let(:encryption_data_128) { JSON.parse(File.read(File.join(resources_root, 'crypto-data-128.json'))) }
|
|
50
|
+
let(:encryption_data_256) { JSON.parse(File.read(File.join(resources_root, 'crypto-data-256.json'))) }
|
|
51
|
+
|
|
52
|
+
shared_examples 'an Ably encrypter and decrypter' do
|
|
53
|
+
let(:algorithm) { data['algorithm'].upcase }
|
|
54
|
+
let(:mode) { data['mode'].upcase }
|
|
55
|
+
let(:key_length) { data['keylength'] }
|
|
56
|
+
let(:secret_key) { Base64.decode64(data['key']) }
|
|
57
|
+
let(:iv) { Base64.decode64(data['iv']) }
|
|
58
|
+
|
|
59
|
+
let(:cipher_options) { { key: secret_key, algorithm: algorithm, mode: mode, key_length: key_length } }
|
|
60
|
+
|
|
61
|
+
context 'text payload' do
|
|
62
|
+
let(:payload) { data['items'].first['encoded']['data'] }
|
|
63
|
+
let(:encrypted) { data['items'].first['encrypted']['data'] }
|
|
64
|
+
|
|
65
|
+
it 'encrypts exactly the same binary data as other client libraries' do
|
|
66
|
+
expect(subject.encrypt(payload, iv: iv)).to eql(Base64.decode64(encrypted))
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'decrypts exactly the same binary data as other client libraries' do
|
|
70
|
+
expect(subject.decrypt(Base64.decode64(encrypted))).to eql(payload)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
context 'with AES-128-CBC' do
|
|
76
|
+
let(:data) { encryption_data_128 }
|
|
77
|
+
|
|
78
|
+
it_behaves_like 'an Ably encrypter and decrypter'
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context 'with AES-256-CBC' do
|
|
82
|
+
let(:data) { encryption_data_256 }
|
|
83
|
+
|
|
84
|
+
it_behaves_like 'an Ably encrypter and decrypter'
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Ably::Util::PubSub do
|
|
4
|
+
let(:options) { {} }
|
|
5
|
+
let(:obj) { double('example') }
|
|
6
|
+
let(:msg) { double('message') }
|
|
7
|
+
|
|
8
|
+
subject { Ably::Util::PubSub.new(options) }
|
|
9
|
+
|
|
10
|
+
context 'event fan out' do
|
|
11
|
+
specify '#publish allows publishing to more than on subscriber' do
|
|
12
|
+
expect(obj).to receive(:received_message).with(msg).twice
|
|
13
|
+
2.times do
|
|
14
|
+
subject.subscribe(:message) { |msg| obj.received_message msg }
|
|
15
|
+
end
|
|
16
|
+
subject.publish :message, msg
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it '#publish sends only messages to #subscribe callbacks matching event names' do
|
|
20
|
+
expect(obj).to receive(:received_message).with(msg).once
|
|
21
|
+
subject.subscribe(:valid) { |msg| obj.received_message msg }
|
|
22
|
+
subject.publish :valid, msg
|
|
23
|
+
subject.publish :ignored, msg
|
|
24
|
+
subject.publish 'valid', msg
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context 'with coercion', api_private: true do
|
|
28
|
+
let(:options) do
|
|
29
|
+
{ coerce_into: Proc.new { |event| String(event) } }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'calls the provided proc to coerce the event name' do
|
|
33
|
+
expect(obj).to receive(:received_message).with(msg).once
|
|
34
|
+
subject.subscribe('valid') { |msg| obj.received_message msg }
|
|
35
|
+
subject.publish :valid, msg
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context 'and two different configurations but sharing the same class' do
|
|
39
|
+
let!(:exception_pubsub) { Ably::Util::PubSub.new(coerce_into: Proc.new { raise KeyError }) }
|
|
40
|
+
|
|
41
|
+
it 'does not share state' do
|
|
42
|
+
expect(obj).to receive(:received_message).with(msg).once
|
|
43
|
+
subject.subscribe('valid') { |msg| obj.received_message msg }
|
|
44
|
+
subject.publish :valid, msg
|
|
45
|
+
|
|
46
|
+
expect { exception_pubsub.publish :fail }.to raise_error KeyError
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context 'without coercion', api_private: true do
|
|
52
|
+
it 'only matches event names on type matches' do
|
|
53
|
+
expect(obj).to_not receive(:received_message).with(msg)
|
|
54
|
+
subject.subscribe('valid') { |msg| obj.received_message msg }
|
|
55
|
+
subject.publish :valid, msg
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context '#unsubscribe' do
|
|
61
|
+
let(:callback) { Proc.new { |msg| obj.received_message msg } }
|
|
62
|
+
|
|
63
|
+
before do
|
|
64
|
+
subject.subscribe(:message, &callback)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
after do
|
|
68
|
+
subject.publish :message, msg
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'deletes matching callbacks' do
|
|
72
|
+
expect(obj).to_not receive(:received_message).with(msg)
|
|
73
|
+
subject.unsubscribe(:message, &callback)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'deletes all callbacks if not block given' do
|
|
77
|
+
expect(obj).to_not receive(:received_message).with(msg)
|
|
78
|
+
subject.unsubscribe(:message)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'continues if the block does not exist' do
|
|
82
|
+
expect(obj).to receive(:received_message).with(msg)
|
|
83
|
+
subject.unsubscribe(:message) { true }
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|