ably 0.7.5 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +5 -13
  2. data/.gitignore +1 -0
  3. data/.gitmodules +3 -0
  4. data/README.md +46 -22
  5. data/SPEC.md +345 -240
  6. data/ably.gemspec +4 -2
  7. data/lib/ably/auth.rb +18 -14
  8. data/lib/ably/models/message.rb +1 -1
  9. data/lib/ably/models/paginated_resource.rb +31 -44
  10. data/lib/ably/models/presence_message.rb +1 -1
  11. data/lib/ably/models/stat.rb +67 -24
  12. data/lib/ably/models/stats_types.rb +131 -0
  13. data/lib/ably/modules/async_wrapper.rb +3 -2
  14. data/lib/ably/modules/message_emitter.rb +2 -2
  15. data/lib/ably/realtime.rb +1 -1
  16. data/lib/ably/realtime/channel.rb +24 -3
  17. data/lib/ably/realtime/channel/channel_manager.rb +1 -0
  18. data/lib/ably/realtime/client.rb +2 -2
  19. data/lib/ably/realtime/connection.rb +1 -1
  20. data/lib/ably/realtime/presence.rb +12 -1
  21. data/lib/ably/rest.rb +1 -1
  22. data/lib/ably/rest/channel.rb +4 -5
  23. data/lib/ably/rest/client.rb +5 -5
  24. data/lib/ably/rest/presence.rb +2 -2
  25. data/lib/ably/version.rb +1 -1
  26. data/spec/acceptance/realtime/channel_history_spec.rb +74 -23
  27. data/spec/acceptance/realtime/channel_spec.rb +3 -3
  28. data/spec/acceptance/realtime/client_spec.rb +3 -3
  29. data/spec/acceptance/realtime/connection_failures_spec.rb +2 -2
  30. data/spec/acceptance/realtime/connection_spec.rb +4 -4
  31. data/spec/acceptance/realtime/message_spec.rb +5 -5
  32. data/spec/acceptance/realtime/presence_history_spec.rb +56 -13
  33. data/spec/acceptance/realtime/presence_spec.rb +8 -8
  34. data/spec/acceptance/realtime/stats_spec.rb +1 -1
  35. data/spec/acceptance/realtime/time_spec.rb +1 -1
  36. data/spec/acceptance/rest/auth_spec.rb +31 -4
  37. data/spec/acceptance/rest/base_spec.rb +3 -3
  38. data/spec/acceptance/rest/channel_spec.rb +19 -19
  39. data/spec/acceptance/rest/channels_spec.rb +1 -1
  40. data/spec/acceptance/rest/client_spec.rb +9 -6
  41. data/spec/acceptance/rest/encoders_spec.rb +1 -1
  42. data/spec/acceptance/rest/message_spec.rb +10 -10
  43. data/spec/acceptance/rest/presence_spec.rb +81 -51
  44. data/spec/acceptance/rest/stats_spec.rb +46 -41
  45. data/spec/acceptance/rest/time_spec.rb +1 -1
  46. data/spec/shared/client_initializer_behaviour.rb +30 -19
  47. data/spec/spec_helper.rb +3 -0
  48. data/spec/support/markdown_spec_formatter.rb +1 -1
  49. data/spec/support/test_app.rb +11 -24
  50. data/spec/unit/auth_spec.rb +1 -1
  51. data/spec/unit/models/paginated_resource_spec.rb +81 -72
  52. data/spec/unit/models/stats_spec.rb +289 -0
  53. data/spec/unit/modules/async_wrapper_spec.rb +1 -1
  54. data/spec/unit/realtime/client_spec.rb +1 -1
  55. data/spec/unit/realtime/realtime_spec.rb +1 -1
  56. data/spec/unit/rest/channel_spec.rb +1 -1
  57. data/spec/unit/rest/client_spec.rb +8 -8
  58. data/spec/unit/rest/rest_spec.rb +1 -1
  59. data/spec/unit/util/crypto_spec.rb +1 -1
  60. metadata +55 -43
  61. data/spec/resources/crypto-data-128.json +0 -56
  62. data/spec/resources/crypto-data-256.json +0 -56
  63. data/spec/unit/models/stat_spec.rb +0 -113
