ably 1.0.7 → 1.1.4.rc

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +14 -0
  3. data/.travis.yml +10 -8
  4. data/CHANGELOG.md +58 -4
  5. data/LICENSE +1 -3
  6. data/README.md +9 -5
  7. data/Rakefile +32 -0
  8. data/SPEC.md +920 -565
  9. data/ably.gemspec +16 -11
  10. data/lib/ably/auth.rb +28 -2
  11. data/lib/ably/exceptions.rb +10 -4
  12. data/lib/ably/logger.rb +7 -1
  13. data/lib/ably/models/channel_state_change.rb +1 -1
  14. data/lib/ably/models/connection_state_change.rb +1 -1
  15. data/lib/ably/models/device_details.rb +87 -0
  16. data/lib/ably/models/device_push_details.rb +86 -0
  17. data/lib/ably/models/error_info.rb +23 -2
  18. data/lib/ably/models/idiomatic_ruby_wrapper.rb +4 -4
  19. data/lib/ably/models/protocol_message.rb +32 -2
  20. data/lib/ably/models/push_channel_subscription.rb +89 -0
  21. data/lib/ably/modules/conversions.rb +1 -1
  22. data/lib/ably/modules/encodeable.rb +1 -1
  23. data/lib/ably/modules/exception_codes.rb +128 -0
  24. data/lib/ably/modules/model_common.rb +15 -2
  25. data/lib/ably/modules/state_machine.rb +2 -2
  26. data/lib/ably/realtime.rb +1 -0
  27. data/lib/ably/realtime/auth.rb +1 -1
  28. data/lib/ably/realtime/channel.rb +24 -102
  29. data/lib/ably/realtime/channel/channel_manager.rb +2 -6
  30. data/lib/ably/realtime/channel/channel_state_machine.rb +2 -2
  31. data/lib/ably/realtime/channel/publisher.rb +74 -0
  32. data/lib/ably/realtime/channel/push_channel.rb +62 -0
  33. data/lib/ably/realtime/client.rb +91 -3
  34. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +6 -2
  35. data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
  36. data/lib/ably/realtime/connection.rb +34 -20
  37. data/lib/ably/realtime/connection/connection_manager.rb +25 -9
  38. data/lib/ably/realtime/connection/websocket_transport.rb +1 -1
  39. data/lib/ably/realtime/presence.rb +4 -4
  40. data/lib/ably/realtime/presence/members_map.rb +3 -3
  41. data/lib/ably/realtime/push.rb +40 -0
  42. data/lib/ably/realtime/push/admin.rb +61 -0
  43. data/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
  44. data/lib/ably/realtime/push/device_registrations.rb +105 -0
  45. data/lib/ably/rest.rb +1 -0
  46. data/lib/ably/rest/channel.rb +53 -17
  47. data/lib/ably/rest/channel/push_channel.rb +62 -0
  48. data/lib/ably/rest/client.rb +161 -35
  49. data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +4 -1
  50. data/lib/ably/rest/middleware/parse_message_pack.rb +17 -1
  51. data/lib/ably/rest/presence.rb +1 -0
  52. data/lib/ably/rest/push.rb +42 -0
  53. data/lib/ably/rest/push/admin.rb +54 -0
  54. data/lib/ably/rest/push/channel_subscriptions.rb +121 -0
  55. data/lib/ably/rest/push/device_registrations.rb +103 -0
  56. data/lib/ably/version.rb +7 -2
  57. data/spec/acceptance/realtime/auth_spec.rb +22 -21
  58. data/spec/acceptance/realtime/channel_history_spec.rb +26 -20
  59. data/spec/acceptance/realtime/channel_spec.rb +177 -59
  60. data/spec/acceptance/realtime/client_spec.rb +153 -0
  61. data/spec/acceptance/realtime/connection_failures_spec.rb +72 -6
  62. data/spec/acceptance/realtime/connection_spec.rb +129 -18
  63. data/spec/acceptance/realtime/message_spec.rb +36 -34
  64. data/spec/acceptance/realtime/presence_spec.rb +201 -167
  65. data/spec/acceptance/realtime/push_admin_spec.rb +736 -0
  66. data/spec/acceptance/realtime/push_spec.rb +27 -0
  67. data/spec/acceptance/rest/auth_spec.rb +4 -3
  68. data/spec/acceptance/rest/base_spec.rb +2 -2
  69. data/spec/acceptance/rest/channel_spec.rb +79 -4
  70. data/spec/acceptance/rest/channels_spec.rb +6 -0
  71. data/spec/acceptance/rest/client_spec.rb +129 -10
  72. data/spec/acceptance/rest/message_spec.rb +158 -6
  73. data/spec/acceptance/rest/push_admin_spec.rb +952 -0
  74. data/spec/acceptance/rest/push_spec.rb +25 -0
  75. data/spec/acceptance/rest/time_spec.rb +1 -1
  76. data/spec/run_parallel_tests +33 -0
  77. data/spec/spec_helper.rb +1 -1
  78. data/spec/support/debug_failure_helper.rb +9 -5
  79. data/spec/support/test_app.rb +2 -2
  80. data/spec/unit/logger_spec.rb +10 -3
  81. data/spec/unit/models/device_details_spec.rb +102 -0
  82. data/spec/unit/models/device_push_details_spec.rb +101 -0
  83. data/spec/unit/models/error_info_spec.rb +51 -3
  84. data/spec/unit/models/message_spec.rb +17 -2
  85. data/spec/unit/models/presence_message_spec.rb +1 -1
  86. data/spec/unit/models/push_channel_subscription_spec.rb +86 -0
  87. data/spec/unit/modules/enum_spec.rb +1 -1
  88. data/spec/unit/realtime/client_spec.rb +13 -1
  89. data/spec/unit/realtime/connection_spec.rb +1 -1
  90. data/spec/unit/realtime/push_channel_spec.rb +36 -0
  91. data/spec/unit/rest/channel_spec.rb +8 -1
  92. data/spec/unit/rest/client_spec.rb +30 -0
  93. data/spec/unit/rest/push_channel_spec.rb +36 -0
  94. metadata +94 -31
