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.
Files changed (148) hide show
  1. checksums.yaml +13 -5
  2. data/.gitmodules +1 -1
  3. data/.rspec +1 -0
  4. data/.travis.yml +7 -3
  5. data/SPEC.md +495 -419
  6. data/ably-rest.gemspec +19 -5
  7. data/lib/ably-rest.rb +9 -1
  8. data/lib/submodules/ably-ruby/.gitignore +6 -0
  9. data/lib/submodules/ably-ruby/.rspec +1 -0
  10. data/lib/submodules/ably-ruby/.ruby-version.old +1 -0
  11. data/lib/submodules/ably-ruby/.travis.yml +10 -0
  12. data/lib/submodules/ably-ruby/Gemfile +4 -0
  13. data/lib/submodules/ably-ruby/LICENSE.txt +22 -0
  14. data/lib/submodules/ably-ruby/README.md +122 -0
  15. data/lib/submodules/ably-ruby/Rakefile +34 -0
  16. data/lib/submodules/ably-ruby/SPEC.md +1794 -0
  17. data/lib/submodules/ably-ruby/ably.gemspec +36 -0
  18. data/lib/submodules/ably-ruby/lib/ably.rb +12 -0
  19. data/lib/submodules/ably-ruby/lib/ably/auth.rb +438 -0
  20. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +69 -0
  21. data/lib/submodules/ably-ruby/lib/ably/logger.rb +102 -0
  22. data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +37 -0
  23. data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +223 -0
  24. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +132 -0
  25. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +108 -0
  26. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base64.rb +40 -0
  27. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/cipher.rb +83 -0
  28. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/json.rb +34 -0
  29. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/utf8.rb +26 -0
  30. data/lib/submodules/ably-ruby/lib/ably/models/nil_logger.rb +20 -0
  31. data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +173 -0
  32. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +147 -0
  33. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +210 -0
  34. data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +161 -0
  35. data/lib/submodules/ably-ruby/lib/ably/models/token.rb +74 -0
  36. data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +15 -0
  37. data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +62 -0
  38. data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +69 -0
  39. data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +100 -0
  40. data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +69 -0
  41. data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +202 -0
  42. data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +128 -0
  43. data/lib/submodules/ably-ruby/lib/ably/modules/event_machine_helpers.rb +26 -0
  44. data/lib/submodules/ably-ruby/lib/ably/modules/http_helpers.rb +41 -0
  45. data/lib/submodules/ably-ruby/lib/ably/modules/message_pack.rb +14 -0
  46. data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +41 -0
  47. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +153 -0
  48. data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +57 -0
  49. data/lib/submodules/ably-ruby/lib/ably/modules/statesman_monkey_patch.rb +33 -0
  50. data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +74 -0
  51. data/lib/submodules/ably-ruby/lib/ably/realtime.rb +64 -0
  52. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +298 -0
  53. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +92 -0
  54. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +69 -0
  55. data/lib/submodules/ably-ruby/lib/ably/realtime/channels.rb +50 -0
  56. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +184 -0
  57. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +184 -0
  58. data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +70 -0
  59. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +445 -0
  60. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +368 -0
  61. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +91 -0
  62. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +188 -0
  63. data/lib/submodules/ably-ruby/lib/ably/realtime/models/nil_channel.rb +30 -0
  64. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +564 -0
  65. data/lib/submodules/ably-ruby/lib/ably/rest.rb +43 -0
  66. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +104 -0
  67. data/lib/submodules/ably-ruby/lib/ably/rest/channels.rb +44 -0
  68. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +396 -0
  69. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/encoder.rb +49 -0
  70. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +41 -0
  71. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/external_exceptions.rb +24 -0
  72. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +17 -0
  73. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +58 -0
  74. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_json.rb +27 -0
  75. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +27 -0
  76. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +92 -0
  77. data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +105 -0
  78. data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +43 -0
  79. data/lib/submodules/ably-ruby/lib/ably/version.rb +3 -0
  80. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +154 -0
  81. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +558 -0
  82. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +119 -0
  83. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +575 -0
  84. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +785 -0
  85. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +457 -0
  86. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +55 -0
  87. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +1001 -0
  88. data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +23 -0
  89. data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +27 -0
  90. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +564 -0
  91. data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +165 -0
  92. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +134 -0
  93. data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +41 -0
  94. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +273 -0
  95. data/lib/submodules/ably-ruby/spec/acceptance/rest/encoders_spec.rb +185 -0
  96. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +247 -0
  97. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +292 -0
  98. data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +172 -0
  99. data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +15 -0
  100. data/lib/submodules/ably-ruby/spec/resources/crypto-data-128.json +56 -0
  101. data/lib/submodules/ably-ruby/spec/resources/crypto-data-256.json +56 -0
  102. data/lib/submodules/ably-ruby/spec/rspec_config.rb +57 -0
  103. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +212 -0
  104. data/lib/submodules/ably-ruby/spec/shared/model_behaviour.rb +86 -0
  105. data/lib/submodules/ably-ruby/spec/shared/protocol_msgbus_behaviour.rb +36 -0
  106. data/lib/submodules/ably-ruby/spec/spec_helper.rb +20 -0
  107. data/lib/submodules/ably-ruby/spec/support/api_helper.rb +60 -0
  108. data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +104 -0
  109. data/lib/submodules/ably-ruby/spec/support/markdown_spec_formatter.rb +118 -0
  110. data/lib/submodules/ably-ruby/spec/support/private_api_formatter.rb +36 -0
  111. data/lib/submodules/ably-ruby/spec/support/protocol_helper.rb +32 -0
  112. data/lib/submodules/ably-ruby/spec/support/random_helper.rb +15 -0
  113. data/lib/submodules/ably-ruby/spec/support/rest_testapp_before_retry.rb +15 -0
  114. data/lib/submodules/ably-ruby/spec/support/test_app.rb +113 -0
  115. data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +68 -0
  116. data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +146 -0
  117. data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +18 -0
  118. data/lib/submodules/ably-ruby/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +349 -0
  119. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/base64_spec.rb +181 -0
  120. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/cipher_spec.rb +260 -0
  121. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/json_spec.rb +135 -0
  122. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/utf8_spec.rb +56 -0
  123. data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +389 -0
  124. data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +288 -0
  125. data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +386 -0
  126. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +315 -0
  127. data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +113 -0
  128. data/lib/submodules/ably-ruby/spec/unit/models/token_spec.rb +86 -0
  129. data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +124 -0
  130. data/lib/submodules/ably-ruby/spec/unit/modules/conversions_spec.rb +72 -0
  131. data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +272 -0
  132. data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +184 -0
  133. data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +283 -0
  134. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +206 -0
  135. data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +81 -0
  136. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +30 -0
  137. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +33 -0
  138. data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +36 -0
  139. data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +111 -0
  140. data/lib/submodules/ably-ruby/spec/unit/realtime/realtime_spec.rb +9 -0
  141. data/lib/submodules/ably-ruby/spec/unit/realtime/websocket_transport_spec.rb +25 -0
  142. data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +109 -0
  143. data/lib/submodules/ably-ruby/spec/unit/rest/channels_spec.rb +79 -0
  144. data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +53 -0
  145. data/lib/submodules/ably-ruby/spec/unit/rest/rest_spec.rb +10 -0
  146. data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +87 -0
  147. data/lib/submodules/ably-ruby/spec/unit/util/pub_sub_spec.rb +86 -0
  148. metadata +182 -27
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ably::Realtime do
4
+ let(:options) { { api_key: 'app.key:secret' } }
5
+
6
+ specify 'constructor returns an Ably::Realtime::Client' do
7
+ expect(Ably::Realtime.new(options)).to be_instance_of(Ably::Realtime::Client)
8
+ end
9
+ end
@@ -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