ably 0.1.5 → 0.1.6

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 (86) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -1
  3. data/ably.gemspec +4 -3
  4. data/lib/ably.rb +6 -2
  5. data/lib/ably/auth.rb +24 -16
  6. data/lib/ably/exceptions.rb +16 -5
  7. data/lib/ably/{realtime/models → models}/error_info.rb +9 -11
  8. data/lib/ably/models/idiomatic_ruby_wrapper.rb +57 -26
  9. data/lib/ably/{realtime/models → models}/message.rb +45 -38
  10. data/lib/ably/{realtime/models → models}/nil_channel.rb +4 -4
  11. data/lib/ably/{rest/models/paged_resource.rb → models/paginated_resource.rb} +21 -10
  12. data/lib/ably/models/presence_message.rb +126 -0
  13. data/lib/ably/{realtime/models → models}/protocol_message.rb +76 -38
  14. data/lib/ably/models/token.rb +74 -0
  15. data/lib/ably/modules/channels_collection.rb +49 -0
  16. data/lib/ably/modules/conversions.rb +2 -0
  17. data/lib/ably/modules/event_emitter.rb +43 -8
  18. data/lib/ably/modules/event_machine_helpers.rb +1 -0
  19. data/lib/ably/modules/http_helpers.rb +9 -2
  20. data/lib/ably/modules/message_pack.rb +14 -0
  21. data/lib/ably/modules/model_common.rb +29 -0
  22. data/lib/ably/modules/{state.rb → state_emitter.rb} +8 -7
  23. data/lib/ably/realtime.rb +37 -7
  24. data/lib/ably/realtime/channel.rb +154 -31
  25. data/lib/ably/realtime/channels.rb +47 -0
  26. data/lib/ably/realtime/client.rb +39 -33
  27. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +50 -21
  28. data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +9 -11
  29. data/lib/ably/realtime/connection.rb +148 -79
  30. data/lib/ably/realtime/connection/connection_state_machine.rb +111 -0
  31. data/lib/ably/realtime/connection/websocket_transport.rb +161 -0
  32. data/lib/ably/realtime/presence.rb +270 -0
  33. data/lib/ably/rest.rb +14 -3
  34. data/lib/ably/rest/channel.rb +3 -3
  35. data/lib/ably/rest/channels.rb +26 -12
  36. data/lib/ably/rest/client.rb +42 -25
  37. data/lib/ably/rest/middleware/exceptions.rb +21 -23
  38. data/lib/ably/rest/middleware/external_exceptions.rb +8 -10
  39. data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +17 -0
  40. data/lib/ably/rest/middleware/parse_json.rb +9 -2
  41. data/lib/ably/rest/middleware/parse_message_pack.rb +6 -2
  42. data/lib/ably/rest/presence.rb +4 -4
  43. data/lib/ably/version.rb +1 -1
  44. data/spec/acceptance/realtime/channel_history_spec.rb +125 -0
  45. data/spec/acceptance/realtime/channel_spec.rb +135 -63
  46. data/spec/acceptance/realtime/connection_spec.rb +86 -0
  47. data/spec/acceptance/realtime/message_spec.rb +116 -94
  48. data/spec/acceptance/realtime/presence_history_spec.rb +0 -0
  49. data/spec/acceptance/realtime/presence_spec.rb +277 -0
  50. data/spec/acceptance/rest/auth_spec.rb +351 -347
  51. data/spec/acceptance/rest/base_spec.rb +43 -26
  52. data/spec/acceptance/rest/channel_spec.rb +88 -83
  53. data/spec/acceptance/rest/channels_spec.rb +32 -28
  54. data/spec/acceptance/rest/presence_spec.rb +83 -63
  55. data/spec/acceptance/rest/stats_spec.rb +38 -37
  56. data/spec/acceptance/rest/time_spec.rb +10 -6
  57. data/spec/integration/modules/{state_spec.rb → state_emitter_spec.rb} +16 -2
  58. data/spec/spec_helper.rb +14 -0
  59. data/spec/support/api_helper.rb +4 -0
  60. data/spec/support/model_helper.rb +28 -9
  61. data/spec/support/protocol_msgbus_helper.rb +8 -1
  62. data/spec/support/test_app.rb +24 -14
  63. data/spec/unit/{realtime → models}/error_info_spec.rb +4 -4
  64. data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +46 -9
  65. data/spec/unit/models/message_spec.rb +229 -0
  66. data/spec/unit/{rest/paged_resource_spec.rb → models/paginated_resource_spec.rb} +19 -11
  67. data/spec/unit/models/presence_message_spec.rb +230 -0
  68. data/spec/unit/models/protocol_message_spec.rb +280 -0
  69. data/spec/unit/{token_spec.rb → models/token_spec.rb} +18 -22
  70. data/spec/unit/modules/conversions_spec.rb +1 -1
  71. data/spec/unit/modules/event_emitter_spec.rb +36 -4
  72. data/spec/unit/realtime/channel_spec.rb +76 -2
  73. data/spec/unit/realtime/channels_spec.rb +50 -0
  74. data/spec/unit/realtime/client_spec.rb +31 -1
  75. data/spec/unit/realtime/connection_spec.rb +8 -15
  76. data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +6 -6
  77. data/spec/unit/realtime/presence_spec.rb +100 -0
  78. data/spec/unit/rest/channels_spec.rb +48 -0
  79. metadata +72 -38
  80. data/lib/ably/realtime/models/shared.rb +0 -17
  81. data/lib/ably/rest/models/message.rb +0 -64
  82. data/lib/ably/rest/models/presence_message.rb +0 -21
  83. data/lib/ably/token.rb +0 -80
  84. data/spec/unit/realtime/message_spec.rb +0 -117
  85. data/spec/unit/realtime/protocol_message_spec.rb +0 -172
  86. data/spec/unit/rest/message_spec.rb +0 -75
