ably 0.8.1 → 0.8.2

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 (47) hide show
  1. checksums.yaml +5 -13
  2. data/README.md +11 -11
  3. data/SPEC.md +87 -87
  4. data/ably.gemspec +1 -1
  5. data/lib/ably/exceptions.rb +4 -1
  6. data/lib/ably/models/{paginated_resource.rb → paginated_result.rb} +8 -8
  7. data/lib/ably/models/presence_message.rb +1 -1
  8. data/lib/ably/modules/conversions.rb +15 -0
  9. data/lib/ably/modules/encodeable.rb +2 -2
  10. data/lib/ably/modules/event_emitter.rb +8 -8
  11. data/lib/ably/modules/safe_deferrable.rb +15 -3
  12. data/lib/ably/modules/state_emitter.rb +2 -2
  13. data/lib/ably/modules/state_machine.rb +1 -1
  14. data/lib/ably/realtime/channel.rb +2 -4
  15. data/lib/ably/realtime/channel/channel_manager.rb +1 -1
  16. data/lib/ably/realtime/client.rb +4 -4
  17. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +2 -2
  18. data/lib/ably/realtime/connection.rb +1 -1
  19. data/lib/ably/realtime/connection/connection_manager.rb +3 -3
  20. data/lib/ably/realtime/connection/connection_state_machine.rb +1 -1
  21. data/lib/ably/realtime/connection/websocket_transport.rb +2 -2
  22. data/lib/ably/realtime/presence.rb +23 -5
  23. data/lib/ably/realtime/presence/members_map.rb +16 -13
  24. data/lib/ably/rest/channel.rb +3 -2
  25. data/lib/ably/rest/client.rb +2 -2
  26. data/lib/ably/rest/presence.rb +4 -4
  27. data/lib/ably/util/pub_sub.rb +1 -1
  28. data/lib/ably/util/safe_deferrable.rb +1 -1
  29. data/lib/ably/version.rb +1 -1
  30. data/spec/acceptance/realtime/channel_history_spec.rb +1 -1
  31. data/spec/acceptance/realtime/channel_spec.rb +5 -15
  32. data/spec/acceptance/realtime/connection_failures_spec.rb +2 -2
  33. data/spec/acceptance/realtime/connection_spec.rb +16 -14
  34. data/spec/acceptance/realtime/message_spec.rb +91 -8
  35. data/spec/acceptance/realtime/presence_spec.rb +190 -71
  36. data/spec/acceptance/realtime/stats_spec.rb +2 -2
  37. data/spec/acceptance/rest/channel_spec.rb +1 -1
  38. data/spec/acceptance/rest/encoders_spec.rb +1 -1
  39. data/spec/acceptance/rest/message_spec.rb +73 -1
  40. data/spec/acceptance/rest/presence_spec.rb +4 -2
  41. data/spec/unit/models/{paginated_resource_spec.rb → paginated_result_spec.rb} +18 -18
  42. data/spec/unit/modules/event_emitter_spec.rb +27 -27
  43. data/spec/unit/modules/state_emitter_spec.rb +1 -1
  44. data/spec/unit/realtime/channel_spec.rb +2 -2
  45. data/spec/unit/realtime/connection_spec.rb +3 -3
  46. data/spec/unit/realtime/presence_spec.rb +2 -2
  47. metadata +44 -44
@@ -7,9 +7,9 @@ describe Ably::Realtime::Client, '#stats', :event_machine do
7
7
  end
8
8
 
9
9
  describe 'fetching stats' do
10
- it 'should return a PaginatedResource' do
10
+ it 'should return a PaginatedResult' do
11
11
  client.stats do |stats|
12
- expect(stats).to be_a(Ably::Models::PaginatedResource)
12
+ expect(stats).to be_a(Ably::Models::PaginatedResult)
13
13
  stop_reactor
14
14
  end
15
15
  end
@@ -64,7 +64,7 @@ describe Ably::Rest::Channel do
64
64
  end
65
65
  end
66
66
 