@@ -7,7 +7,10 @@ module Ably
7
7
  class FailIfUnsupportedMimeType < Faraday::Response::Middleware
8
8
  def on_complete(env)
9
9
  unless env.response_headers['Ably-Middleware-Parsed'] == true
10
- unless (500..599).include?(env.status)
10
+ # Ignore empty body with success status code for no body response
11
+ return if env.body.to_s.empty? && env.status == 204
12
+
13
+ unless (500..599).include?(env.status)
11
14
  raise Ably::Exceptions::InvalidResponseBody,
12
15
  "Content Type #{env.response_headers['Content-Type']} is not supported by this client library"
13
16
  end
@@ -10,6 +10,14 @@ module Ably
10
10
  env.body = parse(env.body) unless env.response_headers['Ably-Middleware-Parsed'] == true
11
11
  env.response_headers['Ably-Middleware-Parsed'] = true
12
12
  end
13
+ rescue Ably::Exceptions::InvalidResponseBody => e
14
+ debug_info = {
15
+ method: env.method,
16
+ url: env.url,
17
+ base64_body: base64_body(env.body),
18
+ response_headers: env.response_headers
19
+ }
20
+ raise Ably::Exceptions::InvalidResponseBody, "#{e.message}\nRequest env: #{debug_info}"
13
21
  end
14
22
 
15
23
  def parse(body)
@@ -18,8 +26,16 @@ module Ably
18
26
  else
19
27
  body
20
28
  end
29
+ rescue MessagePack::UnknownExtTypeError => e
30
+ raise Ably::Exceptions::InvalidResponseBody, "MessagePack::UnknownExtTypeError body could not be decoded: #{e.message}. Got Base64:\n#{base64_body(body)}"
21
31
  rescue MessagePack::MalformedFormatError => e
22
- raise Ably::Exceptions::InvalidResponseBody, "Expected MessagePack response: #{e.message}"
32
+ raise Ably::Exceptions::InvalidResponseBody, "MessagePack::MalformedFormatError body could not be decoded: #{e.message}. Got Base64:\n#{base64_body(body)}"
33
+ end
34
+
35
+ def base64_body(body)
36
+ Base64.encode64(body)
37
+ rescue => err
38
+ "[#{err.message}! Could not base64 encode body: '#{body}']"
23
39
  end
24
40
  end
25
41
  end
@@ -5,6 +5,7 @@ module Ably
5
5
 