data/lib/ably/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ably
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.6"
3
3
  end
@@ -0,0 +1,125 @@
1
+ require 'spec_helper'
2
+ require 'securerandom'
3
+
4
+ describe Ably::Realtime::Channel do
5
+ include RSpec::EventMachine
6
+
7
+ [:msgpack, :json].each do |protocol|
8
+ context "over #{protocol}" do
9
+ let(:default_options) { options.merge(api_key: api_key, environment: environment, protocol: protocol) }
10
+
11
+ let(:client) do
12
+ Ably::Realtime::Client.new(default_options)
13
+ end
14
+ let(:channel) { client.channel(channel_name) }
15
+
16
+ let(:client2) do
17
+ Ably::Realtime::Client.new(default_options)
18
+ end
19
+ let(:channel2) { client2.channel(channel_name) }
20
+
21
+ let(:channel_name) { "persisted:#{SecureRandom.hex(2)}" }
22
+ let(:payload) { SecureRandom.hex(4) }
23
+ let(:messages) { [] }
24
+
25
+ let(:options) { { :protocol => :json } }
26
+
27
+ it 'retrieves real-time history' do
28
+ run_reactor do
29
+ channel.publish('event', payload) do |message|
30
+ history = channel.history
31
+ expect(history.length).to eql(1)
32
+ expect(history[0].data).to eql(payload)
33
+ stop_reactor
34
+ end
35
+ end
36
+ end
37
+
38
+ it 'retrieves real-time history across two channels' do
39
+ run_reactor do
40
+ channel.publish('event', payload) do |message|
41
+ channel2.publish('event', payload) do |message|
42
+ history = channel2.history
43
+ expect(history.length).to eql(2)
44
+ expect(history.map(&:data).uniq).to eql([payload])
45
+ stop_reactor
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ context 'with multiple messages' do
52
+ let(:messages_sent) { 20 }
53
+ let(:limit) { 10 }
54
+
55
+ def check_limited_history(direction)
56
+ history = channel.history(direction: direction, limit: limit)
57
+ expect(history.length).to eql(limit)
58
+ limit.times do |index|
59
+ expect(history[index].data).to eql("history#{index}")
60
+ end
61
+
62
+ history = history.next_page
63
+
64
+ expect(history.length).to eql(limit)
65
+ limit.times do |index|
66
+ expect(history[index].data).to eql("history#{index + limit}")
67
+ end
68
+ expect(history.last_page?).to eql(true)
69
+
70
+ stop_reactor
71
+ end
72
+
73
+ context 'as one ProtocolMessage' do
74
+ it 'retrieves limited history forwards with pagination' do
75
+ run_reactor(5) do
76
+ messages_sent.times do |index|
77
+ channel.publish('event', "history#{index}") do
78
+ check_limited_history :forwards if index == messages_sent - 1
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ it 'retrieves limited history backwards with pagination' do
85
+ run_reactor(5) do
86
+ messages_sent.times.to_a.reverse.each do |index|
87
+ channel.publish('event', "history#{index}") do
88
+ check_limited_history :backwards if index == messages_sent - 1
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ context 'in multiple ProtocolMessages' do
96
+ it 'retrieves limited history forwards with pagination' do
97
+ run_reactor(5) do
98
+ messages_sent.times do |index|
99
+ EventMachine.add_timer(index.to_f / 10) do
100
+ channel.publish('event', "history#{index}") do
101
+ check_limited_history :forwards if index == messages_sent - 1
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ it 'retrieves limited history backwards with pagination' do
109
+ run_reactor(5) do
110
+ messages_sent.times.to_a.reverse.each do |index|
111
+ EventMachine.add_timer((messages_sent - index).to_f / 10) do
112
+ channel.publish('event', "history#{index}") do
113
+ check_limited_history :backwards if index == 0
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ skip 'ensure REST history message IDs match ProtocolMessage wrapped message IDs via Realtime'
122
+ end
123
+ end
124
+ end
125
+ end
@@ -4,83 +4,155 @@ require 'securerandom'
4
4
  describe Ably::Realtime::Channel do