67
- it 'should return paged history using the PaginatedResource model' do
67
+ it 'should return paged history using the PaginatedResult model' do
68
68
  page_1 = channel.history(limit: 1)
69
69
  page_2 = page_1.next
70
70
  page_3 = page_2.next
@@ -162,7 +162,7 @@ describe Ably::Models::MessageEncoders do
162
162
  context 'with binary data' do
163
163
  let(:published_data) { binary_data }
164
164
 
165
- it 'applies cipher and base64 encoding and sets the encoding attribute to "utf-8/cipher+aes-128-cbc/base64"' do
165
+ it 'applies cipher and base64 encoding and sets the encoding attribute to "cipher+aes-128-cbc/base64"' do
166
166
  on_publish do |encoding, encoded_data|
167
167
  expect(encoding).to eql('cipher+aes-128-cbc/base64')
168
168
  expect(decrypted(encoded_data, base64: true)).to eql(published_data)
@@ -10,7 +10,7 @@ describe Ably::Rest::Channel, 'messages' do
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) }
13
- let(:channel) { client.channel('test') }
13
+ let(:channel) { client.channel(random_str) }
14
14
 
15
15
  context 'publishing with an ASCII_8BIT message name' do
16
16
  let(:message_name) { random_str.encode(Encoding::ASCII_8BIT) }
@@ -23,6 +23,78 @@ describe Ably::Rest::Channel, 'messages' do
23
23
  end
24
24
  end
25
25
 
26
+ context 'with supported data payload content type' do
27
+ context 'JSON Object (Hash)' do
28
+ let(:data) { { 'Hash' => 'true' } }
29
+
30
+ it 'is encoded and decoded to the same hash' do
31
+ channel.publish 'event', data
32
+ expect(channel.history.items.first.data).to eql(data)
33
+ end
34
+ end
35
+
36
+ context 'JSON Array' do
37
+ let(:data) { [ nil, true, false, 55, 'string', { 'Hash' => true }, ['array'] ] }
38
+
39
+ it 'is encoded and decoded to the same Array' do
40
+ channel.publish 'event', data
41
+ expect(channel.history.items.first.data).to eql(data)
42
+ end
43
+ end
44
+
45
+ context 'String' do
46
+ let(:data) { random_str }
47
+
48
+ it 'is encoded and decoded to the same Array' do
49
+ channel.publish 'event', data
50
+ expect(channel.history.items.first.data).to eql(data)
51
+ end
52
+ end
53
+
54
+ context 'Binary' do
55
+ let(:data) { Base64.encode64(random_str) }
56
+
57
+ it 'is encoded and decoded to the same Array' do
58
+ channel.publish 'event', data
59
+ expect(channel.history.items.first.data).to eql(data)
60
+ end
61
+ end
62
+ end
63
+
64
+ context 'with unsupported data payload content type' do
65
+ context 'Integer' do
66
+ let(:data) { 1 }
67
+
68
+ it 'is raises an UnsupportedDataTypeError 40011 exception' do
69
+ expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
70
+ end
71
+ end
72
+
73
+ context 'Float' do
74
+ let(:data) { 1.1 }
75
+
76
+ it 'is raises an UnsupportedDataTypeError 40011 exception' do
77
+ expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
78
+ end
79
+ end
80
+
81
+ context 'Boolean' do
82
+ let(:data) { true }
83
+
84
+ it 'is raises an UnsupportedDataTypeError 40011 exception' do
85
+ expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
86
+ end
87
+ end
88
+
89
+ context 'False' do
90
+ let(:data) { false }
91
+
92
+ it 'is raises an UnsupportedDataTypeError 40011 exception' do
93
+ expect { channel.publish 'event', data }.to raise_error(Ably::Exceptions::UnsupportedDataTypeError)
94
+ end
95
+ end
96
+ end
97
+
26
98
  describe 'encryption and encoding' do
27
99
  let(:channel_name) { "persisted:#{random_str}" }
28
100
  let(:cipher_options) { { key: random_str(32) } }
