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.
Files changed (76) hide show
  1. checksums.yaml +8 -8
  2. data/.travis.yml +2 -0
  3. data/README.md +41 -15
  4. data/SPEC.md +654 -518
  5. data/lib/submodules/ably-ruby/.gitignore +1 -0
  6. data/lib/submodules/ably-ruby/.gitmodules +3 -0
  7. data/lib/submodules/ably-ruby/README.md +54 -26
  8. data/lib/submodules/ably-ruby/SPEC.md +468 -322
  9. data/lib/submodules/ably-ruby/ably.gemspec +4 -2
  10. data/lib/submodules/ably-ruby/lib/ably/auth.rb +185 -131
  11. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +1 -1
  12. data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +31 -44
  13. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +2 -2
  14. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +1 -2
  15. data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +67 -24
  16. data/lib/submodules/ably-ruby/lib/ably/models/stats_types.rb +131 -0
  17. data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +101 -0
  18. data/lib/submodules/ably-ruby/lib/ably/models/token_request.rb +108 -0
  19. data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +3 -2
  20. data/lib/submodules/ably-ruby/lib/ably/modules/http_helpers.rb +1 -1
  21. data/lib/submodules/ably-ruby/lib/ably/modules/message_emitter.rb +2 -2
  22. data/lib/submodules/ably-ruby/lib/ably/realtime.rb +3 -7
  23. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +32 -5
  24. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +1 -0
  25. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +4 -8
  26. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +5 -3
  27. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +12 -1
  28. data/lib/submodules/ably-ruby/lib/ably/rest.rb +3 -7
  29. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +13 -10
  30. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +19 -20
  31. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +14 -12
  32. data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
  33. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +74 -23
  34. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +3 -3
  35. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +18 -18
  36. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +5 -5
  37. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +12 -12
  38. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +5 -5
  39. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +56 -13
  40. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +8 -8
  41. data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +1 -1
  42. data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +1 -1
  43. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +262 -158
  44. data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +11 -9
  45. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +28 -21
  46. data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +1 -1
  47. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +30 -27
  48. data/lib/submodules/ably-ruby/spec/acceptance/rest/encoders_spec.rb +1 -1
  49. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +10 -10
  50. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +93 -56
  51. data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +50 -45
  52. data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +1 -1
  53. data/lib/submodules/ably-ruby/spec/rspec_config.rb +3 -2
  54. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +36 -28
  55. data/lib/submodules/ably-ruby/spec/spec_helper.rb +3 -0
  56. data/lib/submodules/ably-ruby/spec/support/api_helper.rb +3 -3
  57. data/lib/submodules/ably-ruby/spec/support/markdown_spec_formatter.rb +1 -1
  58. data/lib/submodules/ably-ruby/spec/support/test_app.rb +20 -33
  59. data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +18 -1
  60. data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +81 -72
  61. data/lib/submodules/ably-ruby/spec/unit/models/stats_spec.rb +289 -0
  62. data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +111 -0
  63. data/lib/submodules/ably-ruby/spec/unit/models/token_request_spec.rb +110 -0
  64. data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +1 -1
  65. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +1 -1
  66. data/lib/submodules/ably-ruby/spec/unit/realtime/realtime_spec.rb +1 -1
  67. data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +1 -1
  68. data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +8 -8
  69. data/lib/submodules/ably-ruby/spec/unit/rest/rest_spec.rb +1 -1
  70. data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +1 -1
  71. metadata +9 -7
  72. data/lib/submodules/ably-ruby/lib/ably/models/token.rb +0 -74
  73. data/lib/submodules/ably-ruby/spec/resources/crypto-data-128.json +0 -56
  74. data/lib/submodules/ably-ruby/spec/resources/crypto-data-256.json +0 -56
  75. data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +0 -113
  76. 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(api_key: 'appid.keyuid:keysecret'))
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(api_key: api_key, environment: environment, protocol: protocol)
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(api_key: 'appid.keyuid:keysecret', environment: environment)
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) { { id: random_str } }
113
- let(:token_2) { { id: random_str } }
114
- let(:channel) { 'channelname' }
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/#{key_id}/requestToken").to_return do
120
+ stub_request(:post, "#{client.endpoint}/keys/#{key_name}/requestToken").to_return do
121
121
  @token_requests += 1
122
122
  {
123
- :body => { access_token: send("token_#{@token_requests}").merge(expires: Time.now.to_i + 3600) }.to_json,
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(token_id: 'token ID cannot be used to create a new token', environment: environment, protocol: protocol) }
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(api_key: api_key, environment: environment, protocol: protocol)
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 adn return true indicating success' do
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
- actual_history = channel.history
40
+ actual_history_items = channel.history.items
41
41
 