5
5
  include RSpec::EventMachine
6
6
 
7
- let(:client) do
8
- Ably::Realtime::Client.new(api_key: api_key, environment: environment)
9
- end
10
- let(:channel_name) { SecureRandom.hex(2) }
11
- let(:payload) { SecureRandom.hex(4) }
12
-
13
- it 'attachs to a channel' do
14
- attached = false
15
-
16
- run_reactor do
17
- channel = client.channel(channel_name)
18
- channel.attach
19
- channel.on(:attached) do
20
- expect(channel.state).to eq(:attached)
21
- attached = true
22
- stop_reactor
23
- end
24
- end
25
-
26
- expect(attached).to eql(true)
27
- end
7
+ [:msgpack, :json].each do |protocol|
8
+ context "over #{protocol}" do
9
+ let(:default_options) { { api_key: api_key, environment: environment, protocol: protocol } }
28
10
 
29
- it 'publishes 3 messages once attached' do
30
- messages = []
31
-
32
- run_reactor do
33
- channel = client.channel(channel_name)
34
- channel.attach
35
- channel.on(:attached) do
36
- 3.times { channel.publish('event', payload) }
11
+ let(:client) do
12
+ Ably::Realtime::Client.new(default_options)
37
13
  end
38
- channel.subscribe do |message|
39
- messages << message if message.data == payload
40
- stop_reactor if messages.length == 3
14
+ let(:channel_name) { SecureRandom.hex(2) }
15
+ let(:payload) { SecureRandom.hex(4) }
16
+ let(:channel) { client.channel(channel_name) }
17
+ let(:messages) { [] }
18
+
19
+ it 'attaches to a channel' do
20
+ run_reactor do
21
+ channel.attach
22
+ channel.on(:attached) do
23
+ expect(channel.state).to eq(:attached)
24
+ stop_reactor
25
+ end
26
+ end
41
27
  end
42
- end
43
28
 
44
- expect(messages.count).to eql(3)
45
- end
29
+ it 'attaches to a channel with a block' do
30
+ run_reactor do
31
+ channel.attach do
32
+ expect(channel.state).to eq(:attached)
33
+ stop_reactor
34
+ end
35
+ end
36
+ end
46
37
 
47
- it 'publishes 3 messages from queue before attached' do
48
- messages = []
38
+ it 'detaches from a channel with a block' do
39
+ run_reactor do
40
+ channel.attach do |chan|
41
+ chan.detach do |detached_chan|
42
+ expect(detached_chan.state).to eq(:detached)
43
+ stop_reactor
44
+ end
45
+ end
46
+ end
47
+ end
49
48
 