@@ -47,8 +47,9 @@ module Ably::Modules
47
47
  operation_with_exception_handling = proc do
48
48
  begin
49
49
  yield
50
- rescue StandardError => e
51
- deferrable.fail e
50
+ rescue StandardError => err
51
+ logger.error "An exception in an AsyncWrapper block was caught. #{err.class}: #{err.message}\n#{err.backtrace.join("\n")}"
52
+ deferrable.fail err
52
53
  end
53
54
  end
54
55
 
@@ -6,7 +6,7 @@ module Ably::Modules
6
6
  module MessageEmitter
7
7
  # Subscribe to events on this object
8
8
  #
9
- # @param name [String,Symbol] Optional, the event name to subscribe to. Defaults to `:all` events
9
+ # @param names [String,Symbol] Optional, the event name(s) to subscribe to. Defaults to `:all` events
10
10
  # @yield [Object] For each event, the provided block is called with the event payload object
11
11
  #
12
12
  # @return [void]
@@ -22,7 +22,7 @@ module Ably::Modules
22
22
  # Unsubscribe the matching block for events on the this object.
23
23
  # If a block is not provided, all subscriptions will be unsubscribed
24
24
  #
25
- # @param name [String,Symbol] Optional, the event name to unsubscribe from. Defaults to `:all` events
25
+ # @param names [String,Symbol] Optional, the event name(s) to unsubscribe from. Defaults to `:all` events
26
26
  #
27
27
  # @return [void]
28
28
  #
@@ -50,7 +50,7 @@ module Ably
50
50
  # client = Ably::Realtime.new('key.id:secret')
51
51
  #
52
52
  # # create a new client authenticating with basic auth and a client_id
53
- # client = Ably::Realtime.new(api_key: 'key.id:secret', client_id: 'john')
53
+ # client = Ably::Realtime.new(key: 'key.id:secret', client_id: 'john')
54
54
  #
55
55
  def self.new(options, &token_request_block)
56
56
  Ably::Realtime::Client.new(options, &token_request_block)
@@ -23,7 +23,7 @@ module Ably
23
23
  # Channel::STATE.Detached
24
24
  # Channel::STATE.Failed
25
25
  #
26
- # Channels emit errors - use `on(:error)` to subscribe to errors
26
+ # Channels emit errors - use +on(:error)+ to subscribe to errors
27
27
  #
28
28
  # @!attribute [r] state
29
29
  # @return {Ably::Realtime::Connection::STATE} channel state
@@ -71,13 +71,18 @@ module Ably
71
71
  # @api private
72
72
  attr_reader :manager
73
73
 
74
+ # Serial number assigned to this channel when it was attached
75
+ # @return [Integer]
76
+ # @api private
77
+ attr_reader :attached_serial
78
+
74
79
  # Initialize a new Channel object
75
80
  #
76
81
  # @param client [Ably::Rest::Client]
77
82
  # @param name [String] The name of the channel
78
83
  # @param channel_options [Hash] Channel options, currently reserved for Encryption options
79
84
  # @option channel_options [Boolean] :encrypted setting this to true for this channel will encrypt & decrypt all messages automatically
80
- # @option channel_options [Hash] :cipher_params A hash of options to configure the encryption. *:key* is required, all other options are optional. See {Ably::Util::Crypto#initialize} for a list of `cipher_params` options
85
+ # @option channel_options [Hash] :cipher_params A hash of options to configure the encryption. *:key* is required, all other options are optional. See {Ably::Util::Crypto#initialize} for a list of +cipher_params+ options
81
86
  #
82
87
  def initialize(client, name, channel_options = {})
83
88
  ensure_utf_8 :name, name
@@ -181,13 +186,24 @@ module Ably
181
186
 
182
187
  # Return the message history of the channel
183
188
  #