@@ -54,6 +54,8 @@ describe Ably::Rest::Presence do
54
54
 
55
55
  it 'returns a paged response limiting number of members per page' do
56
56
  expect(presence_page.items.size).to eql(page_size)
57
+ # TODO: To be enabled once Realtime Presence issue #164 is resolved
58
+ # expect(presence_page).to be_first
57
59
  next_page = presence_page.next
58
60
  expect(next_page.items.size).to eql(page_size)
59
61
  expect(next_page).to be_last
@@ -81,7 +83,7 @@ describe Ably::Rest::Presence do
81
83
  let(:paged_history_forward) { fixtures_channel.presence.history(limit: page_size, direction: :forwards) }
82
84
 
83
85
  it 'returns recent presence activity forwards with most recent history last' do
84
- expect(paged_history_forward).to be_a(Ably::Models::PaginatedResource)
86
+ expect(paged_history_forward).to be_a(Ably::Models::PaginatedResult)
85
87
  expect(paged_history_forward.items.size).to eql(page_size)
86
88
 
87
89
  next_page = paged_history_forward.next
@@ -96,7 +98,7 @@ describe Ably::Rest::Presence do
96
98
  let(:paged_history_backward) { fixtures_channel.presence.history(limit: page_size, direction: :backwards) }
97
99
 
98
100
  it 'returns recent presence activity backwards with most recent history first' do
99
- expect(paged_history_backward).to be_a(Ably::Models::PaginatedResource)
101
+ expect(paged_history_backward).to be_a(Ably::Models::PaginatedResult)
100
102
  expect(paged_history_backward.items.size).to eql(page_size)
101
103
 
102
104
  next_page = paged_history_backward.next
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
  require 'ostruct'
3
3
 
4
- describe Ably::Models::PaginatedResource do
5
- let(:paginated_resource_class) { Ably::Models::PaginatedResource }
4
+ describe Ably::Models::PaginatedResult do
5
+ let(:paginated_result_class) { Ably::Models::PaginatedResult }
6
6
  let(:headers) { Hash.new }
7
7
  let(:client) do
8
8
  instance_double('Ably::Rest::Client', logger: Ably::Models::NilLogger.new).tap do |client|
@@ -23,8 +23,8 @@ describe Ably::Models::PaginatedResource do
23
23
  end
24
24
  let(:base_url) { 'http://rest.ably.io/channels/channel_name' }
25
25
  let(:full_url) { "#{base_url}/whatever?param=exists" }
26
- let(:paginated_resource_options) { Hash.new }
27
- let(:first_paged_request) { paginated_resource_class.new(http_response, full_url, client, paginated_resource_options) }
26
+ let(:paginated_result_options) { Hash.new }
27
+ let(:first_paged_request) { paginated_result_class.new(http_response, full_url, client, paginated_result_options) }
28
28
  subject { first_paged_request }
29
29
 
30
30
  context '#items' do
@@ -69,7 +69,7 @@ describe Ably::Models::PaginatedResource do
69
69
  end
70
70
 
71
71
  context 'with coercion', :api_private do
72
- let(:paginated_resource_options) { { coerce_into: 'OpenStruct' } }
72
+ let(:paginated_result_options) { { coerce_into: 'OpenStruct' } }
73
73
 
74
74
  it 'returns coerced objects' do
75
75
  expect(subject.items.first).to be_a(OpenStruct)
@@ -106,17 +106,17 @@ describe Ably::Models::PaginatedResource do
106
106
 
107
107
  context 'with each block' do
108
108
  subject do
109
- paginated_resource_class.new(http_response, full_url, paged_client, paginated_resource_options) do |resource|
110
- resource[:added_attribute_from_block] = "id:#{resource[:id]}"
111
- resource
109
+ paginated_result_class.new(http_response, full_url, paged_client, paginated_result_options) do |result|
110
+ result[:added_attribute_from_block] = "id:#{result[:id]}"
111
+ result
112
112
  end
113
113
  end
114
114
 