50
- run_reactor do
51
- channel = client.channel(channel_name)
52
- 3.times { channel.publish('event', SecureRandom.hex) }
53
- channel.subscribe do |message|
54
- messages << message if message.name == 'event'
55
- stop_reactor if messages.length == 3
49
+ it 'publishes 3 messages once attached' do
50
+ run_reactor do
51
+ channel.attach do
52
+ 3.times { channel.publish('event', payload) }
53
+ end
54
+ channel.subscribe do |message|
55
+ messages << message if message.data == payload
56
+ stop_reactor if messages.length == 3
57
+ end
58
+ end
59
+
60
+ expect(messages.count).to eql(3)
56
61
  end
57
- end
58
62
 
59
- expect(messages.count).to eql(3)
60
- end
63
+ it 'publishes 3 messages from queue before attached' do
64
+ run_reactor do
65
+ 3.times { channel.publish('event', SecureRandom.hex) }
66
+ channel.subscribe do |message|
67
+ messages << message if message.name == 'event'
68
+ stop_reactor if messages.length == 3
69
+ end
70
+ end
61
71
 
62
- it 'publishes 3 messages from queue before attached in a single protocol message' do
63
- messages = []
72
+ expect(messages.count).to eql(3)
73
+ end
64
74
 
65
- run_reactor do
66
- channel = client.channel(channel_name)
67
- 3.times { channel.publish('event', SecureRandom.hex) }
68
- channel.subscribe do |message|
69
- messages << message if message.name == 'event'
70
- stop_reactor if messages.length == 3
75
+ it 'publishes 3 messages from queue before attached in a single protocol message' do
76
+ run_reactor do
77
+ 3.times { channel.publish('event', SecureRandom.hex) }
78
+ channel.subscribe do |message|
79
+ messages << message if message.name == 'event'
80
+ stop_reactor if messages.length == 3
81
+ end
82
+ end
83
+
84
+ # All 3 messages should be batched into a single Protocol Message by the client library
85
+ # message.id = "{protocol_message.id}:{protocol_message_index}"
86
+
87
+ # Check that all messages share the same message_serial
88
+ message_id = messages.map { |msg| msg.id.split(':')[0] }
89
+ expect(message_id.uniq.count).to eql(1)
90
+
91
+ # Check that all messages use message index 0,1,2
92
+ message_indexes = messages.map { |msg| msg.id.split(':')[1] }
93
+ expect(message_indexes).to include("0", "1", "2")
71
94
  end
72
- end
73
95
 
74
- # All 3 messages should be batched into a single Protocol Message by the client library
75
- # message_id = "{connection_id}:{message_serial}:{protocol_message_index}"
96
+ it 'subscribes and unsubscribes' do
97
+ run_reactor do
98
+ channel.subscribe('click') do |message|
99
+ messages << message
100
+ end
101
+ channel.attach do
102
+ channel.unsubscribe('click')
103
+ channel.publish('click', 'data')
104
+ EventMachine.add_timer(2) do
105
+ stop_reactor
106
+ expect(messages.length).to eql(0)
107
+ end
108
+ end
109
+ end
110
+ end
76
111
 
77
- # Check that all messages share the same message_serial
78
- message_serials = messages.map { |msg| msg.message_id.split(':')[1] }
79
- expect(message_serials.uniq).to eql(["1"])
112
+ it 'subscribes and unsubscribes from multiple channels' do
113
+ run_reactor do
114
+ click_callback = -> (message) { messages << message }
115
+
116
+ channel.subscribe('click', &click_callback)
117
+ channel.subscribe('move', &click_callback)
118
+ channel.subscribe('press', &click_callback)
119
+
120
+ channel.attach do
121
+ channel.unsubscribe('click')
122
+ channel.unsubscribe('move', &click_callback)
123
+ channel.unsubscribe('press') { this_callback_is_not_subscribed_so_ignored }
124
+
125
+ channel.publish('click', 'data')
126
+ channel.publish('move', 'data')
127
+ channel.publish('press', 'data')
128
+
129
+ EventMachine.add_timer(2) do
130
+ stop_reactor
131
+ # Only the press subscribe callback should still be subscribed
132
+ expect(messages.length).to eql(1)
133
+ end
134
+ end
135
+ end
136
+ end
80
137
 
