celluloid_pubsub 1.0.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|