115
- it 'calls the block for each resource after retrieving the resources' do
115
+ it 'calls the block for each result after retrieving the results' do
116
116
  expect(subject.items[0][:added_attribute_from_block]).to eql("id:#{body[0][:id]}")
117
117
  end
118
118
 
119
- it 'calls the block for each resource on second page after retrieving the resources' do
119
+ it 'calls the block for each result on second page after retrieving the results' do
120
120
  page_1_first_id = subject.items[0][:id]
121
121
  next_page = subject.next
122
122
 
@@ -130,7 +130,7 @@ describe Ably::Models::PaginatedResource do
130
130
  include RSpec::EventMachine
131
131
 
132
132
  subject do
133
- paginated_resource_class.new(http_response, full_url, paged_client, async_blocking_operations: true)
133
+ paginated_result_class.new(http_response, full_url, paged_client, async_blocking_operations: true)
134
134
  end
135
135
 
136
136
  context '#next' do
@@ -143,8 +143,8 @@ describe Ably::Models::PaginatedResource do
143
143
 
144
144
  it 'allows a success callback block to be added' do
145
145
  run_reactor do
146
- subject.next do |paginated_resource|
147
- expect(paginated_resource).to be_a(Ably::Models::PaginatedResource)
146
+ subject.next do |paginated_result|
147
+ expect(paginated_result).to be_a(Ably::Models::PaginatedResult)
148
148
  stop_reactor
149
149
  end
150
150
  end
@@ -154,7 +154,7 @@ describe Ably::Models::PaginatedResource do
154
154
  context '#first' do
155
155
  it 'calls the errback callback when first page headers are missing' do
156
156
  run_reactor do
157
- subject.next do |paginated_resource|
157
+ subject.next do |paginated_result|
158
158
  deferrable = subject.first
159
159
  deferrable.errback do |error|
160
160
  expect(error).to be_a(Ably::Exceptions::InvalidPageError)
@@ -247,8 +247,8 @@ describe Ably::Models::PaginatedResource do
247
247
  expect(client).to receive(:get).with("#{base_url}/history?index=1").and_return(next_http_response).once
248
248
  end
249
249
 
250
- it 'returns another PaginatedResource' do
251
- expect(subject).to be_a(paginated_resource_class)
250
+ it 'returns another PaginatedResult' do
251
+ expect(subject).to be_a(paginated_result_class)
252
252
  end
253
253
 
254
254
  it 'retrieves the next page of results' do
@@ -279,8 +279,8 @@ describe Ably::Models::PaginatedResource do
279
279
  end
280
280
  subject { first_paged_request.next.first }
281
281
 
282
- it 'returns a PaginatedResource' do
283
- expect(subject).to be_a(paginated_resource_class)
282
+ it 'returns a PaginatedResult' do
283
+ expect(subject).to be_a(paginated_result_class)
284
284
  end
285
285
 
286
286
  it 'retrieves the first page of results' do
@@ -15,23 +15,23 @@ describe Ably::Modules::EventEmitter do
15
15
 
16
16
  subject { klass.new }
17
17
 
18
- context '#trigger event fan out' do
18
+ context '#emit event fan out' do
19
19
  it 'should emit an event for any number of subscribers' do
20
20
  2.times do
21
21
  subject.on(:message) { |msg| obj.received_message msg }
22
22
  end
23
23
 
24
24
  expect(obj).to receive(:received_message).with(msg).twice
25
- subject.trigger :message, msg
25
+ subject.emit :message, msg
26
26
  end
27
27
 
28
28
  it 'sends only messages to matching event names' do
29
29
  subject.on(:valid) { |msg| obj.received_message msg }
30
30
 
31
31
  expect(obj).to receive(:received_message).with(msg).once
32
- subject.trigger :valid, msg
33
- subject.trigger :ignored, msg
34
- subject.trigger 'valid', msg
32
+ subject.emit :valid, msg
33
+ subject.emit :ignored, msg
34
+ subject.emit 'valid', msg
35
35
  end
36
36
 
37
37
  context 'with coercion', :api_private do