81
- # Check that all messages use message index 0,1,2
82
- message_indexes = messages.map { |msg| msg.message_id.split(':')[2] }
83
- expect(message_indexes).to include("0", "1", "2")
138
+ context 'attach failure' do
139
+ let(:restricted_client) do
140
+ Ably::Realtime::Client.new(default_options.merge(api_key: restricted_api_key))
141
+ end
142
+ let(:restricted_channel) { restricted_client.channel("cannot_subscribe") }
143
+
144
+ it 'triggers failed event' do
145
+ run_reactor do
146
+ restricted_channel.attach
147
+ restricted_channel.on(:failed) do |error|
148
+ expect(restricted_channel.state).to eq(:failed)
149
+ expect(error.status_code).to eq(401)
150
+ stop_reactor
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
84
156
  end
85
157
  end
86
158
 
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ably::Realtime::Connection do
4
+ include RSpec::EventMachine
5
+
6
+ [:msgpack, :json].each do |protocol|
7
+ context "over #{protocol}" do
8
+ let(:client) do
9
+ Ably::Realtime::Client.new(api_key: api_key, environment: environment, protocol: protocol)
10
+ end
11
+
12
+ subject { client.connection }
13
+
14
+ it 'connects automatically' do
15
+ run_reactor do
16
+ subject.on(:connected) do
17
+ expect(subject.state).to eq(:connected)
18
+ stop_reactor
19
+ end
20
+ end
21
+ end
22
+
23
+ context 'initialization phases' do
24
+ let(:phases) { [:initialized, :connecting, :connected] }
25
+ let(:events_triggered) { [] }
26
+
27
+ it 'are triggered in order' do
28
+ test_expectation = Proc.new do
29
+ expect(events_triggered).to eq(phases)
30
+ stop_reactor
31
+ end
32
+
33
+ run_reactor do
34
+ phases.each do |phase|
35
+ subject.on(phase) do
36
+ events_triggered << phase
37
+ test_expectation.call if events_triggered.length == phases.length
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ skip '#closed disconnects and closes the connection once timeout is reached'
45
+
46
+ specify '#closed disconnects and closes the connection gracefully' do
47
+ run_reactor(8) do
48
+ subject.close
49
+ subject.on(:closed) do
50
+ expect(subject.state).to eq(:closed)
51
+ stop_reactor
52
+ end
53
+ end
54
+ end
55
+
56
+ it 'receives a heart beat' do
57
+ run_reactor(20) do
58
+ subject.on(:connected) do
59
+ subject.__incoming_protocol_msgbus__.subscribe(:message) do |protocol_message|
60
+ if protocol_message.action == :heartbeat
61
+ expect(protocol_message.action).to eq(:heartbeat)
62
+ stop_reactor
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ skip 'connects, closes gracefully and reconnects on #connect'
70
+
71
+ it 'connects, closes then connection when timeout is reaached and reconnects on #connect' do
72
+ run_reactor(15) do
73
+ subject.connect do
74
+ connection_id = subject.id
75
+ subject.close do
76
+ subject.connect do
77
+ expect(subject.id).to_not eql(connection_id)
78
+ stop_reactor
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -4,80 +4,66 @@ require 'securerandom'
4
4
  describe 'Ably::Realtime::Channel Messages' do
5
5
  include RSpec::EventMachine
6
6
 
7
- let(:client) do
8
- Ably::Realtime::Client.new(options.merge(api_key: api_key, environment: environment))
9
- end
10
- let(:channel) { client.channel(channel_name) }
7
+ [:msgpack, :json].each do |protocol|
8
+ context "over #{protocol}" do
9
+ let(:default_options) { options.merge(api_key: api_key, environment: environment, protocol: protocol) }
10
+ let(:client) do
11
+ Ably::Realtime::Client.new(default_options)
12
+ end
13
+ let(:channel) { client.channel(channel_name) }
11
14
 
12
- let(:other_client) do
13
- Ably::Realtime::Client.new(options.merge(api_key: api_key, environment: environment))
14
- end
15
- let(:other_client_channel) { other_client.channel(channel_name) }
15
+ let(:other_client) do
16
+ Ably::Realtime::Client.new(default_options)
17
+ end
18
+ let(:other_client_channel) { other_client.channel(channel_name) }
16
19
 