189
+ # Once attached to a channel, you can retrieve messages published on the channel before the
190
+ # channel was attached with the option <tt>until_attach: true</tt>. This is very useful for
191
+ # developers who wish to subscribe to new realtime messages yet also display historical messages with
192
+ # the guarantee that no messages have been missed.
193
+ #
184
194
  # @param (see Ably::Rest::Channel#history)
185
195
  # @option options (see Ably::Rest::Channel#history)
196
+ # @option options [Boolean] :until_attach When true, request for history will be limited only to messages published before this channel was attached. Channel must be attached.
186
197
  #
187
- # @yield [Ably::Models::PaginatedResource<Ably::Models::Message>] An Array of {Ably::Models::Message} objects that supports paging (#next_page, #first_page)
198
+ # @yield [Ably::Models::PaginatedResource<Ably::Models::Message>] First {Ably::Models::PaginatedResource page} of {Ably::Models::Message} objects accessible with {Ably::Models::PaginatedResource#items #items}.
188
199
  #
189
200
  # @return [Ably::Util::SafeDeferrable]
190
201
  def history(options = {}, &callback)
202
+ if options.delete(:until_attach)
203
+ raise ArgumentError, 'option :until_attach cannot be specified if the channel is not attached' unless attached?
204
+ options[:from_serial] = attached_serial
205
+ end
206
+
191
207
  async_wrap(callback) do
192
208
  rest_channel.history(options.merge(async_blocking_operations: true))
193
209
  end
@@ -212,6 +228,11 @@ module Ably
212
228
  @error_reason = nil
213
229
  end
214
230
 
231
+ # @api private
232
+ def set_attached_serial(serial)
233
+ @attached_serial = serial
234
+ end
235
+
215
236
  # Used by {Ably::Modules::StateEmitter} to debug state changes
216
237
  # @api private
217
238
  def logger
@@ -40,6 +40,7 @@ module Ably::Realtime
40
40
  else
41
41
  channel.presence.manager.sync_not_expected
42
42
  end
43
+ channel.set_attached_serial attached_protocol_message.channel_serial
43
44
  end
44
45
 
45
46
  # An error has occurred on the channel
@@ -75,7 +75,7 @@ module Ably
75
75
  # client = Ably::Realtime::Client.new('key.id:secret')
76
76
  #
77
77
  # # create a new client and configure a client ID used for presence
78
- # client = Ably::Realtime::Client.new(api_key: 'key.id:secret', client_id: 'john')
78
+ # client = Ably::Realtime::Client.new(key: 'key.id:secret', client_id: 'john')
79
79
  #
80
80
  def initialize(options, &token_request_block)
81
81
  @rest_client = Ably::Rest::Client.new(options, &token_request_block)
@@ -114,7 +114,7 @@ module Ably
114
114
  # @param (see Ably::Rest::Client#stats)
115
115
  # @option options (see Ably::Rest::Client#stats)
116
116
  #
117
- # @yield [Ably::Models::PaginatedResource<Ably::Models::Stat>] An Array of Stats
117
+ # @yield [Ably::Models::PaginatedResource<Ably::Models::Stats>] An Array of Stats
118
118
  #
119
119
  # @return [Ably::Util::SafeDeferrable]
120
120
  #
@@ -150,7 +150,7 @@ module Ably
150
150
  # @yield [Integer] if a block is passed to this method, then this block will be called once the ping heartbeat is received with the time elapsed in milliseconds
151
151
  #
152
152
  # @example
153
- # client = Ably::Rest::Client.new(api_key: 'key.id:secret')
153
+ # client = Ably::Rest::Client.new(key: 'key.id:secret')
154
154
  # client.connection.ping do |ms_elapsed|
155
155
  # puts "Ping took #{ms_elapsed}ms"
156
156
  # end
@@ -265,14 +265,25 @@ module Ably::Realtime
265
265
 
266
266
  # Return the presence messages history for the channel
267
267
  #
268
+ # Once attached to a channel, you can retrieve presence message history on the channel before the
269
+ # channel was attached with the option <tt>until_attach: true</tt>. This is very useful for
270
+ # developers who wish to capture new presence events as well as retrieve historical presence state with
271
+ # the guarantee that no presence history has been missed.
272
+ #
268
273
  # @param (see Ably::Rest::Presence#history)