@@ -43,7 +43,7 @@ describe Ably::Modules::EventEmitter do
43
43
  subject.on('valid') { |msg| obj.received_message msg }
44
44
 
45
45
  expect(obj).to receive(:received_message).with(msg).once
46
- subject.trigger :valid, msg
46
+ subject.emit :valid, msg
47
47
  end
48
48
  end
49
49
 
@@ -52,7 +52,7 @@ describe Ably::Modules::EventEmitter do
52
52
  subject.on('valid') { |msg| obj.received_message msg }
53
53
 
54
54
  expect(obj).to_not receive(:received_message).with(msg)
55
- subject.trigger :valid, msg
55
+ subject.emit :valid, msg
56
56
  end
57
57
  end
58
58
 
@@ -62,8 +62,8 @@ describe Ably::Modules::EventEmitter do
62
62
 
63
63
  expect(obj).to receive(:received_message).with(msg).twice
64
64
 
65
- subject.trigger :click, msg
66
- subject.trigger :hover, msg
65
+ subject.emit :click, msg
66
+ subject.emit :hover, msg
67
67
  end
68
68
  end
69
69
 
@@ -84,17 +84,17 @@ describe Ably::Modules::EventEmitter do
84
84
  it 'is unaffected and processes the prior event callbacks once' do
85
85
  expect(obj).to receive(:received_message).with(msg).twice
86
86
  expect(obj).to_not receive(:received_message_from_new_callbacks).with(msg)
87
- subject.trigger :message, msg
87
+ subject.emit :message, msg
88
88
  end
89
89
 
90
90
  it 'adds them for the next emitted event' do
91
91
  expect(obj).to receive(:received_message_from_new_callbacks).with(msg).twice
92
92
 
93
- # New callbacks are added in this trigger
94
- subject.trigger :message, msg
93
+ # New callbacks are added in this emit
94
+ subject.emit :message, msg
95
95
 
96
96
  # New callbacks are now called with second event emitted
97
- subject.trigger :message, msg
97
+ subject.emit :message, msg
98
98
  end
99
99
  end
100
100
 
@@ -110,16 +110,16 @@ describe Ably::Modules::EventEmitter do
110
110
 
111
111
  it 'is unaffected and processes the prior event callbacks once' do
112
112
  expect(obj).to receive(:received_message).with(msg).twice
113
- subject.trigger :message, msg
113
+ subject.emit :message, msg
114
114
  end
115
115
 
116
116
  it 'removes them for the next emitted event' do
117
117
  expect(obj).to receive(:received_message).with(msg).twice
118
118
 
119
- # Callbacks are removed in this trigger
120
- subject.trigger :message, msg
119
+ # Callbacks are removed in this emit
120
+ subject.emit :message, msg
121
121
  # No callbacks should exist now
122
- subject.trigger :message, msg
122
+ subject.emit :message, msg
123
123
  end
124
124
  end
125
125
  end
@@ -129,14 +129,14 @@ describe Ably::Modules::EventEmitter do
129
129
  it 'calls the block every time an event is emitted only' do
130
130
  block_called = 0
131
131
  subject.on('event') { block_called += 1 }
132
- 3.times { subject.trigger 'event', 'data' }
132
+ 3.times { subject.emit 'event', 'data' }
133
133
  expect(block_called).to eql(3)
134
134
  end
135
135
 
136
136
  it 'catches exceptions in the provided block, logs the error and continues' do
137
137
  expect(subject.logger).to receive(:error).with(/Intentional exception/)
138
138
  subject.on(:event) { raise 'Intentional exception' }
139
- subject.trigger :event
139
+ subject.emit :event
140
140
  end
141
141
  end
142
142
 
@@ -144,13 +144,13 @@ describe Ably::Modules::EventEmitter do
144
144
  it 'calls the block every time an event is emitted only' do
145
145
  block_called = 0
146
146
  subject.unsafe_on('event') { block_called += 1 }
147
- 3.times { subject.trigger 'event', 'data' }
147
+ 3.times { subject.emit 'event', 'data' }
148
148
  expect(block_called).to eql(3)
