ably-rest 0.7.5 → 0.8.1
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 +8 -8
- data/.travis.yml +2 -0
- data/README.md +41 -15
- data/SPEC.md +654 -518
- data/lib/submodules/ably-ruby/.gitignore +1 -0
- data/lib/submodules/ably-ruby/.gitmodules +3 -0
- data/lib/submodules/ably-ruby/README.md +54 -26
- data/lib/submodules/ably-ruby/SPEC.md +468 -322
- data/lib/submodules/ably-ruby/ably.gemspec +4 -2
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +185 -131
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +31 -44
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +1 -2
- data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +67 -24
- data/lib/submodules/ably-ruby/lib/ably/models/stats_types.rb +131 -0
- data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +101 -0
- data/lib/submodules/ably-ruby/lib/ably/models/token_request.rb +108 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +3 -2
- data/lib/submodules/ably-ruby/lib/ably/modules/http_helpers.rb +1 -1
- data/lib/submodules/ably-ruby/lib/ably/modules/message_emitter.rb +2 -2
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +3 -7
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +32 -5
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +1 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +4 -8
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +5 -3
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +12 -1
- data/lib/submodules/ably-ruby/lib/ably/rest.rb +3 -7
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +13 -10
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +19 -20
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +14 -12
- data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +74 -23
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +3 -3
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +18 -18
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +5 -5
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +12 -12
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +5 -5
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +56 -13
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +8 -8
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +262 -158
- data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +11 -9
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +28 -21
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +30 -27
- data/lib/submodules/ably-ruby/spec/acceptance/rest/encoders_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +10 -10
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +93 -56
- data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +50 -45
- data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/rspec_config.rb +3 -2
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +36 -28
- data/lib/submodules/ably-ruby/spec/spec_helper.rb +3 -0
- data/lib/submodules/ably-ruby/spec/support/api_helper.rb +3 -3
- data/lib/submodules/ably-ruby/spec/support/markdown_spec_formatter.rb +1 -1
- data/lib/submodules/ably-ruby/spec/support/test_app.rb +20 -33
- data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +18 -1
- data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +81 -72
- data/lib/submodules/ably-ruby/spec/unit/models/stats_spec.rb +289 -0
- data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +111 -0
- data/lib/submodules/ably-ruby/spec/unit/models/token_request_spec.rb +110 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/realtime/realtime_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +8 -8
- data/lib/submodules/ably-ruby/spec/unit/rest/rest_spec.rb +1 -1
- data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +1 -1
- metadata +9 -7
- data/lib/submodules/ably-ruby/lib/ably/models/token.rb +0 -74
- data/lib/submodules/ably-ruby/spec/resources/crypto-data-128.json +0 -56
- data/lib/submodules/ably-ruby/spec/resources/crypto-data-256.json +0 -56
- data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +0 -113
- data/lib/submodules/ably-ruby/spec/unit/models/token_spec.rb +0 -86
|
@@ -7,7 +7,7 @@ describe Ably::Rest do
|
|
|
7
7
|
|
|
8
8
|
let(:client_options) { {} }
|
|
9
9
|
let(:client) do
|
|
10
|
-
Ably::Rest::Client.new(client_options.merge(
|
|
10
|
+
Ably::Rest::Client.new(client_options.merge(key: 'appid.keyuid:keysecret'))
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
let(:now) { Time.now - 1000 }
|
|
@@ -67,13 +67,13 @@ describe Ably::Rest do
|
|
|
67
67
|
|
|
68
68
|
vary_by_protocol do
|
|
69
69
|
let(:client) do
|
|
70
|
-
Ably::Rest::Client.new(
|
|
70
|
+
Ably::Rest::Client.new(key: api_key, environment: environment, protocol: protocol)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
describe 'failed requests' do
|
|
74
74
|
context 'due to invalid Auth' do
|
|
75
75
|
it 'should raise an InvalidRequest exception with a valid error message and code' do
|
|
76
|
-
invalid_client = Ably::Rest::Client.new(
|
|
76
|
+
invalid_client = Ably::Rest::Client.new(key: 'appid.keyuid:keysecret', environment: environment)
|
|
77
77
|
expect { invalid_client.channel('test').publish('foo', 'choo') }.to raise_error do |error|
|
|
78
78
|
expect(error).to be_a(Ably::Exceptions::InvalidRequest)
|
|
79
79
|
expect(error.message).to match(/invalid credentials/)
|
|
@@ -109,18 +109,18 @@ describe Ably::Rest do
|
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
describe 'token authentication failures', :webmock do
|
|
112
|
-
let(:token_1) { {
|
|
113
|
-
let(:token_2) { {
|
|
114
|
-
let(:channel) {
|
|
112
|
+
let(:token_1) { { token: random_str } }
|
|
113
|
+
let(:token_2) { { token: random_str } }
|
|
114
|
+
let(:channel) { random_str }
|
|
115
115
|
|
|
116
116
|
before do
|
|
117
117
|
@token_requests = 0
|
|
118
118
|
@publish_attempts = 0
|
|
119
119
|
|
|
120
|
-
stub_request(:post, "#{client.endpoint}/keys/#{
|
|
120
|
+
stub_request(:post, "#{client.endpoint}/keys/#{key_name}/requestToken").to_return do
|
|
121
121
|
@token_requests += 1
|
|
122
122
|
{
|
|
123
|
-
:body =>
|
|
123
|
+
:body => public_send("token_#{@token_requests}").merge(expires: (Time.now.to_i + 60) * 1000).to_json,
|
|
124
124
|
:headers => { 'Content-Type' => 'application/json' }
|
|
125
125
|
}
|
|
126
126
|
end
|
|
@@ -143,7 +143,9 @@ describe Ably::Rest do
|
|
|
143
143
|
it 'should automatically reissue a token' do
|
|
144
144
|
client.channel(channel).publish('evt', 'msg')
|
|
145
145
|
expect(@publish_attempts).to eql(1)
|
|
146
|
+
expect(@token_requests).to eql(1)
|
|
146
147
|
|
|
148
|
+
# Triggers an authentication 401 failure which should automatically request a new token
|
|
147
149
|
client.channel(channel).publish('evt', 'msg')
|
|
148
150
|
expect(@publish_attempts).to eql(3)
|
|
149
151
|
expect(@token_requests).to eql(2)
|
|
@@ -151,7 +153,7 @@ describe Ably::Rest do
|
|
|
151
153
|
end
|
|
152
154
|
|
|
153
155
|
context 'when NOT auth#token_renewable?' do
|
|
154
|
-
let(:client) { Ably::Rest::Client.new(
|
|
156
|
+
let(:client) { Ably::Rest::Client.new(token: 'token ID cannot be used to create a new token', environment: environment, protocol: protocol) }
|
|
155
157
|
|
|
156
158
|
it 'should raise an InvalidToken exception' do
|
|
157
159
|
client.channel(channel).publish('evt', 'msg')
|
|
@@ -6,7 +6,7 @@ describe Ably::Rest::Channel do
|
|
|
6
6
|
|
|
7
7
|
vary_by_protocol do
|
|
8
8
|
let(:client) do
|
|
9
|
-
Ably::Rest::Client.new(
|
|
9
|
+
Ably::Rest::Client.new(key: api_key, environment: environment, protocol: protocol)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
describe '#publish' do
|
|
@@ -14,7 +14,7 @@ describe Ably::Rest::Channel do
|
|
|
14
14
|
let(:event) { 'foo' }
|
|
15
15
|
let(:message) { 'woop!' }
|
|
16
16
|
|
|
17
|
-
it 'should publish the message
|
|
17
|
+
it 'should publish the message and return true indicating success' do
|
|
18
18
|
expect(channel.publish(event, message)).to eql(true)
|
|
19
19
|
end
|
|
20
20
|
end
|
|
@@ -37,20 +37,20 @@ describe Ably::Rest::Channel do
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
it 'should return the current message history for the channel' do
|
|
40
|
-
|
|
40
|
+
actual_history_items = channel.history.items
|
|
41
41
|
|
|
42
|
-
expect(
|
|
42
|
+
expect(actual_history_items.size).to eql(3)
|
|
43
43
|
|
|
44
44
|
expected_history.each do |message|
|
|
45
45
|
message_name, message_data = message[:name], message[:data]
|
|
46
|
-
matching_message =
|
|
46
|
+
matching_message = actual_history_items.find { |message| message.name == message_name && message.data == message_data }
|
|
47
47
|
expect(matching_message).to be_a(Ably::Models::Message)
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
context 'message timestamps' do
|
|
52
52
|
it 'should all be after the messages were published' do
|
|
53
|
-
channel.history.each do |message|
|
|
53
|
+
channel.history.items.each do |message|
|
|
54
54
|
expect(before_published.to_f).to be < message.timestamp.to_f
|
|
55
55
|
end
|
|
56
56
|
end
|
|
@@ -58,7 +58,7 @@ describe Ably::Rest::Channel do
|
|
|
58
58
|
|
|
59
59
|
context 'message IDs' do
|
|
60
60
|
it 'should be unique' do
|
|
61
|
-
message_ids = channel.history.map(&:id).compact
|
|
61
|
+
message_ids = channel.history.items.map(&:id).compact
|
|
62
62
|
expect(message_ids.count).to eql(3)
|
|
63
63
|
expect(message_ids.uniq.count).to eql(3)
|
|
64
64
|
end
|
|
@@ -66,25 +66,25 @@ describe Ably::Rest::Channel do
|
|
|
66
66
|
|
|
67
67
|
it 'should return paged history using the PaginatedResource model' do
|
|
68
68
|
page_1 = channel.history(limit: 1)
|
|
69
|
-
page_2 = page_1.
|
|
70
|
-
page_3 = page_2.
|
|
69
|
+
page_2 = page_1.next
|
|
70
|
+
page_3 = page_2.next
|
|
71
71
|
|
|
72
|
-
all_items = [page_1[0].id, page_2[0].id, page_3[0].id]
|
|
72
|
+
all_items = [page_1.items[0].id, page_2.items[0].id, page_3.items[0].id]
|
|
73
73
|
expect(all_items.uniq).to eql(all_items)
|
|
74
74
|
|
|
75
|
-
expect(page_1.size).to eql(1)
|
|
76
|
-
expect(page_1).to_not
|
|
77
|
-
expect(page_1).to
|
|
75
|
+
expect(page_1.items.size).to eql(1)
|
|
76
|
+
expect(page_1).to_not be_last
|
|
77
|
+
expect(page_1).to be_first
|
|
78
78
|
|
|
79
79
|
# Page 2
|
|
80
|
-
expect(page_2.size).to eql(1)
|
|
81
|
-
expect(page_2).to_not
|
|
82
|
-
expect(page_2).to_not
|
|
80
|
+
expect(page_2.items.size).to eql(1)
|
|
81
|
+
expect(page_2).to_not be_last
|
|
82
|
+
expect(page_2).to_not be_first
|
|
83
83
|
|
|
84
84
|
# Page 3
|
|
85
|
-
expect(page_3.size).to eql(1)
|
|
86
|
-
expect(page_3).to
|
|
87
|
-
expect(page_3).to_not
|
|
85
|
+
expect(page_3.items.size).to eql(1)
|
|
86
|
+
expect(page_3).to be_last
|
|
87
|
+
expect(page_3).to_not be_first
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
90
|
|
|
@@ -93,15 +93,22 @@ describe Ably::Rest::Channel do
|
|
|
93
93
|
let(:channel) { client.channel(channel_name) }
|
|
94
94
|
let(:endpoint) do
|
|
95
95
|
client.endpoint.tap do |client_end_point|
|
|
96
|
-
client_end_point.user =
|
|
96
|
+
client_end_point.user = key_name
|
|
97
97
|
client_end_point.password = key_secret
|
|
98
98
|
end
|
|
99
99
|
end
|
|
100
|
+
let(:default_options) do
|
|
101
|
+
{
|
|
102
|
+
direction: :backwards,
|
|
103
|
+
limit: 100
|
|
104
|
+
}
|
|
105
|
+
end
|
|
100
106
|
|
|
101
107
|
[:start, :end].each do |option|
|
|
102
108
|
describe ":#{option}", :webmock do
|
|
103
109
|
let!(:history_stub) {
|
|
104
|
-
|
|
110
|
+
query_params = default_options.merge(option => milliseconds).map { |k, v| "#{k}=#{v}" }.join('&')
|
|
111
|
+
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/messages?#{query_params}").
|
|
105
112
|
to_return(:body => '{}', :headers => { 'Content-Type' => 'application/json' })
|
|
106
113
|
}
|
|
107
114
|
|
|
@@ -15,7 +15,7 @@ describe Ably::Rest::Channels do
|
|
|
15
15
|
|
|
16
16
|
vary_by_protocol do
|
|
17
17
|
let(:client) do
|
|
18
|
-
Ably::Rest::Client.new(
|
|
18
|
+
Ably::Rest::Client.new(key: api_key, environment: environment, protocol: protocol)
|
|
19
19
|
end
|
|
20
20
|
let(:channel_name) { random_str }
|
|
21
21
|
let(:options) { { key: 'value' } }
|
|
@@ -12,14 +12,14 @@ describe Ably::Rest::Client do
|
|
|
12
12
|
|
|
13
13
|
context '#initialize' do
|
|
14
14
|
let(:client_id) { random_str }
|
|
15
|
-
let(:token_request) { client.auth.create_token_request(
|
|
15
|
+
let(:token_request) { client.auth.create_token_request(key_name: key_name, key_secret: key_secret, client_id: client_id) }
|
|
16
16
|
|
|
17
|
-
context 'with
|
|
18
|
-
let(:client) { Ably::Rest::Client.new(client_options
|
|
17
|
+
context 'with a :auth_callback Proc' do
|
|
18
|
+
let(:client) { Ably::Rest::Client.new(client_options.merge(auth_callback: Proc.new { token_request })) }
|
|
19
19
|
|
|
20
|
-
it 'calls the
|
|
21
|
-
expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.
|
|
22
|
-
expect(client.auth.
|
|
20
|
+
it 'calls the auth Proc to get a new token' do
|
|
21
|
+
expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.current_token_details }
|
|
22
|
+
expect(client.auth.current_token_details.client_id).to eql(client_id)
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
@@ -32,54 +32,57 @@ describe Ably::Rest::Client do
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
it 'sends an HTTP request to the provided URL to get a new token' do
|
|
35
|
-
expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.
|
|
36
|
-
expect(client.auth.
|
|
35
|
+
expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.current_token_details }
|
|
36
|
+
expect(client.auth.current_token_details.client_id).to eql(client_id)
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
context 'using tokens' do
|
|
42
42
|
let(:client) do
|
|
43
|
-
Ably::Rest::Client.new(client_options
|
|
43
|
+
Ably::Rest::Client.new(client_options.merge(auth_callback: Proc.new do
|
|
44
44
|
@request_index ||= 0
|
|
45
45
|
@request_index += 1
|
|
46
|
-
send("token_request_#{@request_index}")
|
|
47
|
-
end
|
|
46
|
+
send("token_request_#{@request_index > 2 ? 'next' : @request_index}")
|
|
47
|
+
end))
|
|
48
48
|
end
|
|
49
49
|
let(:token_request_1) { client.auth.create_token_request(token_request_options.merge(client_id: random_str)) }
|
|
50
50
|
let(:token_request_2) { client.auth.create_token_request(token_request_options.merge(client_id: random_str)) }
|
|
51
51
|
|
|
52
|
+
# If token expires against whilst runnig tests in a slower CI environment then use this token
|
|
53
|
+
let(:token_request_next) { client.auth.create_token_request(token_request_options.merge(client_id: random_str)) }
|
|
54
|
+
|
|
52
55
|
context 'when expired' do
|
|
53
|
-
let(:token_request_options) { {
|
|
56
|
+
let(:token_request_options) { { key_name: key_name, key_secret: key_secret, ttl: Ably::Models::TokenDetails::TOKEN_EXPIRY_BUFFER } }
|
|
54
57
|
|
|
55
58
|
it 'creates a new token automatically when the old token expires' do
|
|
56
|
-
expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.
|
|
57
|
-
expect(client.auth.
|
|
59
|
+
expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.current_token_details }
|
|
60
|
+
expect(client.auth.current_token_details.client_id).to eql(token_request_1.client_id)
|
|
58
61
|
|
|
59
62
|
sleep 1
|
|
60
63
|
|
|
61
|
-
expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.
|
|
62
|
-
expect(client.auth.
|
|
64
|
+
expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.current_token_details }
|
|
65
|
+
expect(client.auth.current_token_details.client_id).to eql(token_request_2.client_id)
|
|
63
66
|
end
|
|
64
67
|
end
|
|
65
68
|
|
|
66
69
|
context 'when token has not expired' do
|
|
67
|
-
let(:token_request_options) { {
|
|
70
|
+
let(:token_request_options) { { key_name: key_name, key_secret: key_secret, ttl: 3600 } }
|
|
68
71
|
|
|
69
72
|
it 'reuses the existing token for every request' do
|
|
70
|
-
expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.
|
|
71
|
-
expect(client.auth.
|
|
73
|
+
expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.current_token_details }
|
|
74
|
+
expect(client.auth.current_token_details.client_id).to eql(token_request_1.client_id)
|
|
72
75
|
|
|
73
76
|
sleep 1
|
|
74
77
|
|
|
75
|
-
expect { client.channel('channel_name').publish('event', 'message') }.to_not change { client.auth.
|
|
76
|
-
expect(client.auth.
|
|
78
|
+
expect { client.channel('channel_name').publish('event', 'message') }.to_not change { client.auth.current_token_details }
|
|
79
|
+
expect(client.auth.current_token_details.client_id).to eql(token_request_1.client_id)
|
|
77
80
|
end
|
|
78
81
|
end
|
|
79
82
|
end
|
|
80
83
|
|
|
81
84
|
context 'connection transport' do
|
|
82
|
-
let(:client_options) { default_options.merge(
|
|
85
|
+
let(:client_options) { default_options.merge(key: api_key) }
|
|
83
86
|
|
|
84
87
|
context 'for default host' do
|
|
85
88
|
it "is configured to timeout connection opening in #{connection_retry.fetch(:single_request_open_timeout)} seconds" do
|
|
@@ -107,7 +110,7 @@ describe Ably::Rest::Client do
|
|
|
107
110
|
let(:publish_block) { proc { client.channel('test').publish('event', 'data') } }
|
|
108
111
|
|
|
109
112
|
context 'configured' do
|
|
110
|
-
let(:client_options) { default_options.merge(
|
|
113
|
+
let(:client_options) { default_options.merge(key: api_key) }
|
|
111
114
|
|
|
112
115
|
it 'should make connection attempts to A.ably-realtime.com, B.ably-realtime.com, C.ably-realtime.com, D.ably-realtime.com, E.ably-realtime.com' do
|
|
113
116
|
hosts = []
|
|
@@ -119,7 +122,7 @@ describe Ably::Rest::Client do
|
|
|
119
122
|
end
|
|
120
123
|
|
|
121
124
|
context 'when environment is NOT production' do
|
|
122
|
-
let(:client_options) { default_options.merge(environment: 'sandbox',
|
|
125
|
+
let(:client_options) { default_options.merge(environment: 'sandbox', key: api_key) }
|
|
123
126
|
let!(:default_host_request_stub) do
|
|
124
127
|
stub_request(:post, "https://#{api_key}@#{environment}-#{Ably::Rest::Client::DOMAIN}#{path}").to_return do
|
|
125
128
|
raise Faraday::TimeoutError.new('timeout error message')
|
|
@@ -135,7 +138,7 @@ describe Ably::Rest::Client do
|
|
|
135
138
|
let(:custom_hosts) { %w(A.ably-realtime.com B.ably-realtime.com) }
|
|
136
139
|
let(:max_attempts) { 2 }
|
|
137
140
|
let(:cumulative_timeout) { 0.5 }
|
|
138
|
-
let(:client_options) { default_options.merge(environment: nil,
|
|
141
|
+
let(:client_options) { default_options.merge(environment: nil, key: api_key) }
|
|
139
142
|
|
|
140
143
|
before do
|
|
141
144
|
stub_const 'Ably::FALLBACK_HOSTS', custom_hosts
|
|
@@ -209,7 +212,7 @@ describe Ably::Rest::Client do
|
|
|
209
212
|
|
|
210
213
|
context 'with a custom host' do
|
|
211
214
|
let(:custom_host) { 'host.does.not.exist' }
|
|
212
|
-
let(:client_options) { default_options.merge(
|
|
215
|
+
let(:client_options) { default_options.merge(key: api_key, rest_host: custom_host) }
|
|
213
216
|
let(:capability) { { :foo => ["publish"] } }
|
|
214
217
|
|
|
215
218
|
context 'that does not exist' do
|
|
@@ -242,7 +245,7 @@ describe Ably::Rest::Client do
|
|
|
242
245
|
end
|
|
243
246
|
|
|
244
247
|
context 'that times out', :webmock do
|
|
245
|
-
let(:path) { '/keys/app_id.
|
|
248
|
+
let(:path) { '/keys/app_id.key_name/requestToken' }
|
|
246
249
|
let!(:custom_host_request_stub) do
|
|
247
250
|
stub_request(:post, "https://#{custom_host}#{path}").to_return do
|
|
248
251
|
raise Faraday::TimeoutError.new('timeout error message')
|
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
|
3
3
|
require 'base64'
|
|
4
4
|
|
|
5
5
|
describe Ably::Models::MessageEncoders do
|
|
6
|
-
let(:default_client_options) { {
|
|
6
|
+
let(:default_client_options) { { key: api_key, environment: environment } }
|
|
7
7
|
let(:client) { Ably::Rest::Client.new(default_client_options.merge(protocol: protocol)) }
|
|
8
8
|
let(:channel_options) { {} }
|
|
9
9
|
let(:channel) { client.channel('test', channel_options) }
|
|
@@ -6,7 +6,7 @@ describe Ably::Rest::Channel, 'messages' do
|
|
|
6
6
|
include Ably::Modules::Conversions
|
|
7
7
|
|
|
8
8
|
vary_by_protocol do
|
|
9
|
-
let(:default_client_options) { {
|
|
9
|
+
let(:default_client_options) { { key: api_key, environment: environment, protocol: protocol } }
|
|
10
10
|
let(:client_options) { default_client_options }
|
|
11
11
|
let(:client) { Ably::Rest::Client.new(client_options) }
|
|
12
12
|
let(:other_client) { Ably::Rest::Client.new(client_options) }
|
|
@@ -17,7 +17,7 @@ describe Ably::Rest::Channel, 'messages' do
|
|
|
17
17
|
|
|
18
18
|
it 'is converted into UTF_8' do
|
|
19
19
|
channel.publish message_name, 'example'
|
|
20
|
-
message = channel.history.first
|
|
20
|
+
message = channel.history.items.first
|
|
21
21
|
expect(message.name.encoding).to eql(Encoding::UTF_8)
|
|
22
22
|
expect(message.name.encode(Encoding::ASCII_8BIT)).to eql(message_name)
|
|
23
23
|
end
|
|
@@ -80,13 +80,13 @@ describe Ably::Rest::Channel, 'messages' do
|
|
|
80
80
|
it 'sends and retrieves messages that are encrypted & decrypted by the Ably library' do
|
|
81
81
|
encrypted_channel.publish 'example', encoded_data_decoded
|
|
82
82
|
|
|
83
|
-
message = encrypted_channel.history.first
|
|
83
|
+
message = encrypted_channel.history.items.first
|
|
84
84
|
expect(message.data).to eql(encoded_data_decoded)
|
|
85
85
|
expect(message.encoding).to be_nil
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
-
resources_root = File.expand_path('
|
|
89
|
+
resources_root = File.expand_path('../../../../lib/submodules/ably-common/test-resources', __FILE__)
|
|
90
90
|
|
|
91
91
|
def self.add_tests_for_data(data)
|
|
92
92
|
data['items'].each_with_index do |item, index|
|
|
@@ -115,7 +115,7 @@ describe Ably::Rest::Channel, 'messages' do
|
|
|
115
115
|
encrypted_channel.publish index.to_s, "#{index}-#{data}"
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
-
messages = encrypted_channel.history
|
|
118
|
+
messages = encrypted_channel.history.items
|
|
119
119
|
|
|
120
120
|
expect(messages.count).to eql(message_count)
|
|
121
121
|
messages.each do |message|
|
|
@@ -140,7 +140,7 @@ describe Ably::Rest::Channel, 'messages' do
|
|
|
140
140
|
specify "delivers a #{payload_description} payload to the receiver" do
|
|
141
141
|
encrypted_channel.publish 'example', payload
|
|
142
142
|
|
|
143
|
-
message = other_client_channel.history.first
|
|
143
|
+
message = other_client_channel.history.items.first
|
|
144
144
|
expect(message.data).to eql(payload)
|
|
145
145
|
expect(message.encoding).to be_nil
|
|
146
146
|
end
|
|
@@ -156,7 +156,7 @@ describe Ably::Rest::Channel, 'messages' do
|
|
|
156
156
|
it 'does not attempt to decrypt the message' do
|
|
157
157
|
unencrypted_channel.publish 'example', payload
|
|
158
158
|
|
|
159
|
-
message = other_client_encrypted_channel.history.first
|
|
159
|
+
message = other_client_encrypted_channel.history.items.first
|
|
160
160
|
expect(message.data).to eql(payload)
|
|
161
161
|
expect(message.encoding).to be_nil
|
|
162
162
|
end
|
|
@@ -175,7 +175,7 @@ describe Ably::Rest::Channel, 'messages' do
|
|
|
175
175
|
end
|
|
176
176
|
|
|
177
177
|
it 'retrieves the message that remains encrypted with an encrypted encoding attribute' do
|
|
178
|
-
message = other_client_unencrypted_channel.history.first
|
|
178
|
+
message = other_client_unencrypted_channel.history.items.first
|
|
179
179
|
expect(message.data).to_not eql(payload)
|
|
180
180
|
expect(message.encoding).to match(/^cipher\+aes-256-cbc/)
|
|
181
181
|
end
|
|
@@ -202,7 +202,7 @@ describe Ably::Rest::Channel, 'messages' do
|
|
|
202
202
|
end
|
|
203
203
|
|
|
204
204
|
it 'retrieves the message that remains encrypted with an encrypted encoding attribute' do
|
|
205
|
-
message = encrypted_channel_client2.history.first
|
|
205
|
+
message = encrypted_channel_client2.history.items.first
|
|
206
206
|
expect(message.data).to_not eql(payload)
|
|
207
207
|
expect(message.encoding).to match(/^cipher\+aes-256-cbc/)
|
|
208
208
|
end
|
|
@@ -229,7 +229,7 @@ describe Ably::Rest::Channel, 'messages' do
|
|
|
229
229
|
end
|
|
230
230
|
|
|
231
231
|
it 'retrieves the message that remains encrypted with an encrypted encoding attribute' do
|
|
232
|
-
message = encrypted_channel_client2.history.first
|
|
232
|
+
message = encrypted_channel_client2.history.items.first
|
|
233
233
|
expect(message.data).to_not eql(payload)
|
|
234
234
|
expect(message.encoding).to match(/^cipher\+aes-256-cbc/)
|
|
235
235
|
end
|
|
@@ -5,7 +5,7 @@ describe Ably::Rest::Presence do
|
|
|
5
5
|
include Ably::Modules::Conversions
|
|
6
6
|
|
|
7
7
|
vary_by_protocol do
|
|
8
|
-
let(:default_options) { {
|
|
8
|
+
let(:default_options) { { key: api_key, environment: environment, protocol: protocol } }
|
|
9
9
|
let(:client_options) { default_options }
|
|
10
10
|
let(:client) do
|
|
11
11
|
Ably::Rest::Client.new(client_options)
|
|
@@ -16,88 +16,93 @@ describe Ably::Rest::Presence do
|
|
|
16
16
|
IdiomaticRubyWrapper(fixture, stop_at: [:data])
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
|
+
let(:non_encoded_fixtures) { fixtures.reject { |fixture| fixture['encoding'] } }
|
|
20
|
+
|
|
21
|
+
# Encrypted fixtures need encryption details or an error will be raised
|
|
22
|
+
let(:cipher_details) { TestApp::APP_SPEC_CIPHER }
|
|
23
|
+
let(:algorithm) { cipher_details.fetch('algorithm').upcase }
|
|
24
|
+
let(:mode) { cipher_details.fetch('mode').upcase }
|
|
25
|
+
let(:key_length) { cipher_details.fetch('keylength') }
|
|
26
|
+
let(:secret_key) { Base64.decode64(cipher_details.fetch('key')) }
|
|
27
|
+
let(:iv) { Base64.decode64(cipher_details.fetch('iv')) }
|
|
28
|
+
|
|
29
|
+
let(:cipher_options) { { key: secret_key, algorithm: algorithm, mode: mode, key_length: key_length, iv: iv } }
|
|
30
|
+
let(:fixtures_channel) { client.channel('persisted:presence_fixtures', encrypted: true, cipher_params: cipher_options, iv: iv) }
|
|
19
31
|
|
|
20
32
|
context 'tested against presence fixture data set up in test app' do
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
end
|
|
33
|
+
before(:context) do
|
|
34
|
+
# When this test is run as a part of a test suite, the presence data injected in the test app may have expired
|
|
35
|
+
reload_test_app
|
|
36
|
+
end
|
|
26
37
|
|
|
27
|
-
|
|
28
|
-
let(:
|
|
38
|
+
describe '#get' do
|
|
39
|
+
let(:presence_page) { fixtures_channel.presence.get }
|
|
29
40
|
|
|
30
41
|
it 'returns current members on the channel with their action set to :present' do
|
|
31
|
-
expect(
|
|
42
|
+
expect(presence_page.items.size).to eql(fixtures.count)
|
|
32
43
|
|
|
33
|
-
|
|
34
|
-
presence_message =
|
|
44
|
+
non_encoded_fixtures.each do |fixture|
|
|
45
|
+
presence_message = presence_page.items.find { |client| client.client_id == fixture[:client_id] }
|
|
35
46
|
expect(presence_message.data).to eq(fixture[:data])
|
|
36
47
|
expect(presence_message.action).to eq(:present)
|
|
37
48
|
end
|
|
38
49
|
end
|
|
39
50
|
|
|
40
51
|
context 'with :limit option' do
|
|
41
|
-
let(:page_size) {
|
|
42
|
-
let(:
|
|
52
|
+
let(:page_size) { 3 }
|
|
53
|
+
let(:presence_page) { fixtures_channel.presence.get(limit: page_size) }
|
|
43
54
|
|
|
44
55
|
it 'returns a paged response limiting number of members per page' do
|
|
45
|
-
expect(
|
|
46
|
-
next_page =
|
|
47
|
-
expect(next_page.size).to eql(
|
|
48
|
-
expect(next_page).to
|
|
56
|
+
expect(presence_page.items.size).to eql(page_size)
|
|
57
|
+
next_page = presence_page.next
|
|
58
|
+
expect(next_page.items.size).to eql(page_size)
|
|
59
|
+
expect(next_page).to be_last
|
|
49
60
|
end
|
|
50
61
|
end
|
|
51
62
|
end
|
|
52
63
|
|
|
53
64
|
describe '#history' do
|
|
54
|
-
|
|
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 }
|
|
65
|
+
let(:history_page) { fixtures_channel.presence.history }
|
|
61
66
|
|
|
62
67
|
it 'returns recent presence activity' do
|
|
63
|
-
expect(
|
|
68
|
+
expect(history_page.items.size).to eql(fixtures.count)
|
|
64
69
|
|
|
65
|
-
|
|
66
|
-
presence_message =
|
|
70
|
+
non_encoded_fixtures.each do |fixture|
|
|
71
|
+
presence_message = history_page.items.find { |client| client.client_id == fixture['clientId'] }
|
|
67
72
|
expect(presence_message.data).to eq(fixture[:data])
|
|
68
73
|
end
|
|
69
74
|
end
|
|
70
75
|
|
|
71
76
|
context 'with options' do
|
|
72
|
-
let(:page_size) {
|
|
77
|
+
let(:page_size) { 3 }
|
|
73
78
|
|
|
74
79
|
context 'direction: :forwards' do
|
|
75
|
-
let(:
|
|
76
|
-
let(:paged_history_forward) {
|
|
80
|
+
let(:history_page) { fixtures_channel.presence.history(direction: :forwards) }
|
|
81
|
+
let(:paged_history_forward) { fixtures_channel.presence.history(limit: page_size, direction: :forwards) }
|
|
77
82
|
|
|
78
83
|
it 'returns recent presence activity forwards with most recent history last' do
|
|
79
84
|
expect(paged_history_forward).to be_a(Ably::Models::PaginatedResource)
|
|
80
|
-
expect(paged_history_forward.size).to eql(
|
|
85
|
+
expect(paged_history_forward.items.size).to eql(page_size)
|
|
81
86
|
|
|
82
|
-
next_page = paged_history_forward.
|
|
87
|
+
next_page = paged_history_forward.next
|
|
83
88
|
|
|
84
|
-
expect(paged_history_forward.first.id).to eql(
|
|
85
|
-
expect(next_page.first.id).to eql(
|
|
89
|
+
expect(paged_history_forward.items.first.id).to eql(history_page.items.first.id)
|
|
90
|
+
expect(next_page.items.first.id).to eql(history_page.items[page_size].id)
|
|
86
91
|
end
|
|
87
92
|
end
|
|
88
93
|
|
|
89
94
|
context 'direction: :backwards' do
|
|
90
|
-
let(:
|
|
91
|
-
let(:paged_history_backward) {
|
|
95
|
+
let(:history_page) { fixtures_channel.presence.history(direction: :backwards) }
|
|
96
|
+
let(:paged_history_backward) { fixtures_channel.presence.history(limit: page_size, direction: :backwards) }
|
|
92
97
|
|
|
93
98
|
it 'returns recent presence activity backwards with most recent history first' do
|
|
94
99
|
expect(paged_history_backward).to be_a(Ably::Models::PaginatedResource)
|
|
95
|
-
expect(paged_history_backward.size).to eql(
|
|
100
|
+
expect(paged_history_backward.items.size).to eql(page_size)
|
|
96
101
|
|
|
97
|
-
next_page = paged_history_backward.
|
|
102
|
+
next_page = paged_history_backward.next
|
|
98
103
|
|
|
99
|
-
expect(paged_history_backward.first.id).to eql(
|
|
100
|
-
expect(next_page.first.id).to eql(
|
|
104
|
+
expect(paged_history_backward.items.first.id).to eql(history_page.items.first.id)
|
|
105
|
+
expect(next_page.items.first.id).to eql(history_page.items[page_size].id)
|
|
101
106
|
end
|
|
102
107
|
end
|
|
103
108
|
end
|
|
@@ -117,13 +122,20 @@ describe Ably::Rest::Presence do
|
|
|
117
122
|
end
|
|
118
123
|
end
|
|
119
124
|
let(:client) do
|
|
120
|
-
Ably::Rest::Client.new(
|
|
125
|
+
Ably::Rest::Client.new(key: "#{user}:#{secret}")
|
|
126
|
+
end
|
|
127
|
+
let(:default_options) do
|
|
128
|
+
{
|
|
129
|
+
direction: :backwards,
|
|
130
|
+
limit: 100
|
|
131
|
+
}
|
|
121
132
|
end
|
|
122
133
|
|
|
123
134
|
[:start, :end].each do |option|
|
|
124
135
|
describe ":#{option}", :webmock do
|
|
125
136
|
let!(:history_stub) {
|
|
126
|
-
|
|
137
|
+
query_params = default_options.merge(option => milliseconds).map { |k, v| "#{k}=#{v}" }.join('&')
|
|
138
|
+
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence/history?#{query_params}").
|
|
127
139
|
to_return(:body => '{}', :headers => { 'Content-Type' => 'application/json' })
|
|
128
140
|
}
|
|
129
141
|
|
|
@@ -154,7 +166,32 @@ describe Ably::Rest::Presence do
|
|
|
154
166
|
end
|
|
155
167
|
end
|
|
156
168
|
|
|
157
|
-
describe 'decoding'
|
|
169
|
+
describe 'decoding' do
|
|
170
|
+
context 'with encoded fixture data' do
|
|
171
|
+
let(:decoded_client_id) { 'client_decoded' }
|
|
172
|
+
let(:encoded_client_id) { 'client_encoded' }
|
|
173
|
+
|
|
174
|
+
def message(client_id, messages)
|
|
175
|
+
messages.items.find { |message| message.client_id == client_id }
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
describe '#history' do
|
|
179
|
+
let(:history) { fixtures_channel.presence.history }
|
|
180
|
+
it 'decodes encoded and encryped presence fixture data automatically' do
|
|
181
|
+
expect(message(decoded_client_id, history).data).to eql(message(encoded_client_id, history).data)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
describe '#get' do
|
|
186
|
+
let(:present) { fixtures_channel.presence.get }
|
|
187
|
+
it 'decodes encoded and encryped presence fixture data automatically' do
|
|
188
|
+
expect(message(decoded_client_id, present).data).to eql(message(encoded_client_id, present).data)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
describe 'decoding permutations using mocked #history', :webmock do
|
|
158
195
|
let(:user) { 'appid.keyuid' }
|
|
159
196
|
let(:secret) { random_str(8) }
|
|
160
197
|
let(:endpoint) do
|
|
@@ -164,7 +201,7 @@ describe Ably::Rest::Presence do
|
|
|
164
201
|
end
|
|
165
202
|
end
|
|
166
203
|
let(:client) do
|
|
167
|
-
Ably::Rest::Client.new(client_options.merge(
|
|
204
|
+
Ably::Rest::Client.new(client_options.merge(key: "#{user}:#{secret}"))
|
|
168
205
|
end
|
|
169
206
|
|
|
170
207
|
let(:data) { random_str(32) }
|
|
@@ -195,7 +232,7 @@ describe Ably::Rest::Presence do
|
|
|
195
232
|
|
|
196
233
|
context '#get' do
|
|
197
234
|
let!(:get_stub) {
|
|
198
|
-
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence").
|
|
235
|
+
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence?limit=100").
|
|
199
236
|
to_return(:body => serialized_encoded_message, :headers => { 'Content-Type' => content_type })
|
|
200
237
|
}
|
|
201
238
|
|
|
@@ -204,15 +241,15 @@ describe Ably::Rest::Presence do
|
|
|
204
241
|
end
|
|
205
242
|
|
|
206
243
|
it 'automaticaly decodes presence messages' do
|
|
207
|
-
|
|
208
|
-
expect(
|
|
209
|
-
expect(
|
|
244
|
+
present_page = presence.get
|
|
245
|
+
expect(present_page.items.first.encoding).to be_nil
|
|
246
|
+
expect(present_page.items.first.data).to eql(data)
|
|
210
247
|
end
|
|
211
248
|
end
|
|
212
249
|
|
|
213
250
|
context '#history' do
|
|
214
251
|
let!(:history_stub) {
|
|
215
|
-
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence/history").
|
|
252
|
+
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence/history?direction=backwards&limit=100").
|
|
216
253
|
to_return(:body => serialized_encoded_message, :headers => { 'Content-Type' => content_type })
|
|
217
254
|
}
|
|
218
255
|
|
|
@@ -221,9 +258,9 @@ describe Ably::Rest::Presence do
|
|
|
221
258
|
end
|
|
222
259
|
|
|
223
260
|
it 'automaticaly decodes presence messages' do
|
|
224
|
-
|
|
225
|
-
expect(
|
|
226
|
-
expect(
|
|
261
|
+
history_page = presence.history
|
|
262
|
+
expect(history_page.items.first.encoding).to be_nil
|
|
263
|
+
expect(history_page.items.first.data).to eql(data)
|
|
227
264
|
end
|
|
228
265
|
end
|
|
229
266
|
end
|
|
@@ -242,10 +279,10 @@ describe Ably::Rest::Presence do
|
|
|
242
279
|
context '#get' do
|
|
243
280
|
let(:client_options) { default_options.merge(log_level: :fatal) }
|
|
244
281
|
let!(:get_stub) {
|
|
245
|
-
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence").
|
|
282
|
+
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence?limit=100").
|
|
246
283
|
to_return(:body => serialized_encoded_message_with_invalid_encoding, :headers => { 'Content-Type' => content_type })
|
|
247
284
|
}
|
|
248
|
-
let(:presence_message) { presence.get.first }
|
|
285
|
+
let(:presence_message) { presence.get.items.first }
|
|
249
286
|
|
|
250
287
|
after do
|
|
251
288
|
expect(get_stub).to have_been_requested
|
|
@@ -266,10 +303,10 @@ describe Ably::Rest::Presence do
|
|
|
266
303
|
context '#history' do
|
|
267
304
|
let(:client_options) { default_options.merge(log_level: :fatal) }
|
|
268
305
|
let!(:history_stub) {
|
|
269
|
-
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence/history").
|
|
306
|
+
stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence/history?direction=backwards&limit=100").
|
|
270
307
|
to_return(:body => serialized_encoded_message_with_invalid_encoding, :headers => { 'Content-Type' => content_type })
|
|
271
308
|
}
|
|
272
|
-
let(:presence_message) { presence.history.first }
|
|
309
|
+
let(:presence_message) { presence.history.items.first }
|
|
273
310
|
|
|
274
311
|
after do
|
|
275
312
|
expect(history_stub).to have_been_requested
|