269
274
  # @option options (see Ably::Rest::Presence#history)
275
+ # @option options [Boolean] :until_attach When true, request for history will be limited only to messages published before the associated channel was attached. The associated channel must be attached.
270
276
  #
271
- # @yield [Ably::Models::PaginatedResource<Ably::Models::PresenceMessage>] An Array of {Ably::Models::PresenceMessage} objects that supports paging (#next_page, #first_page)
277
+ # @yield [Ably::Models::PaginatedResource<Ably::Models::PresenceMessage>] First {Ably::Models::PaginatedResource page} of {Ably::Models::PresenceMessage} objects accessible with {Ably::Models::PaginatedResource#items #items}.
272
278
  #
273
279
  # @return [Ably::Util::SafeDeferrable]
274
280
  #
275
281
  def history(options = {}, &callback)
282
+ if options.delete(:until_attach)
283
+ raise ArgumentError, 'option :until_attach cannot be specified if the channel is not attached' unless channel.attached?
284
+ options[:from_serial] = channel.attached_serial
285
+ end
286
+
276
287
  async_wrap(callback) do
277
288
  rest_presence.history(options.merge(async_blocking_operations: true))
278
289
  end
@@ -34,7 +34,7 @@ module Ably
34
34
  # client = Ably::Rest.new('key.id:secret')
35
35
  #
36
36
  # # create a new client authenticating with basic auth and a client_id
37
- # client = Ably::Rest.new(api_key: 'key.id:secret', client_id: 'john')
37
+ # client = Ably::Rest.new(key: 'key.id:secret', client_id: 'john')
38
38
  #
39
39
  def self.new(options, &token_request_block)
40
40
  Ably::Rest::Client.new(options, &token_request_block)
@@ -20,7 +20,7 @@ module Ably
20
20
  # @param name [String] The name of the channel
21
21
  # @param channel_options [Hash] Channel options, currently reserved for Encryption options
22
22
  # @option channel_options [Boolean] :encrypted setting this to true for this channel will encrypt & decrypt all messages automatically
23
- # @option channel_options [Hash] :cipher_params A hash of options to configure the encryption. *:key* is required, all other options are optional. See {Ably::Util::Crypto#initialize} for a list of `cipher_params` options
23
+ # @option channel_options [Hash] :cipher_params A hash of options to configure the encryption. *:key* is required, all other options are optional. See {Ably::Util::Crypto#initialize} for a list of +cipher_params+ options
24
24
  #
25
25
  def initialize(client, name, channel_options = {})
26
26
  ensure_utf_8 :name, name
@@ -52,16 +52,15 @@ module Ably
52
52
  [201, 204].include?(response.status)
53
53
  end
54
54
 
55
- # Return the message history of the channel
55
+ # Return the message of the channel
56
56
  #
57
57
  # @param [Hash] options the options for the message history request
58
58
  # @option options [Integer,Time] :start Time or millisecond since epoch
59
59
  # @option options [Integer,Time] :end Time or millisecond since epoch
60
- # @option options [Symbol] :direction `:forwards` or `:backwards`
60
+ # @option options [Symbol] :direction +:forwards+ or +:backwards+
61
61
  # @option options [Integer] :limit Maximum number of messages to retrieve up to 10,000
62
- # @option options [Symbol] :by `:message`, `:bundle` or `:hour`. Defaults to `:message`
63
62
  #
64
- # @return [Ably::Models::PaginatedResource<Ably::Models::Message>] An Array of {Ably::Models::Message} objects that supports paging (#next_page, #first_page)
63
+ # @return [Ably::Models::PaginatedResource<Ably::Models::Message>] First {Ably::Models::PaginatedResource page} of {Ably::Models::Message} objects accessible with {Ably::Models::PaginatedResource#items #items}.
65
64
  def history(options = {})
66
65
  url = "#{base_path}/messages"
67
66
  options = options.dup
@@ -70,7 +70,7 @@ module Ably
70
70
  # @param [Hash,String] options an options Hash used to configure the client and the authentication, or String with an API key or Token ID