6
6
  # {Ably::Rest::Client} for this Presence object
7
7
  # @return {Ably::Rest::Client}
8
+ # @private
8
9
  attr_reader :client
9
10
 
10
11
  # {Ably::Rest::Channel} this Presence object is associated with
@@ -0,0 +1,42 @@
1
+ require 'ably/rest/push/admin'
2
+
3
+ module Ably
4
+ module Rest
5
+ # Class providing push notification functionality
6
+ class Push
7
+ include Ably::Modules::Conversions
8
+
9
+ # @private
10
+ attr_reader :client
11
+
12
+ def initialize(client)
13
+ @client = client
14
+ end
15
+
16
+ # Admin features for push notifications like managing devices and channel subscriptions
17
+ # @return [Ably::Rest::Push::Admin]
18
+ def admin
19
+ @admin ||= Admin.new(self)
20
+ end
21
+
22
+ # Activate this device for push notifications by registering with the push transport such as GCM/APNS
23
+ #
24
+ # @note This is unsupported in the Ruby library
25
+ def activate(*arg)
26
+ raise_unsupported
27
+ end
28
+
29
+ # Deactivate this device for push notifications by removing the registration with the push transport such as GCM/APNS
30
+ #
31
+ # @note This is unsupported in the Ruby library
32
+ def deactivate(*arg)
33
+ raise_unsupported
34
+ end
35
+
36
+ private
37
+ def raise_unsupported
38
+ raise Ably::Exceptions::PushNotificationsNotSupported, 'This device does not support receiving or subscribing to push notifications. All PushChannel methods are unavailable'
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,54 @@
1
+ require 'ably/rest/push/device_registrations'
2
+ require 'ably/rest/push/channel_subscriptions'
3
+
4
+ module Ably::Rest
5
+ class Push
6
+ # Class providing push notification administrative functionality
7
+ # for registering devices and attaching to channels etc.
8
+ class Admin
9
+ include Ably::Modules::Conversions
10
+
11
+ # @api private
12
+ attr_reader :client
13
+
14
+ # @api private
15
+ attr_reader :push
16
+
17
+ def initialize(push)
18
+ @push = push
19
+ @client = push.client
20
+ end
21
+
22
+ # Publish a push message directly to a single recipient
23
+ #
24
+ # @param recipient [Hash] A recipient device, client_id or raw APNS/GCM target. Refer to push documentation
25
+ # @param data [Hash] The notification payload data and fields. Refer to push documentation
26
+ #
27
+ # @return [void]
28
+ #
29
+ def publish(recipient, data)
30
+ raise ArgumentError, "Expecting a Hash object for recipient, got #{recipient.class}" unless recipient.kind_of?(Hash)
31
+ raise ArgumentError, "Recipient data is empty. You must provide recipient details" if recipient.empty?
32
+ raise ArgumentError, "Expecting a Hash object for data, got #{data.class}" unless data.kind_of?(Hash)
33
+ raise ArgumentError, "Push data field is empty. You must provide attributes for the push notification" if data.empty?
34
+
35
+ publish_data = data.merge(recipient: IdiomaticRubyWrapper(recipient))
36
+ # Co-erce to camelCase for notitication fields which are always camelCase
37
+ publish_data[:notification] = IdiomaticRubyWrapper(data[:notification]) if publish_data[:notification].kind_of?(Hash)
38
+ client.post('/push/publish', publish_data)
39
+ end
40
+
41
+ # Manage device registrations
42
+ # @return [Ably::Rest::Push::DeviceRegistrations]
43
+ def device_registrations
44
+ @device_registrations ||= DeviceRegistrations.new(self)
45
+ end
46
+
47
+ # Manage channel subscriptions for devices or clients
48
+ # @return [Ably::Rest::Push::ChannelSubscriptions]
49
+ def channel_subscriptions
50
+ @channel_subscriptions ||= ChannelSubscriptions.new(self)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,121 @@
1
+ module Ably::Rest
2
+ class Push
3
+ # Manage push notification channel subscriptions for devices or client identifiers
4
+ class ChannelSubscriptions
5
+ include Ably::Modules::Conversions
6
+
7
+ # @api private
8
+ attr_reader :client
9
+
10
+ # @api private
11
+ attr_reader :admin
12
+
13
+ def initialize(admin)
14
+ @admin = admin
15
+ @client = admin.client
16
+ end
17
+
18
+ # List channel subscriptions filtered by optional params
19
+ #
20
+ # @param [Hash] params the filter options for the list channel subscription request. At least one of channel, client_id or device_id is required
21
+ # @option params [String] :channel filter by realtime pub/sub channel name
22
+ # @option params [String] :client_id filter by devices registered to a client identifier. If provided with device_id param, a concat operation is used so that any device with this client_id or provided device_id is returned.
23
+ # @option params [String] :device_id filter by unique device ID. If provided with client_id param, a concat operation is used so that any device with this device_id or provided client_id is returned.
24
+ # @option params [Integer] :limit maximum number of subscriptions to retrieve up to 1,000, defaults to 100
25
+ #
26
+ # @return [Ably::Models::PaginatedResult<Ably::Models::PushChannelSubscription>] Paginated list of matching {Ably::Models::PushChannelSubscription}
27
+ #
28
+ def list(params)
29
+ raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
30
+
31
+ if (IdiomaticRubyWrapper(params).keys & [:channel, :client_id, :device_id]).length == 0
32
+ raise ArgumentError, "at least one channel, client_id or device_id filter param must be provided"
33
+ end
34
+
35
+ params = params.clone
36
+
37
+ paginated_options = {
38
+ coerce_into: 'Ably::Models::PushChannelSubscription',
39
+ async_blocking_operations: params.delete(:async_blocking_operations),
40
+ }
41
+
42
+ response = client.get('/push/channelSubscriptions', IdiomaticRubyWrapper(params).as_json)
43
+
44
+ Ably::Models::PaginatedResult.new(response, '', client, paginated_options)
45
+ end
46
+
47
+ # List channels with at least one subscribed device
48
+ #
49
+ # @param [Hash] params the options for the list channels request
50
+ # @option params [Integer] :limit maximum number of channels to retrieve up to 1,000, defaults to 100
51
+ #
52
+ # @return [Ably::Models::PaginatedResult<String>] Paginated list of matching {Ably::Models::PushChannelSubscription}
53
+ #
54
+ def list_channels(params = {})
55
+ params = {} if params.nil?
56
+ raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
57
+
58
+ params = params.clone
59
+
60
+ paginated_options = {
61
+ coerce_into: 'String',
62
+ async_blocking_operations: params.delete(:async_blocking_operations),
63
+ }
64
+
65
+ response = client.get('/push/channels', IdiomaticRubyWrapper(params).as_json)
66
+
67
+ Ably::Models::PaginatedResult.new(response, '', client, paginated_options)
68
+ end
69
+
70
+ # Save push channel subscription for a device or client ID
71
+ #
72
+ # @param [Ably::Models::PushChannelSubscription,Hash] push_channel_subscription the push channel subscription details to save
73
+ #
74
+ # @return [void]
75
+ #
76
+ def save(push_channel_subscription)
77
+ push_channel_subscription_object = PushChannelSubscription(push_channel_subscription)
78
+ raise ArgumentError, "Channel is required yet is empty" if push_channel_subscription_object.channel.to_s.empty?
79
+
80
+ client.post("/push/channelSubscriptions", push_channel_subscription_object.as_json)
81
+ end
82
+
83
+ # Remove a push channel subscription
84
+ #
85
+ # @param [Ably::Models::PushChannelSubscription,Hash] push_channel_subscription the push channel subscription details to remove
86
+ #
87
+ # @return [void]
88
+ #
89
+ def remove(push_channel_subscription)
90
+ push_channel_subscription_object = PushChannelSubscription(push_channel_subscription)
91
+ raise ArgumentError, "Channel is required yet is empty" if push_channel_subscription_object.channel.to_s.empty?
92
+ if push_channel_subscription_object.client_id.to_s.empty? && push_channel_subscription_object.device_id.to_s.empty?
93
+ raise ArgumentError, "Either client_id or device_id must be present"
94
+ end
95
+
96
+ client.delete("/push/channelSubscriptions", push_channel_subscription_object.as_json)
97
+ end
98
+
99
+ # Remove all matching push channel subscriptions
100
+ #
101
+ # @param [Hash] params the filter options for the list channel subscription request. At least one of channel, client_id or device_id is required
102
+ # @option params [String] :channel filter by realtime pub/sub channel name
103
+ # @option params [String] :client_id filter by devices registered to a client identifier. If provided with device_id param, a concat operation is used so that any device with this client_id or provided device_id is returned.
104
+ # @option params [String] :device_id filter by unique device ID. If provided with client_id param, a concat operation is used so that any device with this device_id or provided client_id is returned.
105
+ #
106
+ # @return [void]
107
+ #
108
+ def remove_where(params)
109
+ raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
110
+
111
+ if (IdiomaticRubyWrapper(params).keys & [:channel, :client_id, :device_id]).length == 0
112
+ raise ArgumentError, "at least one channel, client_id or device_id filter param must be provided"
113
+ end
114
+
115
+ params = params.clone
116
+
117
+ client.delete("/push/channelSubscriptions", IdiomaticRubyWrapper(params).as_json)
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,103 @@
1
+ module Ably::Rest
2
+ class Push
3
+ # Manage device registrations for push notifications
4
+ class DeviceRegistrations
5
+ include Ably::Modules::Conversions
6
+
7
+ # @api private
8
+ attr_reader :client
9
+
10
+ # @api private
11
+ attr_reader :admin
12
+
13
+ def initialize(admin)
14
+ @admin = admin
15
+ @client = admin.client
16
+ end
17
+
18
+ # Get registered device by device ID
19
+ #
20
+ # @param [String, Ably::Models::DeviceDetails] device_id the device to retrieve
21
+ #
22
+ # @return [Ably::Models::DeviceDetails] Returns {Ably::Models::DeviceDetails} if a match is found else a {Ably::Exceptions::ResourceMissing} is raised
23
+ #
24
+ def get(device_id)
25
+ device_id = device_id.id if device_id.kind_of?(Ably::Models::DeviceDetails)
26
+ raise ArgumentError, "device_id must be a string or DeviceDetails object" unless device_id.kind_of?(String)
27
+
28
+ DeviceDetails(client.get("/push/deviceRegistrations/#{device_id}").body)
29
+ end
30
+
31
+ # List registered devices filtered by optional params
32
+ #
33
+ # @param [Hash] params the filter options for the list registered device request
34
+ # @option params [String] :client_id filter by devices registered to a client identifier. Cannot be used with +device_id+ param
35
+ # @option params [String] :device_id filter by unique device ID. Cannot be used with +client_id+ param
36
+ # @option params [Integer] :limit maximum number of devices to retrieve up to 1,000, defaults to 100
37
+ #
38
+ # @return [Ably::Models::PaginatedResult<Ably::Models::DeviceDetails>] Paginated list of matching {Ably::Models::DeviceDetails}
39
+ #
40
+ def list(params = {})
41
+ params = {} if params.nil?
42
+ raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
43
+ raise ArgumentError, "device_id filter cannot be specified alongside a client_id filter. Use one or the other" if params[:client_id] && params[:device_id]
44
+
45
+ params = params.clone
46
+
47
+ paginated_options = {
48
+ coerce_into: 'Ably::Models::DeviceDetails',
49
+ async_blocking_operations: params.delete(:async_blocking_operations),
50
+ }
51
+
52
+ response = client.get('/push/deviceRegistrations', IdiomaticRubyWrapper(params).as_json)
53
+
54
+ Ably::Models::PaginatedResult.new(response, '', client, paginated_options)
55
+ end
56
+
57
+ # Save and register device
58
+ #
59
+ # @param [Ably::Models::DeviceDetails, Hash] device the device details to save
60
+ #
61
+ # @return [void]
62
+ #
63
+ def save(device)
64
+ device_details = DeviceDetails(device)
65
+ raise ArgumentError, "Device ID is required yet is empty" if device_details.id.nil? || device_details == ''
66
+
67
+ client.put("/push/deviceRegistrations/#{device_details.id}", device_details.as_json)
68
+ end
69
+
70
+ # Remove device
71
+ #
72
+ # @param [String, Ably::Models::DeviceDetails] device_id the device to remove
73
+ #
74
+ # @return [void]
75
+ #
76
+ def remove(device_id)
77
+ device_id = device_id.id if device_id.kind_of?(Ably::Models::DeviceDetails)
78
+ raise ArgumentError, "device_id must be a string or DeviceDetails object" unless device_id.kind_of?(String)
79
+
80
+ client.delete("/push/deviceRegistrations/#{device_id}", {})
81
+ end
82
+
83
+ # Remove device matching where params
84
+ #
85
+ # @param [Hash] params the filter params for the remove request
86
+ # @option params [String] :client_id remove devices registered to a client identifier. Cannot be used with +device_id+ param
87
+ # @option params [String] :device_id remove device with this unique device ID. Cannot be used with +client_id+ param
88
+ #
89
+ # @return [void]
90
+ #
91
+ def remove_where(params = {})
92
+ filter = if params.kind_of?(Ably::Models::DeviceDetails)
93
+ { 'deviceId' => params.id }
94
+ else
95
+ raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
96
+ raise ArgumentError, "device_id filter cannot be specified alongside a client_id filter. Use one or the other" if params[:client_id] && params[:device_id]
97
+ IdiomaticRubyWrapper(params).as_json
98
+ end
99
+ client.delete("/push/deviceRegistrations", filter)
100
+ end
101
+ end
102
+ end
103
+ end
@@ -1,6 +1,6 @@
1
1
  module Ably
