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.
@@ -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) { mock }
9
- let(:connection) { mock }
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.any_instance.stubs(:supervise_actors).returns(true)
14
- CelluloidPubsub::Client.any_instance.stubs(:connection).returns(connection)
15
- @worker = CelluloidPubsub::Client.new(actor: actor, channel: channel, enable_debug: false)
16
- @worker.stubs(:debug).returns(true)
17
- @worker.stubs(:async).returns(@worker)
18
- actor.stubs(:async).returns(actor)
19
- actor.stubs(:respond_to?).returns(false)
20
- actor.stubs(:terminate).returns(true)
21
- connection.stubs(:terminate).returns(true)
22
- connection.stubs(:text).returns(true)
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(@worker.channel).to eq channel
28
- expect(@worker.actor).to eq actor
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
- @worker.expects(:chat).with('client_action' => 'subscribe', 'channel' => channel)
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) { mock }
73
- let(:action) { mock }
74
+ let(:message) { double(present?: true) }
75
+ let(:action) { double }
74
76
 
75
77
  before(:each) do
76
- message.stubs(:present?).returns(true)
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.expects(:is_a?).with(Hash).returns(true)
82
- message.stubs(:[]).with('client_action').returns('successful_subscription')
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.expects(:is_a?).with(Hash).returns(true)
89
- message.stubs(:[]).with('client_action').returns('something_else')
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
- @worker.expects(:send_action).with('publish', channel, data)
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
- @worker.expects(:subscribe).with(channel)
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.expects(:parse).with(data).returns(data)
118
- @worker.actor.expects(:respond_to?).returns(true)
119
- @worker.actor.expects(:async).returns(actor)
120
- @worker.actor.expects(:on_message).with(data)
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.expects(:parse).with(data).returns(data)
126
- @worker.actor.expects(:respond_to?).returns(false)
127
- @worker.actor.expects(:on_message).with(data)
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.expects(:on_close).with(code, reason).returns(true)
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 witout hash' do
149
- JSON.expects(:dump).with(json).returns(json)
150
- connection.expects(:text).with(json)
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.expects(:text).with(data_hash.to_json)
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) { mock }
7
- let(:server) { mock }
8
- let(:mutex) { mock }
9
- let(:synchronizer) { mock }
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
- subject.stubs(:async).returns(subject)
13
- server.stubs(:debug_enabled?).returns(false)
14
- server.stubs(:async).returns(server)
15
- server.stubs(:handle_dispatched_message)
16
- server.stubs(:subscribers).returns({})
17
- server.stubs(:adapter).returns(CelluloidPubsub::WebServer::CLASSIC_ADAPTER)
18
- websocket.stubs(:read)
19
- websocket.stubs(:url)
20
- websocket.stubs(:close)
21
- websocket.stubs(:closed?).returns(false)
22
- server.stubs(:dead?).returns(false)
23
- subject.stubs(:inspect).returns(subject)
24
- subject.stubs(:run)
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
- subject.expects(:run)
35
- subject.work(websocket, server)
36
- expect(subject.websocket).to eq websocket
37
- expect(subject.server).to eq server
38
- expect(subject.channels).to eq []
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
- # subject.unstub(:run)
47
- # websocket.stubs(:read).returns(data)
48
- # subject.expects(:handle_websocket_message).with(data)
49
- # subject.run
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.expects(:parse).with(data).returns(expected)
59
- actual = subject.parse_json_data(data)
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.expects(:parse).with(data).raises(StandardError)
65
- actual = subject.parse_json_data(data)
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.expects(:parse_json_data).with(data).returns(json_data)
76
- subject.expects(:handle_parsed_websocket_message).with(json_data)
77
- subject.handle_websocket_message(data)
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.expects(:stringify_keys).returns(data)
85
- subject.expects(:delegate_action).with(data)
86
- subject.handle_parsed_websocket_message(data)
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.expects(:handle_unknown_action).with(data['channel'], data)
92
- subject.handle_parsed_websocket_message(data)
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.stubs(:unsubscribe_clients).returns(true)
100
- subject.stubs(:shutdown).returns(true)
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.expects(:send).with(data['client_action'], data['channel'], data).returns('bla')
106
- subject.delegate_action(data)
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.expects(:send).with(data['client_action'], data['channel'], data)
112
- subject.delegate_action(data)
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.expects(:send).with(data['client_action'], data['channel'], data)
118
- subject.delegate_action(data)
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.expects(:send).with(data['client_action'], data['channel'], data)
124
- subject.delegate_action(data)
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 = "some_channel"
132
- server.expects(:handle_dispatched_message)
133
- subject.handle_unknown_action(channel, data)
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 = subject.unsubscribe('', data)
161
+ act = actor.unsubscribe('', data)
142
162
  expect(act).to eq(nil)
143
163
  end
144
164
 
145
165
  it 'unsubscribes' do
146
- channel.stubs(:present?).returns(true)
147
- subject.expects(:forget_channel).with(channel)
148
- subject.expects(:delete_server_subscribers).with(channel)
149
- act = subject.unsubscribe(channel, data)
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.stubs(:subscribers).returns("#{channel}" => [{ reactor: subject }])
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 = subject.delete_server_subscribers(channel)
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
- subject.channels.stubs(:blank?).returns(true)
174
- subject.websocket.expects(:close)
175
- act = subject.forget_channel(channel)
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
- subject.channels.stubs(:blank?).returns(false)
181
- subject.channels.expects(:delete).with(channel)
182
- # server.stubs(:subscribers).returns("#{channel}" => [{ reactor: subject }])
183
- subject.forget_channel(channel)
184
- # expect(server.subscribers[channel]).to eq([])
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.expects(:terminate)
191
- subject.shutdown
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 = subject.subscribe('', message)
222
+ act = actor.subscribe('', message)
201
223
  expect(act).to eq(nil)
202
224
  end
203
225
 
204
226
  it 'subscribes ' do
205
- subject.stubs(:add_subscriber_to_channel).with(channel, message)
206
- server.stubs(:redis_enabled?).returns(false)
207
- subject.websocket.expects(:<<).with(message.merge('client_action' => 'successful_subscription', 'channel' => channel).to_json)
208
- subject.subscribe(channel, message)
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.stubs(:add_subscriber_to_channel).raises(StandardError)
234
+ # subject).to receive(:add_subscriber_to_channel).raises(StandardError)
213
235
  #
214
236
  # expect do
215
- # subject.start_subscriber(channel, message)
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) { mock }
247
+ let(:subscribers) { double }
226
248
 
227
249
  it 'adds subscribed' do
228
- CelluloidPubsub::Registry.channels.stubs(:include?).with(channel).returns(false)
229
- CelluloidPubsub::Registry.channels.expects(:<<).with(channel)
230
- subject.expects(:channel_subscribers).with(channel).returns(subscribers)
231
- subscribers.expects(:push).with(reactor: subject, message: message)
232
- subject.add_subscriber_to_channel(channel, message)
233
- expect(subject.channels).to include(channel)
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.stubs(:channels).returns([channel])
243
- subject.expects(:unsubscribe_from_channel).with(channel).returns(true)
244
- subject.unsubscribe_all(channel, message)
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