71
71
  # @option options (see Ably::Auth#authorise)
72
72
  # @option options [Boolean] :tls TLS is used by default, providing a value of false disables TLS. Please note Basic Auth is disallowed without TLS as secrets cannot be transmitted over unsecured connections.
73
- # @option options [String] :api_key API key comprising the key ID and key secret in a single string
73
+ # @option options [String] :key API key comprising the key ID and key secret in a single string
74
74
  # @option options [Boolean] :use_token_auth Will force Basic Auth if set to false, and TOken auth if set to true
75
75
  # @option options [String] :environment Specify 'sandbox' when testing the client library against an alternate Ably environment
76
76
  # @option options [Symbol] :protocol Protocol used to communicate with Ably, :json and :msgpack currently supported. Defaults to :msgpack
@@ -89,7 +89,7 @@ module Ably
89
89
  # client = Ably::Rest::Client.new('key.id:secret')
90
90
  #
91
91
  # # create a new client and configure a client ID used for presence
92
- # client = Ably::Rest::Client.new(api_key: 'key.id:secret', client_id: 'john')
92
+ # client = Ably::Rest::Client.new(key: 'key.id:secret', client_id: 'john')
93
93
  #
94
94
  def initialize(options, &token_request_block)
95
95
  raise ArgumentError, 'Options Hash is expected' if options.nil?
@@ -97,7 +97,7 @@ module Ably
97
97
  options = options.clone
98
98
  if options.kind_of?(String)
99
99
  options = if options.match(/^[\w]{2,}\.[\w]{2,}:[\w]{2,}$/)
100
- { api_key: options }
100
+ { key: options }
101
101
  else
102
102
  { token_id: options }
103
103
  end
@@ -152,7 +152,7 @@ module Ably
152
152
  # @option options [Integer] :limit Maximum number of stats to retrieve up to 10,000
153
153
  # @option options [Symbol] :by `:minute`, `:hour`, `:day` or `:month`. Defaults to `:minute`
154
154
  #
155
- # @return [Ably::Models::PaginatedResource<Ably::Models::Stat>] An Array of Stats
155
+ # @return [Ably::Models::PaginatedResource<Ably::Models::Stats>] An Array of Stats
156
156
  #
157
157
  def stats(options = {})