2
- VERSION = '1.0.7'
3
- PROTOCOL_VERSION = '1.0'
2
+ VERSION = '1.1.4.rc'
3
+ PROTOCOL_VERSION = '1.1'
4
4
 
5
5
  # Allow a variant to be configured for all instances of this client library
6
6
  # such as ruby-rest-[VERSION]
@@ -13,4 +13,9 @@ module Ably
13
13
  def self.lib_variant
14
14
  @lib_variant
15
15
  end
16
+
17
+ # @api private
18
+ def self.major_minor_version_numeric
19
+ VERSION.gsub(/\.\d+$/, '').to_f
20
+ end
16
21
  end
@@ -607,16 +607,17 @@ describe Ably::Realtime::Auth, :event_machine do
607
607
 
608
608
  context 'when auth fails' do
609
609
  let(:client_options) { default_options.merge(auth_callback: basic_token_cb, log_level: :none) }
610
+ let!(:token_string) { client.rest_client.auth.request_token.token }
610
611
 
611
612
  it 'transitions the connection state to the FAILED state (#RSA15c, #RTC8a2, #RTC8a3)' do
612
613
  connection_failed = false
613
614
 
614
615
  client.connection.once(:connected) do
615
- client.auth.authorize(nil, auth_callback: lambda { |token_params| 'invalid.token:will.cause.failure' }).tap do |deferrable|
616
+ client.auth.authorize(nil, auth_callback: lambda { |token_params| "#{app_id}.invalid.token.will.cause.failure" }).tap do |deferrable|
616
617
  deferrable.errback do |error|