17
- context 'using binary protocol' do
18
- skip 'sends a string message'
19
- skip 'sends a single message with an echo on another connection'
20
- skip 'all tests with multiple messages'
21
- end
20
+ let(:channel_name) { 'subscribe_send_text' }
21
+ let(:options) { { :protocol => :json } }
22
+ let(:payload) { 'Test message (subscribe_send_text)' }
22
23
 
23
- context 'using text protocol' do
24
- let(:channel_name) { 'subscribe_send_text' }
25
- let(:options) { { :protocol => :json } }
26
- let(:payload) { 'Test message (subscribe_send_text)' }
27
-
28
- it 'sends a string message' do
29
- run_reactor do
30
- channel.attach
31
- channel.on(:attached) do
32
- channel.publish('test_event', payload) do |message|
33
- expect(message.data).to eql(payload)
34
- stop_reactor
24
+ it 'sends a string message' do
25
+ run_reactor do
26
+ channel.attach
27
+ channel.on(:attached) do
28
+ channel.publish('test_event', payload) do |message|
29
+ expect(message.data).to eql(payload)
30
+ stop_reactor
31
+ end
35
32
  end
36
33
  end
37
34
  end
38
- end
39
35
 
40
- it 'sends a single message with an echo on another connection' do
41
- run_reactor do
42
- other_client_channel.attach
43
- other_client_channel.on(:attached) do
44
- channel.publish 'test_event', payload
45
- other_client_channel.subscribe('test_event') do |message|
46
- expect(message.data).to eql(payload)
47
- stop_reactor
36
+ it 'sends a single message with an echo on another connection' do
37
+ run_reactor do
38
+ other_client_channel.attach do
39
+ channel.publish 'test_event', payload
40
+ other_client_channel.subscribe('test_event') do |message|
41
+ expect(message.data).to eql(payload)
42
+ stop_reactor
43
+ end
48
44
  end
49
45
  end
50
46
  end
51
- end
52
47
 
53
- context 'with multiple messages' do
54
- let(:send_count) { 15 }
55
- let(:expected_echos) { send_count * 2 }
56
- let(:channel_name) { SecureRandom.hex }
57
- let(:echos) do
58
- { client: 0, other: 0 }
59
- end
60
- let(:callbacks) do
61
- { client: 0, other: 0 }
62
- end
48
+ context 'with echo_messages => false' do
49
+ let(:no_echo_client) do
50
+ Ably::Realtime::Client.new(default_options.merge(echo_messages: false))
51
+ end
52
+ let(:no_echo_channel) { no_echo_client.channel(channel_name) }
53
+
54
+ it 'sends a single message without a reply yet the messages is echoed on another normal connection' do
55
+ run_reactor do
56
+ channel.attach do |echo_channel|
57
+ no_echo_channel.attach do
58
+ no_echo_channel.publish 'test_event', payload
59
+
60
+ no_echo_channel.subscribe('test_event') do |message|
61
+ fail "Message should not have been echoed back"
62
+ end
63
63
 
64
- def expect_messages_to_be_echoed_on_both_connections
65
- {
66
- channel => :client,
67
- other_client_channel => :other
68
- }.each do |target_channel, echo_key|
69
- EventMachine.defer do
70
- target_channel.subscribe('test_event') do |message|
71
- echos[echo_key] += 1
72
-
73
- if echos[:client] == expected_echos && echos[:other] == expected_echos
74
- # Wait briefly before doing the final check in case additional messages received
75
- EventMachine.add_timer(0.5) do
76
- expect(echos[:client]).to eql(expected_echos)
77
- expect(echos[:other]).to eql(expected_echos)
78
- expect(callbacks[:client]).to eql(send_count)
79
- expect(callbacks[:other]).to eql(send_count)
80
- stop_reactor
64
+ echo_channel.subscribe('test_event') do |message|
65
+ expect(message.data).to eql(payload)
66
+ EventMachine.add_timer(1.5) { stop_reactor }
81
67
  end
82
68
  end
83
69
  end
@@ -85,48 +71,84 @@ describe 'Ably::Realtime::Channel Messages' do
85
71
  end
86
72
  end
87
73
 