149
149
  end
150
150
 
151
151
  it 'does not catch exceptions in provided blocks' do
152
152
  subject.unsafe_on(:event) { raise 'Intentional exception' }
153
- expect { subject.trigger :event }.to raise_error(/Intentional exception/)
153
+ expect { subject.emit :event }.to raise_error(/Intentional exception/)
154
154
  end
155
155
  end
156
156
 
@@ -158,7 +158,7 @@ describe Ably::Modules::EventEmitter do
158
158
  it 'calls the block the first time an event is emitted only' do
159
159
  block_called = 0
160
160
  subject.once('event') { block_called += 1 }
161
- 3.times { subject.trigger 'event', 'data' }
161
+ 3.times { subject.emit 'event', 'data' }
162
162
  expect(block_called).to eql(1)
163
163
  end
164
164
 
@@ -166,14 +166,14 @@ describe Ably::Modules::EventEmitter do
166
166
  block_called = 0
167
167
  subject.once('event') { block_called += 1 }
168
168
  subject.on('event') { block_called += 1 }
169
- 3.times { subject.trigger 'event', 'data' }
169
+ 3.times { subject.emit 'event', 'data' }
170
170
  expect(block_called).to eql(4)
171
171
  end
172
172
 
173
173
  it 'catches exceptions in the provided block, logs the error and continues' do
174
174
  expect(subject.logger).to receive(:error).with(/Intentional exception/)
175
175
  subject.once(:event) { raise 'Intentional exception' }
176
- subject.trigger :event
176
+ subject.emit :event
177
177
  end
178
178
  end
179
179
 
@@ -181,13 +181,13 @@ describe Ably::Modules::EventEmitter do
181
181
  it 'calls the block the first time an event is emitted only' do
182
182
  block_called = 0
183
183
  subject.unsafe_once('event') { block_called += 1 }
184
- 3.times { subject.trigger 'event', 'data' }
184
+ 3.times { subject.emit 'event', 'data' }
185
185
  expect(block_called).to eql(1)
186
186
  end
187
187
 
188
188
  it 'does not catch exceptions in provided blocks' do
189
189
  subject.unsafe_once(:event) { raise 'Intentional exception' }
190
- expect { subject.trigger :event }.to raise_error(/Intentional exception/)
190
+ expect { subject.emit :event }.to raise_error(/Intentional exception/)
191
191
  end
192
192
  end
193
193
 
@@ -199,7 +199,7 @@ describe Ably::Modules::EventEmitter do
199
199
  end
200
200
 
201
201
  after do
202
- subject.trigger :message, msg
202
+ subject.emit :message, msg
203
203
  end
204
204
 
205
205
  context 'with event names as arguments' do
@@ -41,7 +41,7 @@ describe Ably::Modules::StateEmitter do
41
41
  let(:args) { [5,3,1] }
42
42
  let(:callback_status) { { called: false } }
43
43
 
44
- it 'passes the arguments through to the triggered callback' do
44
+ it 'passes the arguments through to the executed callback' do
45
45
  subject.on(:connecting) do |*callback_args|
46
46
  expect(callback_args).to eql(args)
47
47
  callback_status[:called] = true
@@ -118,12 +118,12 @@ describe Ably::Realtime::Channel do
118
118
  specify 'are supported for valid STATE events' do
119
119
  state = nil
120
120
  subject.on(:initialized) { state = :ready }
121
- expect { subject.trigger(:initialized) }.to change { state }.to(:ready)
121
+ expect { subject.emit(:initialized) }.to change { state }.to(:ready)
122
122
  end
123
123
 
124
124
  specify 'fail with unacceptable STATE event names' do
125
125
  expect { subject.on(:invalid) }.to raise_error KeyError
126
- expect { subject.trigger(:invalid) }.to raise_error KeyError
126
+ expect { subject.emit(:invalid) }.to raise_error KeyError
127
127
  expect { subject.off(:invalid) }.to raise_error KeyError
128
128
  end
129
129
  end