celluloid_pubsub 1.0.2 → 2.0.0
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.
- checksums.yaml +5 -5
- data/.hound.yml +10 -0
- data/.reek +2 -0
- data/.rubocop.yml +107 -25
- data/.rubocop_todo.yml +7 -0
- data/.travis.yml +52 -11
- data/Appraisals +10 -2
- data/Gemfile +1 -6
- data/Rakefile +7 -2
- data/celluloid_pubsub.gemspec +15 -13
- data/examples/simple_test.rb +30 -8
- data/gemfiles/{celluloid_0.16.0.gemfile → cell_0.16.0.gemfile} +1 -1
- data/gemfiles/{celluloid_0.17.3.gemfile → cell_0.17.3.gemfile} +1 -1
- data/gemfiles/cell_0.17.4.gemfile +7 -0
- data/gemfiles/cell_0.18.0.gemfile +7 -0
- data/init.rb +1 -0
- data/lib/celluloid_pubsub.rb +2 -1
- data/lib/celluloid_pubsub/base_actor.rb +38 -1
- data/lib/celluloid_pubsub/client.rb +47 -7
- data/lib/celluloid_pubsub/client_connection.rb +57 -0
- data/lib/celluloid_pubsub/gem_version_parser.rb +2 -2
- data/lib/celluloid_pubsub/helper.rb +56 -8
- data/lib/celluloid_pubsub/initializers/reel_colors.rb +6 -1
- data/lib/celluloid_pubsub/reactor.rb +154 -22
- data/lib/celluloid_pubsub/registry.rb +28 -2
- data/lib/celluloid_pubsub/version.rb +20 -2
- data/lib/celluloid_pubsub/web_server.rb +84 -6
- data/spec/lib/celluloid_pubsub/base_actor_spec.rb +78 -0
- data/spec/lib/celluloid_pubsub/client_pubsub_spec.rb +168 -37
- data/spec/lib/celluloid_pubsub/reactor_spec.rb +373 -98
- data/spec/lib/celluloid_pubsub/registry_spec.rb +19 -1
- data/spec/lib/celluloid_pubsub/version_spec.rb +21 -0
- data/spec/lib/celluloid_pubsub/web_server_spec.rb +2 -2
- data/spec/spec_helper.rb +76 -11
- metadata +62 -81
@@ -0,0 +1,78 @@
|
|
1
|
+
# encoding:utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe CelluloidPubsub::BaseActor do
|
6
|
+
let(:actor) { TestActor.new }
|
7
|
+
subject { actor.own_self }
|
8
|
+
|
9
|
+
it 'returns the self' do
|
10
|
+
expect(actor.own_self.class.name).to eq('TestActor')
|
11
|
+
expect(actor.own_self).to_not respond_to(:mailbox)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'returns the actor' do
|
15
|
+
expect(actor.cell_actor).to respond_to(:mailbox)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns true if action subscribe' do
|
19
|
+
expect(subject.send(:action_subscribe?, 'subscribe')).to eq(true)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#parse_options' do
|
23
|
+
it 'returns empty hash for null value' do
|
24
|
+
expect(subject.send(:parse_options, nil)).to eq({})
|
25
|
+
end
|
26
|
+
it 'returns empty hash for null value' do
|
27
|
+
expect(subject.send(:parse_options, [{ a: 1 }, { b: 2 }])).to eq('b' => 2)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'booting up' do
|
32
|
+
it 'does not boot if already running' do
|
33
|
+
allow(Celluloid).to receive(:running?).and_return(true)
|
34
|
+
expect(Celluloid).to_not receive(:boot)
|
35
|
+
CelluloidPubsub::BaseActor.boot_up
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'boos if not running' do
|
39
|
+
allow(Celluloid).to receive(:running?).and_return(false)
|
40
|
+
expect(Celluloid).to receive(:boot)
|
41
|
+
CelluloidPubsub::BaseActor.boot_up
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'boos if running? returns error ' do
|
45
|
+
allow(Celluloid).to receive(:running?).and_raise(RuntimeError)
|
46
|
+
expect(Celluloid).to receive(:boot)
|
47
|
+
begin
|
48
|
+
CelluloidPubsub::BaseActor.boot_up
|
49
|
+
rescue RuntimeError => e
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'fetch_gem_version' do
|
55
|
+
let(:gem_name) { 'rails' }
|
56
|
+
let(:version) { '1.2.3' }
|
57
|
+
|
58
|
+
it 'returns the loaded gem version' do
|
59
|
+
expect(subject).to receive(:find_loaded_gem_property).with(gem_name).and_return(nil)
|
60
|
+
result = actor.send(:fetch_gem_version, gem_name)
|
61
|
+
expect(result).to eq(nil)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'returns the loaded gem version' do
|
65
|
+
expected = 1.2
|
66
|
+
expect(subject).to receive(:find_loaded_gem_property).with(gem_name).and_return(version)
|
67
|
+
expect(subject).to receive(:get_parsed_version).with(version).and_return(expected)
|
68
|
+
result = actor.send(:fetch_gem_version, gem_name)
|
69
|
+
expect(result).to eq(expected)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
describe 'filtered_error?' do
|
73
|
+
it 'filters the interrupt exception' do
|
74
|
+
error = Interrupt.new
|
75
|
+
expect(actor.send(:filtered_error?, error)).to eq(true)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -5,27 +5,29 @@ require 'spec_helper'
|
|
5
5
|
describe CelluloidPubsub::Client do
|
6
6
|
let(:blk) { proc { |a| puts a } }
|
7
7
|
let(:options) { {} }
|
8
|
-
let(:actor) {
|
9
|
-
let(:connection) {
|
8
|
+
let(:actor) { double('actor') }
|
9
|
+
let(:connection) { double('connection') }
|
10
10
|
let(:channel) { 'some_channel' }
|
11
|
+
let(:additional_options) { {} }
|
11
12
|
|
12
13
|
before(:each) do
|
13
|
-
CelluloidPubsub::Client.
|
14
|
-
CelluloidPubsub::Client.
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
14
|
+
allow_any_instance_of(CelluloidPubsub::Client).to receive(:supervise_actors).and_return(true)
|
15
|
+
allow_any_instance_of(CelluloidPubsub::Client).to receive(:connection).and_return(connection)
|
16
|
+
allow(actor).to receive(:async).and_return(actor)
|
17
|
+
allow(actor).to receive(:terminate).and_return(true)
|
18
|
+
allow(connection).to receive(:terminate).and_return(true)
|
19
|
+
allow(connection).to receive(:text).and_return(true)
|
20
|
+
allow(connection).to receive(:alive?).and_return(true)
|
21
|
+
@worker = CelluloidPubsub::Client.new(additional_options.merge(actor: actor, channel: channel, enable_debug: false))
|
22
|
+
@own_self = @worker.own_self
|
23
|
+
allow(@own_self).to receive(:debug).and_return(true)
|
24
|
+
allow(@own_self).to receive(:async).and_return(@worker)
|
23
25
|
end
|
24
26
|
|
25
27
|
describe '#initialize' do
|
26
28
|
it 'creates a object' do
|
27
|
-
expect(@
|
28
|
-
expect(@
|
29
|
+
expect(@own_self.channel).to eq channel
|
30
|
+
expect(@own_self.actor).to eq actor
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
@@ -63,30 +65,29 @@ describe CelluloidPubsub::Client do
|
|
63
65
|
describe '#subscribe' do
|
64
66
|
let(:channel) { 'some_channel' }
|
65
67
|
it 'chats with the server' do
|
66
|
-
@
|
68
|
+
expect(@own_self).to receive(:chat).with('client_action' => 'subscribe', 'channel' => channel)
|
67
69
|
@worker.subscribe(channel)
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
71
73
|
describe '#succesfull_subscription?' do
|
72
|
-
let(:message) {
|
73
|
-
let(:action) {
|
74
|
+
let(:message) { double(present?: true) }
|
75
|
+
let(:action) { double }
|
74
76
|
|
75
77
|
before(:each) do
|
76
|
-
message.
|
77
|
-
message.stubs(:[]).with('client_action').returns('successful_subscription')
|
78
|
+
allow(message).to receive(:[]).with('client_action').and_return('successful_subscription')
|
78
79
|
end
|
79
80
|
|
80
81
|
it 'checks the message and returns true' do
|
81
|
-
message.
|
82
|
-
message.
|
82
|
+
expect(message).to receive(:is_a?).with(Hash).and_return(true)
|
83
|
+
allow(message).to receive(:[]).with('client_action').and_return('successful_subscription')
|
83
84
|
actual = @worker.succesfull_subscription?(message)
|
84
85
|
expect(actual).to eq(true)
|
85
86
|
end
|
86
87
|
|
87
88
|
it 'checks the message and returns false' do
|
88
|
-
message.
|
89
|
-
message.
|
89
|
+
expect(message).to receive(:is_a?).with(Hash).and_return(true)
|
90
|
+
allow(message).to receive(:[]).with('client_action').and_return('something_else')
|
90
91
|
actual = @worker.succesfull_subscription?(message)
|
91
92
|
expect(actual).to eq(false)
|
92
93
|
end
|
@@ -96,16 +97,59 @@ describe CelluloidPubsub::Client do
|
|
96
97
|
let(:channel) { 'some_channel' }
|
97
98
|
let(:data) { 'some_message' }
|
98
99
|
it 'chats with the server' do
|
99
|
-
@
|
100
|
+
expect(@own_self).to receive(:send_action).with('publish', channel, data)
|
100
101
|
@worker.publish(channel, data)
|
101
102
|
end
|
102
103
|
end
|
103
104
|
|
105
|
+
describe '#unsubscribe' do
|
106
|
+
let(:channel) { 'some_channel' }
|
107
|
+
it 'chats with the server' do
|
108
|
+
expect(@own_self).to receive(:send_action).with('unsubscribe', channel)
|
109
|
+
@worker.unsubscribe(channel)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#unsubscribe_clients' do
|
114
|
+
let(:channel) { 'some_channel' }
|
115
|
+
it 'chats with the server' do
|
116
|
+
expect(@own_self).to receive(:send_action).with('unsubscribe_clients', channel)
|
117
|
+
@worker.unsubscribe_clients(channel)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe '#unsubscribe_all' do
|
122
|
+
it 'chats with the server' do
|
123
|
+
expect(@own_self).to receive(:send_action).with('unsubscribe_all')
|
124
|
+
@worker.unsubscribe_all
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe '#supervise_actors' do
|
129
|
+
before do
|
130
|
+
allow_any_instance_of(CelluloidPubsub::Client).to receive(:supervise_actors).and_call_original
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'supervises the actor' do
|
134
|
+
allow(actor).to receive(:respond_to?).with(:link).and_return(true)
|
135
|
+
expect(actor).to receive(:link).with(@worker)
|
136
|
+
expect(@worker).to receive(:link).with(connection)
|
137
|
+
@worker.supervise_actors
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'does not link the actor if not possible' do
|
141
|
+
allow(actor).to receive(:respond_to?).with(:link).and_return(false)
|
142
|
+
expect(actor).to_not receive(:link).with(@worker)
|
143
|
+
expect(@worker).to receive(:link).with(connection)
|
144
|
+
@worker.supervise_actors
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
104
148
|
describe '#on_open' do
|
105
149
|
let(:channel) { 'some_channel' }
|
106
150
|
let(:data) { 'some_message' }
|
107
151
|
it 'chats with the server' do
|
108
|
-
@
|
152
|
+
expect(@own_self).to receive(:subscribe).with(channel)
|
109
153
|
@worker.on_open
|
110
154
|
end
|
111
155
|
end
|
@@ -114,17 +158,17 @@ describe CelluloidPubsub::Client do
|
|
114
158
|
let(:channel) { 'some_channel' }
|
115
159
|
let(:data) { 'some_message' }
|
116
160
|
it 'chats with the server' do
|
117
|
-
JSON.
|
118
|
-
|
119
|
-
@
|
120
|
-
@
|
161
|
+
expect(JSON).to receive(:parse).with(data).and_return(data)
|
162
|
+
expect(@own_self.actor).to receive(:respond_to?).and_return(true)
|
163
|
+
expect(@own_self.actor).to receive(:async).and_return(actor)
|
164
|
+
expect(@own_self.actor).to receive(:on_message).with(data)
|
121
165
|
@worker.on_message(data)
|
122
166
|
end
|
123
167
|
|
124
168
|
it 'chats with the server without async' do
|
125
|
-
JSON.
|
126
|
-
|
127
|
-
|
169
|
+
expect(JSON).to receive(:parse).with(data).and_return(data)
|
170
|
+
expect(@own_self.actor).to receive(:respond_to?).and_return(false)
|
171
|
+
expect(@own_self.actor).to receive(:on_message).with(data)
|
128
172
|
@worker.on_message(data)
|
129
173
|
end
|
130
174
|
end
|
@@ -135,7 +179,13 @@ describe CelluloidPubsub::Client do
|
|
135
179
|
let(:reason) { 'some_reason' }
|
136
180
|
|
137
181
|
it 'chats with the server' do
|
138
|
-
actor.
|
182
|
+
expect(actor).to receive(:on_close).with(code, reason).and_return(true)
|
183
|
+
@worker.on_close(code, reason)
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'chats with the server' do
|
187
|
+
expect(actor).to receive(:respond_to?).with(:async).and_return(false)
|
188
|
+
expect(actor).to receive(:on_close).with(code, reason).and_return(true)
|
139
189
|
@worker.on_close(code, reason)
|
140
190
|
end
|
141
191
|
end
|
@@ -145,15 +195,96 @@ describe CelluloidPubsub::Client do
|
|
145
195
|
let(:data) { 'some_message' }
|
146
196
|
let(:data_hash) { { a: 'some mesage ' } }
|
147
197
|
let(:json) { { action: 'message', message: data } }
|
148
|
-
it 'chats
|
149
|
-
JSON.
|
150
|
-
connection.
|
198
|
+
it 'chats without hash' do
|
199
|
+
expect(JSON).to receive(:dump).with(json).and_return(json)
|
200
|
+
expect(connection).to receive(:text).with(json)
|
151
201
|
@worker.send(:chat, data)
|
152
202
|
end
|
153
203
|
|
154
204
|
it 'chats with a hash' do
|
155
|
-
connection.
|
205
|
+
expect(connection).to receive(:text).with(data_hash.to_json)
|
156
206
|
@worker.send(:chat, data_hash)
|
157
207
|
end
|
158
208
|
end
|
209
|
+
|
210
|
+
describe 'shutting_down?' do
|
211
|
+
it 'returns false by default' do
|
212
|
+
expect(@worker.shutting_down?).to eq(false)
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'returns true' do
|
216
|
+
allow(@own_self).to receive(:terminate).and_return(true)
|
217
|
+
expect { @worker.shutdown }.to change(@worker, :shutting_down?).from(false).to(true)
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'returns true when actor dies' do
|
221
|
+
allow(@own_self).to receive(:shutdown).and_return(true)
|
222
|
+
allow(@worker).to receive(:hostname).and_raise(RuntimeError)
|
223
|
+
begin
|
224
|
+
expect { @worker.hostname }.to change(@worker, :shutting_down?).from(false).to(true)
|
225
|
+
rescue RuntimeError => e
|
226
|
+
# do nothing
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
describe 'log_file_path' do
|
232
|
+
it 'returns nil by default' do
|
233
|
+
expect(@worker.log_file_path).to eq(nil)
|
234
|
+
end
|
235
|
+
|
236
|
+
context 'when log file path is defined' do
|
237
|
+
let(:path) { '/some-path-here' }
|
238
|
+
let(:additional_options) { { log_file_path: path } }
|
239
|
+
|
240
|
+
it 'returns the path' do
|
241
|
+
expect(@worker.log_file_path).to eq(path)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe 'log_level' do
|
247
|
+
it 'returns info by default' do
|
248
|
+
expect(@worker.log_level).to eq(::Logger::Severity::INFO)
|
249
|
+
end
|
250
|
+
|
251
|
+
context 'when log level is defined' do
|
252
|
+
let(:level) { Logger::Severity::DEBUG }
|
253
|
+
let(:additional_options) { { log_level: level } }
|
254
|
+
|
255
|
+
it 'returns the path' do
|
256
|
+
expect(@worker.log_level).to eq(level)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
describe 'path' do
|
262
|
+
it 'returns the path of the server' do
|
263
|
+
expect(@worker.path).to eq(CelluloidPubsub::WebServer::PATH)
|
264
|
+
end
|
265
|
+
|
266
|
+
context 'when path is defined' do
|
267
|
+
let(:path) { '/demo' }
|
268
|
+
let(:additional_options) { { path: path } }
|
269
|
+
|
270
|
+
it 'returns the path' do
|
271
|
+
expect(@worker.path).to eq(path)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
describe 'connection' do
|
277
|
+
it 'returns the path of the server' do
|
278
|
+
allow_any_instance_of(CelluloidPubsub::Client).to receive(:connection).and_call_original
|
279
|
+
expect(CelluloidPubsub::ClientConnection).to receive(:new).with("ws://#{@worker.hostname}:#{@worker.port}#{@worker.path}", @worker).and_return(connection)
|
280
|
+
result = @worker.connection
|
281
|
+
expect(result).to eq(connection)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
describe 'actor_died' do
|
286
|
+
it 'sets the shutting down' do
|
287
|
+
expect { @worker.send(:actor_died, @worker, nil) }.to change(@worker, :shutting_down?).from(false).to(true)
|
288
|
+
end
|
289
|
+
end
|
159
290
|
end
|
@@ -3,39 +3,62 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe CelluloidPubsub::Reactor do
|
6
|
-
let(:websocket)
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
let(:websocket) do
|
7
|
+
double(
|
8
|
+
'websocket',
|
9
|
+
url: nil,
|
10
|
+
read: nil,
|
11
|
+
close: nil,
|
12
|
+
closed?: false,
|
13
|
+
present?: false
|
14
|
+
)
|
15
|
+
end
|
16
|
+
let(:server_options) { {}.with_indifferent_access }
|
17
|
+
let(:server) do
|
18
|
+
double(
|
19
|
+
'server',
|
20
|
+
debug_enabled?: false,
|
21
|
+
adapter: CelluloidPubsub::WebServer::CLASSIC_ADAPTER,
|
22
|
+
server_options: server_options,
|
23
|
+
dead?: false,
|
24
|
+
subscribers: {},
|
25
|
+
handle_dispatched_message: nil,
|
26
|
+
mutex: mutex,
|
27
|
+
timers_mutex: timers_mutex,
|
28
|
+
reactors: []
|
29
|
+
)
|
30
|
+
end
|
31
|
+
let(:mutex) { double('mutex') }
|
32
|
+
let(:synchronizer) { double('synchronizer') }
|
33
|
+
let(:timers_mutex) { double('timers_mutex') }
|
34
|
+
let(:timers_synchronizer) { double('timers_synchronizer') }
|
10
35
|
|
11
36
|
before(:each) do
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
subject.work(websocket, server)
|
26
|
-
subject.stubs(:unsubscribe_from_channel).returns(true)
|
27
|
-
server.stubs(:mutex).returns(mutex)
|
28
|
-
mutex.stubs(:synchronize).yields(server)
|
29
|
-
Celluloid::Actor.stubs(:kill).returns(true)
|
37
|
+
allow(server).to receive(:async).and_return(server)
|
38
|
+
allow(actor).to receive(:async).and_return(actor)
|
39
|
+
allow(actor).to receive(:inspect).and_return(actor)
|
40
|
+
allow(actor).to receive(:run)
|
41
|
+
allow(actor).to receive(:unsubscribe_from_channel).and_return(true)
|
42
|
+
allow(mutex).to receive(:synchronize).and_yield
|
43
|
+
allow(timers_mutex).to receive(:synchronize).and_yield
|
44
|
+
allow(Celluloid::Actor).to receive(:kill).and_return(true)
|
45
|
+
allow_any_instance_of(CelluloidPubsub::Reactor).to receive(:shutdown).and_return(true)
|
46
|
+
end
|
47
|
+
|
48
|
+
after(:each) do
|
49
|
+
Celluloid.shutdown
|
30
50
|
end
|
31
51
|
|
52
|
+
let(:actor) { CelluloidPubsub::Reactor.new.initialize_data(websocket, server) }
|
53
|
+
subject { actor.own_self }
|
54
|
+
|
32
55
|
describe '#work' do
|
33
56
|
it 'works ' do
|
34
|
-
|
35
|
-
|
36
|
-
expect(
|
37
|
-
expect(
|
38
|
-
expect(
|
57
|
+
expect(actor).to receive(:run)
|
58
|
+
actor.work(websocket, server)
|
59
|
+
expect(actor.websocket).to eq(websocket)
|
60
|
+
expect(actor.server).to eq(server)
|
61
|
+
expect(actor.channels).to eq([])
|
39
62
|
end
|
40
63
|
end
|
41
64
|
|
@@ -43,10 +66,10 @@ describe CelluloidPubsub::Reactor do
|
|
43
66
|
# let(:data) { 'some message' }
|
44
67
|
#
|
45
68
|
# it 'works ' do
|
46
|
-
#
|
47
|
-
# websocket.
|
48
|
-
# subject.
|
49
|
-
#
|
69
|
+
# actor.unstub(:run)
|
70
|
+
# allow(websocket).to receive(:read).and_return(data)
|
71
|
+
# expect(subject).to receive(:handle_websocket_message).with(data)
|
72
|
+
# actor.run
|
50
73
|
# end
|
51
74
|
# end
|
52
75
|
|
@@ -55,14 +78,14 @@ describe CelluloidPubsub::Reactor do
|
|
55
78
|
let(:expected) { data.to_json }
|
56
79
|
|
57
80
|
it 'works with hash ' do
|
58
|
-
JSON.
|
59
|
-
actual =
|
81
|
+
expect(JSON).to receive(:parse).with(data).and_return(expected)
|
82
|
+
actual = actor.parse_json_data(data)
|
60
83
|
expect(actual).to eq expected
|
61
84
|
end
|
62
85
|
|
63
86
|
it 'works with exception parsing ' do
|
64
|
-
JSON.
|
65
|
-
actual =
|
87
|
+
expect(JSON).to receive(:parse).with(data).and_raise(StandardError)
|
88
|
+
actual = actor.parse_json_data(data)
|
66
89
|
expect(actual).to eq data
|
67
90
|
end
|
68
91
|
end
|
@@ -72,96 +95,91 @@ describe CelluloidPubsub::Reactor do
|
|
72
95
|
let(:json_data) { { a: 'b' } }
|
73
96
|
|
74
97
|
it 'handle_websocket_message' do
|
75
|
-
subject.
|
76
|
-
subject.
|
77
|
-
|
98
|
+
expect(subject).to receive(:parse_json_data).with(data).and_return(json_data)
|
99
|
+
expect(subject).to receive(:handle_parsed_websocket_message).with(json_data)
|
100
|
+
actor.handle_websocket_message(data)
|
78
101
|
end
|
79
102
|
end
|
80
103
|
|
81
104
|
describe '#handle_parsed_websocket_message' do
|
82
105
|
it 'handle_websocket_message with a hash' do
|
83
|
-
data = { 'client_action' => 'subscribe' }
|
84
|
-
data.
|
85
|
-
subject.
|
86
|
-
|
106
|
+
data = { 'client_action' => 'subscribe', 'channel' => 'test' }
|
107
|
+
expect(data).to receive(:stringify_keys).and_return(data)
|
108
|
+
expect(subject).to receive(:delegate_action).with(data).and_return(true)
|
109
|
+
actor.handle_parsed_websocket_message(data)
|
87
110
|
end
|
88
111
|
|
89
112
|
it 'handle_websocket_message with something else than a hash' do
|
90
|
-
data = { 'message'=> 'some message' }
|
91
|
-
subject.
|
92
|
-
|
113
|
+
data = { 'message' => 'some message' }
|
114
|
+
expect(subject).to receive(:handle_unknown_action).with(data['channel'], data).and_return(true)
|
115
|
+
actor.handle_parsed_websocket_message(data)
|
93
116
|
end
|
94
117
|
end
|
95
118
|
|
96
119
|
describe '#delegate_action' do
|
97
|
-
|
98
120
|
before(:each) do
|
99
|
-
subject.
|
100
|
-
subject.
|
121
|
+
allow(subject).to receive(:unsubscribe_clients).and_return(true)
|
122
|
+
allow(subject).to receive(:shutdown).and_return(true)
|
101
123
|
end
|
102
124
|
|
103
125
|
it 'unsubscribes all' do
|
104
126
|
data = { 'client_action' => 'unsubscribe_all', 'channel' => '' }
|
105
|
-
subject.
|
106
|
-
|
127
|
+
expect(subject).to receive(:send).with(data['client_action'], data['channel'], data).and_return('bla')
|
128
|
+
actor.delegate_action(data)
|
107
129
|
end
|
108
130
|
|
109
131
|
it 'unsubscribes all' do
|
110
132
|
data = { 'client_action' => 'unsubscribe', 'channel' => 'some channel' }
|
111
|
-
subject.
|
112
|
-
|
133
|
+
expect(subject).to receive(:send).with(data['client_action'], data['channel'], data)
|
134
|
+
actor.delegate_action(data)
|
113
135
|
end
|
114
|
-
#
|
115
136
|
it 'subscribes to channell' do
|
116
137
|
data = { 'client_action' => 'subscribe', 'channel' => 'some channel' }
|
117
|
-
subject.
|
118
|
-
|
138
|
+
expect(subject).to receive(:send).with(data['client_action'], data['channel'], data)
|
139
|
+
actor.delegate_action(data)
|
119
140
|
end
|
120
141
|
|
121
142
|
it 'publish' do
|
122
143
|
data = { 'client_action' => 'publish', 'channel' => 'some channel', 'data' => 'some data' }
|
123
|
-
subject.
|
124
|
-
|
144
|
+
expect(subject).to receive(:send).with(data['client_action'], data['channel'], data)
|
145
|
+
actor.delegate_action(data)
|
125
146
|
end
|
126
147
|
end
|
127
|
-
#
|
128
148
|
describe '#handle_unknown_action' do
|
129
149
|
it 'handles unknown' do
|
130
150
|
data = 'some data'
|
131
|
-
channel =
|
132
|
-
server.
|
133
|
-
|
151
|
+
channel = 'some_channel'
|
152
|
+
expect(server).to receive(:handle_dispatched_message)
|
153
|
+
actor.handle_unknown_action(channel, data)
|
134
154
|
end
|
135
155
|
end
|
136
156
|
|
137
157
|
describe '#unsubscribe_client' do
|
138
158
|
let(:channel) { 'some channel' }
|
139
|
-
let(:data) { {'client_action' => 'unsubscribe', 'channel' => channel } }
|
159
|
+
let(:data) { { 'client_action' => 'unsubscribe', 'channel' => channel } }
|
140
160
|
it 'returns nil' do
|
141
|
-
act =
|
161
|
+
act = actor.unsubscribe('', data)
|
142
162
|
expect(act).to eq(nil)
|
143
163
|
end
|
144
164
|
|
145
165
|
it 'unsubscribes' do
|
146
|
-
channel.
|
147
|
-
subject.
|
148
|
-
subject.
|
149
|
-
act =
|
166
|
+
allow(channel).to receive(:present?).and_return(true)
|
167
|
+
expect(subject).to receive(:forget_channel).with(channel)
|
168
|
+
expect(subject).to receive(:delete_server_subscribers).with(channel)
|
169
|
+
act = actor.unsubscribe(channel, data)
|
150
170
|
expect(act).to eq(nil)
|
151
171
|
end
|
152
|
-
|
153
|
-
|
154
172
|
end
|
155
173
|
|
156
174
|
describe '#delete_server_subscribers' do
|
157
175
|
let(:channel) { 'some channel' }
|
158
176
|
|
159
177
|
before(:each) do
|
160
|
-
server.
|
178
|
+
allow(server).to receive(:subscribers).and_return(channel.to_s => [{ reactor: actor }])
|
161
179
|
end
|
162
180
|
|
163
181
|
it 'unsubscribes' do
|
164
|
-
act =
|
182
|
+
act = actor.delete_server_subscribers(channel)
|
165
183
|
expect(server.subscribers[channel]).to eq([])
|
166
184
|
end
|
167
185
|
end
|
@@ -170,25 +188,29 @@ describe CelluloidPubsub::Reactor do
|
|
170
188
|
let(:channel) { 'some channel' }
|
171
189
|
|
172
190
|
it 'unsubscribes' do
|
173
|
-
|
174
|
-
|
175
|
-
act =
|
191
|
+
allow(actor.channels).to receive(:blank?).and_return(true)
|
192
|
+
expect(actor.websocket).to receive(:close)
|
193
|
+
act = actor.forget_channel(channel)
|
176
194
|
expect(act).to eq(nil)
|
177
195
|
end
|
178
196
|
|
179
197
|
it 'unsubscribes' do
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
198
|
+
allow(actor.channels).to receive(:blank?).and_return(false)
|
199
|
+
expect(actor.channels).to receive(:delete).with(channel)
|
200
|
+
# allow(server).to receive(:subscribers).and_return("#{channel}" => [{ reactor: subject }])
|
201
|
+
actor.forget_channel(channel)
|
202
|
+
# expect(server.subscribers[channel]).to eq([])
|
185
203
|
end
|
186
204
|
end
|
187
205
|
|
188
206
|
describe '#shutdown' do
|
207
|
+
before(:each) do
|
208
|
+
allow_any_instance_of(CelluloidPubsub::Reactor).to receive(:shutdown).and_call_original
|
209
|
+
end
|
210
|
+
|
189
211
|
it 'shutdowns' do
|
190
|
-
subject.
|
191
|
-
|
212
|
+
expect(subject).to receive(:terminate).at_least(:once)
|
213
|
+
actor.shutdown
|
192
214
|
end
|
193
215
|
end
|
194
216
|
|
@@ -197,22 +219,22 @@ describe CelluloidPubsub::Reactor do
|
|
197
219
|
let(:message) { { a: 'b' } }
|
198
220
|
|
199
221
|
it 'subscribes ' do
|
200
|
-
act =
|
222
|
+
act = actor.subscribe('', message)
|
201
223
|
expect(act).to eq(nil)
|
202
224
|
end
|
203
225
|
|
204
226
|
it 'subscribes ' do
|
205
|
-
subject.
|
206
|
-
server.
|
207
|
-
|
208
|
-
|
227
|
+
allow(subject).to receive(:add_subscriber_to_channel).with(channel, message)
|
228
|
+
allow(server).to receive(:redis_enabled?).and_return(false)
|
229
|
+
expect(actor.websocket).to receive(:<<).with(message.merge('client_action' => 'successful_subscription', 'channel' => channel).to_json)
|
230
|
+
actor.subscribe(channel, message)
|
209
231
|
end
|
210
232
|
|
211
233
|
# it 'raises error' do
|
212
|
-
# subject.
|
234
|
+
# subject).to receive(:add_subscriber_to_channel).raises(StandardError)
|
213
235
|
#
|
214
236
|
# expect do
|
215
|
-
#
|
237
|
+
# actor.start_subscriber(channel, message)
|
216
238
|
# end.to raise_error(StandardError) { |e|
|
217
239
|
# expect(e.message).to include(channel)
|
218
240
|
# }
|
@@ -222,15 +244,15 @@ describe CelluloidPubsub::Reactor do
|
|
222
244
|
describe '#add_subscriber_to_channel' do
|
223
245
|
let(:channel) { 'some channel' }
|
224
246
|
let(:message) { { a: 'b' } }
|
225
|
-
let(:subscribers) {
|
247
|
+
let(:subscribers) { double }
|
226
248
|
|
227
249
|
it 'adds subscribed' do
|
228
|
-
CelluloidPubsub::Registry.channels.
|
229
|
-
CelluloidPubsub::Registry.channels.
|
230
|
-
subject.
|
231
|
-
subscribers.
|
232
|
-
|
233
|
-
expect(
|
250
|
+
allow(CelluloidPubsub::Registry.channels).to receive(:include?).with(channel).and_return(false)
|
251
|
+
expect(CelluloidPubsub::Registry.channels).to receive(:<<).with(channel)
|
252
|
+
expect(subject).to receive(:channel_subscribers).with(channel).and_return(subscribers)
|
253
|
+
expect(subscribers).to receive(:push).with(reactor: actor, message: message)
|
254
|
+
actor.add_subscriber_to_channel(channel, message)
|
255
|
+
expect(actor.channels).to include(channel)
|
234
256
|
end
|
235
257
|
end
|
236
258
|
|
@@ -239,9 +261,262 @@ describe CelluloidPubsub::Reactor do
|
|
239
261
|
let(:message) { { a: 'b' } }
|
240
262
|
|
241
263
|
it 'adds subscribed' do
|
242
|
-
CelluloidPubsub::Registry.
|
243
|
-
subject.
|
244
|
-
|
264
|
+
allow(CelluloidPubsub::Registry).to receive(:channels).and_return([channel])
|
265
|
+
expect(subject).to receive(:unsubscribe_from_channel).with(channel).and_return(true)
|
266
|
+
actor.unsubscribe_all(channel, message)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
describe 'log_file_path' do
|
271
|
+
it 'returns nil by default' do
|
272
|
+
expect(actor.log_file_path).to eq(nil)
|
273
|
+
end
|
274
|
+
|
275
|
+
context 'when log file path is defined' do
|
276
|
+
let(:path) { '/some-path-here' }
|
277
|
+
let(:server_options) { { log_file_path: path }.with_indifferent_access }
|
278
|
+
|
279
|
+
it 'returns the path' do
|
280
|
+
expect(actor.log_file_path).to eq(path)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
describe 'log_level' do
|
286
|
+
it 'returns info by default' do
|
287
|
+
expect(actor.log_level).to eq(::Logger::Severity::INFO)
|
288
|
+
end
|
289
|
+
|
290
|
+
context 'when log level is defined' do
|
291
|
+
let(:level) { Logger::Severity::DEBUG }
|
292
|
+
let(:server_options) { { log_level: level }.with_indifferent_access }
|
293
|
+
|
294
|
+
it 'returns the path' do
|
295
|
+
expect(actor.log_level).to eq(level)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
describe 'adapter options' do
|
301
|
+
it 'returns info by default' do
|
302
|
+
expect(actor.adapter_options).to eq({})
|
303
|
+
end
|
304
|
+
|
305
|
+
context 'when log level is defined' do
|
306
|
+
let(:adapter_options) { { something: :here, another: { key: :value } } }
|
307
|
+
let(:server_options) { { adapter_options: adapter_options }.with_indifferent_access }
|
308
|
+
|
309
|
+
it 'returns the path' do
|
310
|
+
expect(actor.adapter_options).to eq(adapter_options.deep_stringify_keys)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
describe 'shutting_down?' do
|
316
|
+
before(:each) do
|
317
|
+
allow_any_instance_of(CelluloidPubsub::Reactor).to receive(:shutdown).and_call_original
|
318
|
+
end
|
319
|
+
|
320
|
+
it 'returns false by default' do
|
321
|
+
expect(actor.shutting_down?).to eq(false)
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'returns true' do
|
325
|
+
allow(subject).to receive(:terminate).and_return(true)
|
326
|
+
expect { actor.shutdown }.to change(actor, :shutting_down?).from(false).to(true)
|
327
|
+
end
|
328
|
+
|
329
|
+
it 'returns true when actor dies' do
|
330
|
+
allow(subject).to receive(:shutdown).and_return(true)
|
331
|
+
allow(actor).to receive(:log_level).and_raise(RuntimeError)
|
332
|
+
begin
|
333
|
+
expect { actor.log_level }.to change(actor, :shutting_down?).from(false).to(true)
|
334
|
+
rescue RuntimeError => e
|
335
|
+
# do nothing
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
describe 'try_read_websocket' do
|
341
|
+
it 'returns nil if socket closed' do
|
342
|
+
allow(websocket).to receive(:closed?).and_return(true)
|
343
|
+
expect(websocket).to_not receive(:read)
|
344
|
+
result = actor.try_read_websocket
|
345
|
+
expect(result).to eq(nil)
|
346
|
+
end
|
347
|
+
|
348
|
+
it 'reads the socket' do
|
349
|
+
expected = 'something'
|
350
|
+
allow(websocket).to receive(:closed?).and_return(false)
|
351
|
+
expect(websocket).to receive(:read).and_return(expected)
|
352
|
+
result = actor.try_read_websocket
|
353
|
+
expect(result).to eq(expected)
|
354
|
+
end
|
355
|
+
|
356
|
+
it 'returns nil if socket closed' do
|
357
|
+
allow(websocket).to receive(:closed?).and_return(false)
|
358
|
+
expect(websocket).to receive(:read).and_raise(StandardError)
|
359
|
+
result = actor.try_read_websocket
|
360
|
+
expect(result).to eq(nil)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
describe 'send_unpublshed' do
|
365
|
+
let(:channel) { 'test' }
|
366
|
+
let(:messages) { [1, 2, 3] }
|
367
|
+
|
368
|
+
it 'does not send if no messages' do
|
369
|
+
allow(subject).to receive(:unpublished_messages).with(channel).and_return(nil)
|
370
|
+
expect(websocket).to_not receive(:<<)
|
371
|
+
subject.send_unpublished(channel)
|
372
|
+
end
|
373
|
+
|
374
|
+
it 'sends the messages' do
|
375
|
+
allow(subject).to receive(:unpublished_messages).with(channel).and_return(messages)
|
376
|
+
messages.each do |msg|
|
377
|
+
expect(websocket).to receive(:<<).ordered.with(msg.to_json)
|
378
|
+
end
|
379
|
+
subject.send_unpublished(channel)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
describe 'clears the messages' do
|
384
|
+
let(:channel) { 'test' }
|
385
|
+
let(:messages) { [1, 2, 3] }
|
386
|
+
|
387
|
+
before do
|
388
|
+
CelluloidPubsub::Registry.messages[channel] = messages
|
389
|
+
end
|
390
|
+
|
391
|
+
after do
|
392
|
+
CelluloidPubsub::Registry.messages = {}
|
393
|
+
end
|
394
|
+
|
395
|
+
it 'clears the messages' do
|
396
|
+
actor.clear_unpublished_messages(channel)
|
397
|
+
expect(CelluloidPubsub::Registry.messages).to eq(channel => [])
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
describe 'unpublished_messages' do
|
402
|
+
let(:channel) { 'test' }
|
403
|
+
let(:messages) { [1, 2, 3] }
|
404
|
+
|
405
|
+
before do
|
406
|
+
CelluloidPubsub::Registry.messages[channel] = messages
|
407
|
+
end
|
408
|
+
|
409
|
+
after do
|
410
|
+
CelluloidPubsub::Registry.messages = {}
|
411
|
+
end
|
412
|
+
|
413
|
+
it 'retrieves the messages' do
|
414
|
+
result = actor.unpublished_messages(channel)
|
415
|
+
expect(result).to eq(messages)
|
416
|
+
end
|
417
|
+
|
418
|
+
it 'returns empty array for non existing channel' do
|
419
|
+
result = actor.unpublished_messages('something-here')
|
420
|
+
expect(result).to eq([])
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
describe 'subscribers' do
|
425
|
+
let(:channel) { 'test' }
|
426
|
+
before do
|
427
|
+
server.subscribers[channel] = [{ reactor: actor }]
|
428
|
+
end
|
429
|
+
|
430
|
+
it 'returns empty array' do
|
431
|
+
result = actor.channel_subscribers('some-channel')
|
432
|
+
expect(result).to eq([])
|
433
|
+
end
|
434
|
+
|
435
|
+
it 'returns the subscribers' do
|
436
|
+
result = actor.channel_subscribers(channel)
|
437
|
+
expect(result).to eq([{ reactor: actor }])
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
describe 'publish' do
|
442
|
+
let(:channel) { 'test' }
|
443
|
+
let(:data) { { 'client_action' => 'publish', 'channel' => 'test_channel', 'data' => { 'data' => ' my_message' } } }
|
444
|
+
|
445
|
+
it 'publishes the message' do
|
446
|
+
expect(subject).to receive(:server_publish_event).with(channel, data['data'].to_json)
|
447
|
+
actor.publish(channel, data)
|
448
|
+
end
|
449
|
+
|
450
|
+
it 'does not publish if channel is blank' do
|
451
|
+
expect(subject).to_not receive(:server_publish_event)
|
452
|
+
actor.publish(nil, data)
|
453
|
+
end
|
454
|
+
|
455
|
+
it 'publishes null' do
|
456
|
+
expect(subject).to receive(:server_publish_event).with(channel, 'null')
|
457
|
+
actor.publish(channel, data.except('data'))
|
458
|
+
end
|
459
|
+
|
460
|
+
it 'catches error' do
|
461
|
+
expect(subject).to receive(:server_publish_event).and_raise(StandardError)
|
462
|
+
expect(subject).to receive(:log_debug)
|
463
|
+
actor.publish(channel, data.except('data'))
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
describe 'server_publish_event' do
|
468
|
+
let(:actor2) { CelluloidPubsub::Reactor.new.initialize_data(websocket, server) }
|
469
|
+
let(:subject2) { actor2.own_self }
|
470
|
+
|
471
|
+
let(:channel) { 'test' }
|
472
|
+
let(:message) { '1' }
|
473
|
+
before do
|
474
|
+
server.subscribers[channel] = [{ reactor: actor }, { reactor: actor2 }]
|
475
|
+
end
|
476
|
+
|
477
|
+
it 'published message to channel' do
|
478
|
+
server.subscribers[channel].each do |hash|
|
479
|
+
expect(hash[:reactor].websocket).to receive(:<<).with(message)
|
480
|
+
end
|
481
|
+
actor.server_publish_event(channel, message)
|
482
|
+
end
|
483
|
+
|
484
|
+
it 'saves the mesages if no subscribers' do
|
485
|
+
channel2 = 'some-channel'
|
486
|
+
expect(subject).to receive(:save_unpublished_message).with(channel2, message).and_call_original
|
487
|
+
actor.server_publish_event(channel2, message)
|
488
|
+
expect(CelluloidPubsub::Registry.messages).to eq(channel2 => [message])
|
489
|
+
end
|
490
|
+
end
|
491
|
+
describe 'unsubscribe_from_channel' do
|
492
|
+
let(:channel) { 'test' }
|
493
|
+
it 'kills the reactors' do
|
494
|
+
expect(subject).to receive(:server_kill_reactors).with(channel)
|
495
|
+
subject.unsubscribe_from_channel(channel)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
describe 'server_kill_reactors' do
|
500
|
+
let(:actor2) { CelluloidPubsub::Reactor.new.initialize_data(websocket, server) }
|
501
|
+
let(:subject2) { actor2.own_self }
|
502
|
+
|
503
|
+
let(:channel) { 'test' }
|
504
|
+
|
505
|
+
before do
|
506
|
+
server.subscribers[channel] = [{ reactor: actor }, { reactor: actor2 }]
|
507
|
+
end
|
508
|
+
|
509
|
+
it 'kills the reactors' do
|
510
|
+
server.subscribers[channel].each do |hash|
|
511
|
+
expect(hash[:reactor].websocket).to receive(:close)
|
512
|
+
expect(Celluloid::Actor).to receive(:kill).ordered.with(hash[:reactor])
|
513
|
+
end
|
514
|
+
actor.server_kill_reactors(channel)
|
515
|
+
end
|
516
|
+
end
|
517
|
+
describe 'actor_died' do
|
518
|
+
it 'sets the shutting down' do
|
519
|
+
expect { actor.send(:actor_died, actor, nil) }.to change(actor, :shutting_down?).from(false).to(true)
|
245
520
|
end
|
246
521
|
end
|
247
522
|
end
|