617
618
  EventMachine.add_timer(0.2) do
618
619
  expect(connection_failed).to eql(true)
619
- expect(error.message).to match(/Invalid accessToken/i)
620
+ expect(error.message).to match(/invalid.*accessToken/i)
620
621
  expect(error.code).to eql(40005)
621
622
  stop_reactor
622
623
  end
@@ -626,7 +627,7 @@ describe Ably::Realtime::Auth, :event_machine do
626
627
  end
627
628
 
628
629
  client.connection.once(:failed) do
629
- expect(client.connection.error_reason.message).to match(/Invalid accessToken/i)
630
+ expect(client.connection.error_reason.message).to match(/invalid.*accessToken/i)
630
631
  expect(client.connection.error_reason.code).to eql(40005)
631
632
  connection_failed = true
632
633
  end
@@ -660,17 +661,19 @@ describe Ably::Realtime::Auth, :event_machine do
660
661
  client.connection.once(:disconnected) { raise 'Upgrade does not require a disconnect' }
661
662
 
662
663
  channel = client.channels.get('foo')
663
- channel.publish('not-allowed').errback do |error|
664
- expect(error.code).to eql(40160)
665
- expect(error.message).to match(/permission denied/)
664
+ channel.attach do
665
+ channel.publish('not-allowed').errback do |error|
666
+ expect(error.code).to eql(40160)
667
+ expect(error.message).to match(/permission denied/)
666
668
 