42
- expect(actual_history.size).to eql(3)
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 = actual_history.find { |message| message.name == message_name && message.data == message_data }
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.next_page
70
- page_3 = page_2.next_page
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 be_last_page
77
- expect(page_1).to be_first_page
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 be_last_page
82
- expect(page_2).to_not be_first_page
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 be_last_page
87
- expect(page_3).to_not be_first_page
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 = key_id
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
- stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/messages?#{option}=#{milliseconds}").
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(api_key: api_key, environment: environment, protocol: protocol)
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(key_id: key_id, key_secret: key_secret, client_id: client_id) }
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 an auth block' do
18
- let(:client) { Ably::Rest::Client.new(client_options) { token_request } }
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 block to get a new token' do
21
- expect { client.channel('channel_name').publish('event', 'message') }.to change { client.auth.current_token }
22
- expect(client.auth.current_token.client_id).to eql(client_id)
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.current_token }
36
- expect(client.auth.current_token.client_id).to eql(client_id)
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) do
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) { { key_id: key_id, key_secret: key_secret, ttl: Ably::Models::Token::TOKEN_EXPIRY_BUFFER } }
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.current_token }
57
- expect(client.auth.current_token.client_id).to eql(token_request_1['clientId'])
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.current_token }
62
- expect(client.auth.current_token.client_id).to eql(token_request_2['clientId'])
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) { { key_id: key_id, key_secret: key_secret, ttl: 3600 } }
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.current_token }
71
- expect(client.auth.current_token.client_id).to eql(token_request_1['clientId'])
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.current_token }
76
- expect(client.auth.current_token.client_id).to eql(token_request_1['clientId'])
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(api_key: api_key) }
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(api_key: api_key) }
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', api_key: api_key) }
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, api_key: api_key) }
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(api_key: api_key, rest_host: custom_host) }
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.key_id/requestToken' }
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) { { api_key: api_key, environment: environment } }
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) { { api_key: api_key, environment: environment, protocol: protocol } }
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('../../../resources', __FILE__)
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) { { api_key: api_key, environment: environment, protocol: protocol } }
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
- describe '#get' do
22
- before(:context) do
23
- # When this test is run as a part of a test suite, the presence data injected in the test app may have expired
24
- reload_test_app
25
- end
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
- let(:channel) { client.channel('persisted:presence_fixtures') }
28
- let(:presence) { channel.presence.get }
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(presence.size).to eql(4)
42
+ expect(presence_page.items.size).to eql(fixtures.count)
32
43
 
33
- fixtures.each do |fixture|
34
- presence_message = presence.find { |client| client.client_id == fixture[:client_id] }
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) { 2 }
42
- let(:presence) { channel.presence.get(limit: page_size) }
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(presence.size).to eql(2)
46
- next_page = presence.next_page
47
- expect(next_page.size).to eql(2)
48
- expect(next_page).to be_last_page
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
- before(:context) do
55
- # When this test is run as a part of a test suite, the presence data injected in the test app may have expired
56
- reload_test_app
57
- end
58
-
59
- let(:channel) { client.channel('persisted:presence_fixtures') }
60
- let(:presence_history) { channel.presence.history }
65
+ let(:history_page) { fixtures_channel.presence.history }
61
66
 
62
67
  it 'returns recent presence activity' do
63
- expect(presence_history.size).to eql(4)
68
+ expect(history_page.items.size).to eql(fixtures.count)
64
69
 
65
- fixtures.each do |fixture|
66
- presence_message = presence_history.find { |client| client.client_id == fixture['clientId'] }
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) { 2 }
77
+ let(:page_size) { 3 }
73
78
 
74
79
  context 'direction: :forwards' do
75
- let(:presence_history) { channel.presence.history(direction: :forwards) }
76
- let(:paged_history_forward) { channel.presence.history(limit: page_size, direction: :forwards) }
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(2)
85
+ expect(paged_history_forward.items.size).to eql(page_size)
81
86
 
82
- next_page = paged_history_forward.next_page
87
+ next_page = paged_history_forward.next
83
88
 
84
- expect(paged_history_forward.first.id).to eql(presence_history.first.id)
85
- expect(next_page.first.id).to eql(presence_history[page_size].id)
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(:presence_history) { channel.presence.history(direction: :backwards) }
91
- let(:paged_history_backward) { channel.presence.history(limit: page_size, direction: :backwards) }
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(2)
100
+ expect(paged_history_backward.items.size).to eql(page_size)
96
101
 
97
- next_page = paged_history_backward.next_page
102
+ next_page = paged_history_backward.next
98
103
 
99
- expect(paged_history_backward.first.id).to eql(presence_history.first.id)
100
- expect(next_page.first.id).to eql(presence_history[page_size].id)
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(api_key: "#{user}:#{secret}")
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
- stub_request(:get, "#{endpoint}/channels/#{CGI.escape(channel_name)}/presence/history?#{option}=#{milliseconds}").
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', :webmock do
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(api_key: "#{user}:#{secret}"))
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
- present = presence.get
208
- expect(present.first.encoding).to be_nil
209
- expect(present.first.data).to eql(data)
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
- history = presence.history
225
- expect(history.first.encoding).to be_nil
226
- expect(history.first.data).to eql(data)
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