88
- it 'sends and receives the messages on both opened connections (4 x send count due to local echos) and calls the callbacks' do
89
- run_reactor(10) do
90
- channel.attach
91
- other_client_channel.attach
74
+ context 'with multiple messages' do
75
+ let(:send_count) { 15 }
76
+ let(:expected_echos) { send_count * 2 }
77
+ let(:channel_name) { SecureRandom.hex }
78
+ let(:echos) do
79
+ { client: 0, other: 0 }
80
+ end
81
+ let(:callbacks) do
82
+ { client: 0, other: 0 }
83
+ end
92
84
 
93
- channel.on(:attached) do
94
- other_client_channel.on(:attached) do
95
- send_count.times do |index|
96
- channel.publish('test_event', "#{index}: #{payload}") do
97
- callbacks[:client] += 1
85
+ def expect_messages_to_be_echoed_on_both_connections
86
+ {
87
+ channel => :client,
88
+ other_client_channel => :other
89
+ }.each do |target_channel, echo_key|
90
+ EventMachine.defer do
91
+ target_channel.subscribe('test_event') do |message|
92
+ echos[echo_key] += 1
93
+
94
+ if echos[:client] == expected_echos && echos[:other] == expected_echos
95
+ # Wait briefly before doing the final check in case additional messages received
96
+ EventMachine.add_timer(0.5) do
97
+ expect(echos[:client]).to eql(expected_echos)
98
+ expect(echos[:other]).to eql(expected_echos)
99
+ expect(callbacks[:client]).to eql(send_count)
100
+ expect(callbacks[:other]).to eql(send_count)
101
+ stop_reactor
102
+ end
98
103
  end
99
- other_client_channel.publish('test_event', "#{index}: #{payload}") do
100
- callbacks[:other] += 1
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ it 'sends and receives the messages on both opened connections (4 x send count due to local echos) and calls the callbacks' do
110
+ run_reactor(10) do
111
+ channel.attach
112
+ other_client_channel.attach
113
+
114
+ channel.on(:attached) do
115
+ other_client_channel.on(:attached) do
116
+ send_count.times do |index|
117
+ channel.publish('test_event', "#{index}: #{payload}") do
118
+ callbacks[:client] += 1
119
+ end
120
+ other_client_channel.publish('test_event', "#{index}: #{payload}") do
121
+ callbacks[:other] += 1
122
+ end
101
123
  end
124
+ expect_messages_to_be_echoed_on_both_connections
102
125
  end
103
- expect_messages_to_be_echoed_on_both_connections
104
126
  end
105
127
  end
106
128
  end
107
129
  end
108
- end
109
130
 
110
- context 'without suitable publishing permissions' do
111
- let(:restricted_client) do
112
- Ably::Realtime::Client.new(options.merge(api_key: restricted_api_key, environment: environment))
113
- end
114
- let(:restricted_channel) { restricted_client.channel(channel_name) }
115
- let(:payload) { 'Test message without permission to publish' }
131
+ context 'without suitable publishing permissions' do
132
+ let(:restricted_client) do
133
+ Ably::Realtime::Client.new(options.merge(api_key: restricted_api_key, environment: environment, protocol: protocol))
134
+ end
135
+ let(:restricted_channel) { restricted_client.channel("cansubscribe:example") }
136
+ let(:payload) { 'Test message without permission to publish' }
116
137
 
117
- it 'calls the error callback' do
118
- run_reactor do
119
- restricted_channel.attach
120
- restricted_channel.on(:attached) do
121
- deferrable = restricted_channel.publish('test_event', payload)
122
- deferrable.errback do |message, error|
123
- expect(message.data).to eql(payload)
124
- expect(error.status).to eql(401)
125
- stop_reactor
126
- end
127
- deferrable.callback do |message|
128
- fail 'Success callback should not have been called'
129
- stop_reactor
138
+ it 'calls the error callback' do
139
+ run_reactor do
140
+ restricted_channel.attach
141
+ restricted_channel.on(:attached) do
142
+ deferrable = restricted_channel.publish('test_event', payload)
143
+ deferrable.errback do |message, error|
144
+ expect(message.data).to eql(payload)
145
+ expect(error.status).to eql(401)
146
+ stop_reactor
147
+ end
148
+ deferrable.callback do |message|
149
+ fail 'Success callback should not have been called'
150
+ stop_reactor
151
+ end
130
152
  end
131
153
  end
132
154
  end