667
- client.auth.authorize(nil, auth_callback: upgraded_token_cb)
668
- client.connection.once(:update) do
669
- expect(client.connection.error_reason).to be_nil
670
- channel.subscribe('now-allowed') do |message|
671
- stop_reactor
669
+ client.auth.authorize(nil, auth_callback: upgraded_token_cb)
670
+ client.connection.once(:update) do
671
+ expect(client.connection.error_reason).to be_nil
672
+ channel.subscribe('now-allowed') do |message|
673
+ stop_reactor
674
+ end
675
+ channel.publish 'now-allowed'
672
676
  end
673
- channel.publish 'now-allowed'
674
677
  end
675
678
  end
676
679
  end
@@ -749,11 +752,8 @@ describe Ably::Realtime::Auth, :event_machine do
749
752
  end
750
753
 
751
754
  context 'when received' do
752
- # Ably in all environments other than locla will send AUTH 30 seconds before expiry
753
- # We set the TTL to 33s and wait (3s window)
754
- # In local env, that window is 5 seconds instead of 30 seconds
755
- let(:local_offset) { ENV['ABLY_ENV'] == 'local' ? 25 : 0 }
756
- let(:client_options) { default_options.merge(use_token_auth: :true, default_token_params: { ttl: 33 - local_offset }) }
755
+ # Ably will send AUTH 30 seconds before expiry
756
+ let(:client_options) { default_options.merge(use_token_auth: :true, default_token_params: { ttl: 33 }) }
757
757
 