158
158
  options = {
@@ -163,7 +163,7 @@ module Ably
163
163
  [:start, :end].each { |option| options[option] = as_since_epoch(options[option]) if options.has_key?(option) }
164
164
 
165
165
  paginated_options = {
166
- coerce_into: 'Ably::Models::Stat'
166
+ coerce_into: 'Ably::Models::Stats'
167
167
  }
168
168
 
169
169
  url = '/stats'
@@ -28,7 +28,7 @@ module Ably
28
28
  # @option options [Symbol] :direction `:forwards` or `:backwards`
29
29
  # @option options [Integer] :limit Maximum number of members to retrieve up to 10,000
30
30
  #
31
- # @return [Ably::Models::PaginatedResource<Ably::Models::PresenceMessage>] An Array of {Ably::Models::PresenceMessage} objects that supports paging (#next_page, #first_page)
31
+ # @return [Ably::Models::PaginatedResource<Ably::Models::PresenceMessage>] First {Ably::Models::PaginatedResource page} of {Ably::Models::PresenceMessage} objects accessible with {Ably::Models::PaginatedResource#items #items}.
32
32
  #
33
33
  def get(options = {})
34
34
  options = options.dup
@@ -55,7 +55,7 @@ module Ably
55
55
  # @option options [Symbol] :direction `:forwards` or `:backwards`
56
56
  # @option options [Integer] :limit Maximum number of presence messages to retrieve up to 10,000
57
57
  #
58
- # @return [Ably::Models::PaginatedResource<Ably::Models::PresenceMessage>] An Array of {Ably::Models::PresenceMessage} objects that supports paging (#next_page, #first_page)
58
+ # @return [Ably::Models::PaginatedResource<Ably::Models::PresenceMessage>] First {Ably::Models::PaginatedResource page} of {Ably::Models::PresenceMessage} objects accessible with {Ably::Models::PaginatedResource#items #items}.
59
59
  #
60
60
  def history(options = {})
61
61
  url = "#{base_path}/history"
@@ -1,3 +1,3 @@
1
1
  module Ably
2
- VERSION = '0.7.5'
2
+ VERSION = '0.7.6'
3
3
  end
@@ -3,10 +3,11 @@ require 'spec_helper'
3
3
 
4
4
  describe Ably::Realtime::Channel, '#history', :event_machine do
5
5
  vary_by_protocol do
6
- let(:default_options) { options.merge(api_key: api_key, environment: environment, protocol: protocol) }
6
+ let(:default_options) { options.merge(key: api_key, environment: environment, protocol: protocol) }
7
7
 
8
8
  let(:client) { Ably::Realtime::Client.new(default_options) }
9
9
  let(:channel) { client.channel(channel_name) }
10
+ let(:rest_channel) { client.rest_client.channel(channel_name) }
10
11
 
11
12
  let(:client2) { Ably::Realtime::Client.new(default_options) }
12
13
  let(:channel2) { client2.channel(channel_name) }
@@ -21,20 +22,20 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
21
22
  channel.publish('event', payload) do |message|
22
23
  history = channel.history
23
24
  expect(history).to be_a(Ably::Util::SafeDeferrable)
24
- history.callback do |messages|
25
- expect(messages.count).to eql(1)
26
- expect(messages).to be_a(Ably::Models::PaginatedResource)
25
+ history.callback do |page|
26
+ expect(page.items.count).to eql(1)
27
+ expect(page).to be_a(Ably::Models::PaginatedResource)
27
28
  stop_reactor
28
29
  end
29
30
  end
30
31
  end
31
32
 
32
33
  context 'with a single client publishing and receiving' do
33
- it 'retrieves real-time history' do
34
+ it 'retrieves realtime history' do
34
35
  channel.publish('event', payload) do |message|
35
- channel.history do |history|
36
- expect(history.length).to eql(1)
37
- expect(history[0].data).to eql(payload)
36
+ channel.history do |page|
37
+ expect(page.items.length).to eql(1)
38
+ expect(page.items[0].data).to eql(payload)
38
39
  stop_reactor
39
40
  end
40
41
  end
@@ -42,15 +43,15 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
42
43
  end
43
44
 
44
45
  context 'with two clients publishing messages on the same channel' do
45
- it 'retrieves real-time history on both channels' do
46
+ it 'retrieves realtime history on both channels' do
46
47
  channel.publish('event', payload) do |message|
47
48
  channel2.publish('event', payload) do |message|
48
- channel.history do |history|
49
- expect(history.length).to eql(2)
50
- expect(history.map(&:data).uniq).to eql([payload])
49
+ channel.history do |page|
50
+ expect(page.items.length).to eql(2)
51
+ expect(page.items.map(&:data).uniq).to eql([payload])
51
52
 
52
- channel2.history do |history_2|
53
- expect(history_2.length).to eql(2)
53
+ channel2.history do |page_2|
54
+ expect(page_2.items.length).to eql(2)
54
55
  stop_reactor
55
56
  end
56
57
  end
@@ -65,18 +66,18 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
65
66
  let(:limit) { 15 }
66
67
 
67
68
  def ensure_message_history_direction_and_paging_is_correct(direction)
68
- channel.history(direction: direction, limit: limit) do |history|
69
- expect(history.length).to eql(limit)
69
+ channel.history(direction: direction, limit: limit) do |history_page|
70
+ expect(history_page.items.length).to eql(limit)
70
71
  limit.times do |index|
71
- expect(history[index].data).to eql("history#{index}")
72
+ expect(history_page.items[index].data).to eql("history#{index}")
72
73
  end
73
74
 
74
- history.next_page do |history|
75
- expect(history.length).to eql(limit)
75
+ history_page.next do |next_page|
76
+ expect(next_page.items.length).to eql(limit)
76
77
  limit.times do |index|
77
- expect(history[index].data).to eql("history#{index + limit}")
78
+ expect(next_page.items[index].data).to eql("history#{index + limit}")
78
79
  end
79
- expect(history.last_page?).to eql(true)
80
+ expect(next_page).to be_last
80
81
 
81
82
  stop_reactor
82
83
  end
@@ -141,8 +142,8 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
141
142
  channel.subscribe('event') do |message|
142
143
  messages << message
143
144
  if messages.count == batches * messages_per_batch
144
- channel.history do |history|
145
- expect(history.map(&:id).sort).to eql(messages.map(&:id).sort)
145
+ channel.history do |page|
146
+ expect(page.items.map(&:id).sort).to eql(messages.map(&:id).sort)
146
147
  stop_reactor
147
148
  end
148
149
  end
@@ -150,5 +151,55 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
150
151
  end
151
152
  end
152
153
  end
154
+
155
+ context 'with option until_attach: true' do
156
+ let(:event) { random_str }
157
+ let(:message_before_attach) { random_str }
158
+ let(:message_after_attach) { random_str }
159
+
160
+ it 'retrieves all messages before channel was attached' do
161
+ rest_channel.publish event, message_before_attach
162
+
163
+ channel.attach do
164
+ channel.publish(event, message_after_attach) do
165
+ channel.history(until_attach: true) do |messages|
166
+ expect(messages.items.count).to eql(1)
167
+ expect(messages.items.first.data).to eql(message_before_attach)
168
+ stop_reactor
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ context 'and two pages of messages' do
175
+ it 'retrieves two pages of messages before channel was attached' do
176
+ 10.times { rest_channel.publish event, message_before_attach }
177
+
178
+ channel.attach do
179
+ 10.times { rest_channel.publish event, message_after_attach }
180
+
181
+ EventMachine.add_timer(0.5) do
182
+ channel.history(until_attach: true, limit: 5) do |messages|
183
+ expect(messages.items.count).to eql(5)
184
+ expect(messages.items.map(&:data).uniq.first).to eql(message_before_attach)
185
+
186
+ messages.next do |next_page_messages|
187
+ expect(next_page_messages.items.count).to eql(5)
188
+ expect(next_page_messages.items.map(&:data).uniq.first).to eql(message_before_attach)
189
+ expect(next_page_messages).to be_last
190
+
191
+ stop_reactor
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
198
+
199
+ it 'raises an exception unless state is attached' do
200
+ expect { channel.history(until_attach: true) }.to raise_error(ArgumentError, /not attached/)
201
+ stop_reactor
202
+ end
203
+ end
153
204
  end
154
205
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
 
4
4
  describe Ably::Realtime::Channel, :event_machine do
5
5
  vary_by_protocol do
6
- let(:default_options) { { api_key: api_key, environment: environment, protocol: protocol } }
6
+ let(:default_options) { { key: api_key, environment: environment, protocol: protocol } }
7
7
  let(:client_options) { default_options }
8
8
 
9
9
  let(:client) { Ably::Realtime::Client.new(client_options) }
@@ -158,7 +158,7 @@ describe Ably::Realtime::Channel, :event_machine do
158
158
 
159
159
  context 'failure as a result of insufficient key permissions' do
160
160
  let(:restricted_client) do
161
- Ably::Realtime::Client.new(default_options.merge(api_key: restricted_api_key, log_level: :fatal))
161
+ Ably::Realtime::Client.new(default_options.merge(key: restricted_api_key, log_level: :fatal))
162
162
  end
163
163
  let(:restricted_channel) { restricted_client.channel("cannot_subscribe") }
164
164
 
@@ -202,7 +202,7 @@ describe Ably::Realtime::Channel, :event_machine do
202
202
  restricted_channel.once(:failed) do
203
203
  restricted_client.close do
204
204
  # A direct call to #authorise is synchronous
205
- restricted_client.auth.authorise(api_key: api_key)
205
+ restricted_client.auth.authorise(key: api_key)
206
206
 
207
207
  restricted_client.connect do
208
208
  restricted_channel.once(:attached) do