758
758
  it 'should immediately start a new authentication process (#RTN22)' do
759
759
  client.connection.once(:connected) do
@@ -1058,7 +1058,7 @@ describe Ably::Realtime::Auth, :event_machine do
1058
1058
 
1059
1059
  it 'disconnected includes and invalid signature message' do
1060
1060
  client.connection.once(:disconnected) do |state_change|
1061
- expect(state_change.reason.message.match(/invalid signature/i)).to_not be_nil
1061
+ expect(state_change.reason.message.match(/signature verification failed/i)).to_not be_nil
1062
1062
  expect(state_change.reason.code).to eql(40144)
1063
1063
  stop_reactor
1064
1064
  end
@@ -1111,7 +1111,7 @@ describe Ably::Realtime::Auth, :event_machine do
1111
1111
 
1112
1112
  it 'authentication fails and reason for disconnection is invalid signature' do
1113
1113
  client.connection.once(:disconnected) do |state_change|
1114
- expect(state_change.reason.message.match(/invalid signature/i)).to_not be_nil
1114
+ expect(state_change.reason.message.match(/signature verification failed/i)).to_not be_nil
1115
1115
  expect(state_change.reason.code).to eql(40144)
1116
1116
  stop_reactor
1117
1117
  end
@@ -1139,10 +1139,11 @@ describe Ably::Realtime::Auth, :event_machine do
1139
1139
  context 'when credentials are invalid' do
1140
1140
  let(:key_secret) { 'invalid' }
1141
1141
  let(:token) { Faraday.get("#{auth_url}?keyName=#{key_name}&keySecret=#{key_secret}").body }
1142
+ let(:client_options) { { token: token, environment: environment, protocol: protocol, log_level: :none } }
1142
1143
 
1143
1144
  it 'fails with an invalid signature error' do
1144
1145
  client.connection.once(:disconnected) do |state_change|
1145
- expect(state_change.reason.message.match(/invalid signature/i)).to_not be_nil
1146
+ expect(state_change.reason.message.match(/signature verification failed/i)).to_not be_nil
1146
1147
  expect(state_change.reason.code).to eql(40144)
1147
1148
  stop_reactor
1148
1149
  end
@@ -1239,7 +1240,7 @@ describe Ably::Realtime::Auth, :event_machine do
1239
1240
  Faraday.get("#{auth_url}?keyName=#{key_name}&keySecret=#{key_secret}&capability=#{URI.escape(basic_capability)}").body
1240
1241
  end
1241
1242
  end
1242
- let(:client_options) { default_options.merge(auth_callback: auth_callback) }
1243
+ let(:client_options) { default_options.merge(auth_callback: auth_callback, log_level: :error) }
1243
1244
 
1244
1245
  it 'client fails to publish to a channel with subscribe-only capability and publishes successfully on a channel with permissions' do
1245
1246
  client.connection.once(:connected) do