celluloid_pubsub_redis_adapter 0.0.1
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 +7 -0
- data/.codeclimate.yml +26 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +19 -0
- data/.reek +11 -0
- data/.rspec +1 -0
- data/.rubocop.yml +72 -0
- data/.travis.yml +16 -0
- data/CONTRIBUTING.md +44 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +158 -0
- data/LICENSE +20 -0
- data/README.md +135 -0
- data/Rakefile +35 -0
- data/celluloid_pubsub_redis_adapter.gemspec +32 -0
- data/examples/log/celluloid_pubsub.log +43 -0
- data/examples/redis_test.rb +2 -0
- data/examples/shared_classes.rb +73 -0
- data/examples/simple_test.rb +2 -0
- data/init.rb +1 -0
- data/lib/celluloid_pubsub_redis_adapter/redis_reactor.rb +282 -0
- data/lib/celluloid_pubsub_redis_adapter/version.rb +27 -0
- data/lib/celluloid_pubsub_redis_adapter.rb +2 -0
- data/spec/lib/celluloid_pubsub/reactor_spec.rb +221 -0
- data/spec/spec_helper.rb +47 -0
- metadata +312 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'celluloid_pubsub'
|
3
|
+
require 'celluloid_pubsub_redis_adapter'
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
debug_enabled = ENV['DEBUG'].present? && ENV['DEBUG'].to_s == 'true'
|
7
|
+
use_redis = ENV['USE_REDIS'].to_s == 'true' ? 'redis': ''
|
8
|
+
log_file_path = File.join(File.expand_path(File.dirname(__FILE__)), 'log', 'celluloid_pubsub.log')
|
9
|
+
|
10
|
+
# actor that subscribes to a channel
|
11
|
+
class Subscriber
|
12
|
+
include Celluloid
|
13
|
+
include Celluloid::Logger
|
14
|
+
|
15
|
+
def initialize(options = {})
|
16
|
+
@client = CelluloidPubsub::Client.new({ actor: Actor.current, channel: 'test_channel' }.merge(options))
|
17
|
+
end
|
18
|
+
|
19
|
+
def on_message(message)
|
20
|
+
if @client.succesfull_subscription?(message)
|
21
|
+
puts "subscriber got successful subscription #{message.inspect}"
|
22
|
+
@client.publish('test_channel2', 'data' => ' subscriber got successfull subscription') # the message needs to be a Hash
|
23
|
+
else
|
24
|
+
puts "subscriber got message #{message.inspect}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_close(code, reason)
|
29
|
+
puts "websocket connection closed: #{code.inspect}, #{reason.inspect}"
|
30
|
+
terminate
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
# actor that publishes a message in a channel
|
37
|
+
class Publisher
|
38
|
+
include Celluloid
|
39
|
+
include Celluloid::Logger
|
40
|
+
|
41
|
+
def initialize(options = {})
|
42
|
+
@client = CelluloidPubsub::Client.new({ actor: Actor.current, channel: 'test_channel2' }.merge(options))
|
43
|
+
end
|
44
|
+
|
45
|
+
def on_message(message)
|
46
|
+
if @client.succesfull_subscription?(message)
|
47
|
+
puts "publisher got successful subscription #{message.inspect}"
|
48
|
+
@client.publish('test_channel', 'data' => ' my_message') # the message needs to be a Hash
|
49
|
+
else
|
50
|
+
puts "publisher got message #{message.inspect}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_close(code, reason)
|
55
|
+
puts "websocket connection closed: #{code.inspect}, #{reason.inspect}"
|
56
|
+
terminate
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
CelluloidPubsub::WebServer.supervise_as(:web_server, enable_debug: debug_enabled, adapter: use_redis,log_file_path: log_file_path )
|
63
|
+
Subscriber.supervise_as(:subscriber, enable_debug: debug_enabled)
|
64
|
+
Publisher.supervise_as(:publisher, enable_debug: debug_enabled)
|
65
|
+
signal_received = false
|
66
|
+
|
67
|
+
Signal.trap('INT') do
|
68
|
+
puts "\nAn interrupt signal has been triggered!"
|
69
|
+
signal_received = true
|
70
|
+
end
|
71
|
+
|
72
|
+
sleep 0.1 until signal_received
|
73
|
+
puts 'Exited succesfully! =)'
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'celluloid_pubsub_redis_adapter'
|
@@ -0,0 +1,282 @@
|
|
1
|
+
require 'celluloid_pubsub/reactor'
|
2
|
+
require 'celluloid_pubsub/helper'
|
3
|
+
module CelluloidPubsub
|
4
|
+
# reactor used for redis pubsub
|
5
|
+
# @!attribute connected
|
6
|
+
# @return [Boolean] returns true if already connected to redis
|
7
|
+
# @!attribute connection
|
8
|
+
# @return [EM::Hiredis] The connection used for redis
|
9
|
+
class RedisReactor < CelluloidPubsub::Reactor
|
10
|
+
include Celluloid
|
11
|
+
include Celluloid::IO
|
12
|
+
include Celluloid::Logger
|
13
|
+
include CelluloidPubsub::Helper
|
14
|
+
|
15
|
+
attr_accessor :connected, :connection
|
16
|
+
|
17
|
+
alias_method :connected?, :connected
|
18
|
+
|
19
|
+
# returns true if already connected to redis otherwise false
|
20
|
+
#
|
21
|
+
# @return [Boolean] returns true if already connected to redis otherwise false
|
22
|
+
#
|
23
|
+
# @api public
|
24
|
+
def connected
|
25
|
+
@connected ||= false
|
26
|
+
end
|
27
|
+
|
28
|
+
# method used to unsubscribe from a channel
|
29
|
+
# @see #redis_action
|
30
|
+
#
|
31
|
+
# @return [void]
|
32
|
+
#
|
33
|
+
# @api public
|
34
|
+
def unsubscribe(channel)
|
35
|
+
super
|
36
|
+
async.redis_action('unsubscribe', channel)
|
37
|
+
end
|
38
|
+
|
39
|
+
# method used to subscribe to a channel
|
40
|
+
# @see #redis_action
|
41
|
+
#
|
42
|
+
# @return [void]
|
43
|
+
#
|
44
|
+
# @api public
|
45
|
+
def add_subscriber_to_channel(channel, message)
|
46
|
+
super
|
47
|
+
async.redis_action('subscribe', channel, message)
|
48
|
+
end
|
49
|
+
|
50
|
+
# method used to unsubscribe from a channel
|
51
|
+
# @see #redis_action
|
52
|
+
#
|
53
|
+
# @return [void]
|
54
|
+
#
|
55
|
+
# @api public
|
56
|
+
def unsubscribe_from_channel(channel)
|
57
|
+
super
|
58
|
+
async.redis_action('unsubscribe', channel)
|
59
|
+
end
|
60
|
+
|
61
|
+
# method used to unsubscribe from all channels
|
62
|
+
# @see #redis_action
|
63
|
+
#
|
64
|
+
# @return [void]
|
65
|
+
#
|
66
|
+
# @api public
|
67
|
+
def unsubscribe_all
|
68
|
+
info 'clearing connections'
|
69
|
+
shutdown
|
70
|
+
end
|
71
|
+
|
72
|
+
# method used to shutdown the reactor and unsubscribe from all channels
|
73
|
+
# @see #redis_action
|
74
|
+
#
|
75
|
+
# @return [void]
|
76
|
+
#
|
77
|
+
# @api public
|
78
|
+
def shutdown
|
79
|
+
@channels.dup.each do |channel|
|
80
|
+
redis_action('unsubscribe', channel)
|
81
|
+
end if @channels.present?
|
82
|
+
super
|
83
|
+
end
|
84
|
+
|
85
|
+
# method used to publish event using redis
|
86
|
+
#
|
87
|
+
# @return [void]
|
88
|
+
#
|
89
|
+
# @api public
|
90
|
+
def publish_event(topic, data)
|
91
|
+
return if topic.blank? || data.blank?
|
92
|
+
connect_to_redis do |connection|
|
93
|
+
connection.publish(topic, data)
|
94
|
+
end
|
95
|
+
rescue => exception
|
96
|
+
log_debug("could not publish message #{message} into topic #{current_topic} because of #{exception.inspect}")
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
# method used to run the enventmachine and setup the exception handler
|
102
|
+
# @see #run_the_eventmachine
|
103
|
+
# @see #setup_em_exception_handler
|
104
|
+
#
|
105
|
+
# @param [Proc] block the block that will use the connection
|
106
|
+
#
|
107
|
+
# @return [void]
|
108
|
+
#
|
109
|
+
# @api private
|
110
|
+
def connect_to_redis(&block)
|
111
|
+
require 'eventmachine'
|
112
|
+
require 'em-hiredis'
|
113
|
+
run_the_eventmachine(&block)
|
114
|
+
setup_em_exception_handler
|
115
|
+
end
|
116
|
+
|
117
|
+
# method used to connect to redis and yield the connection
|
118
|
+
#
|
119
|
+
# @param [Proc] block the block that will use the connection
|
120
|
+
#
|
121
|
+
# @return [void]
|
122
|
+
#
|
123
|
+
# @api private
|
124
|
+
def run_the_eventmachine(&block)
|
125
|
+
EM.run do
|
126
|
+
@connection ||= EM::Hiredis.connect
|
127
|
+
@connected = true
|
128
|
+
block.call @connection
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# method used to setup the eventmachine exception handler
|
133
|
+
#
|
134
|
+
# @return [void]
|
135
|
+
#
|
136
|
+
# @api private
|
137
|
+
def setup_em_exception_handler
|
138
|
+
EM.error_handler do |error|
|
139
|
+
debug error unless filtered_error?(error)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# method used to fetch the pubsub client from the connection and yield it
|
144
|
+
#
|
145
|
+
# @return [void]
|
146
|
+
#
|
147
|
+
# @api private
|
148
|
+
def fetch_pubsub
|
149
|
+
connect_to_redis do |connection|
|
150
|
+
@pubsub ||= connection.pubsub
|
151
|
+
yield @pubsub if block_given?
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# method used to fetch the pubsub client from the connection and yield it
|
156
|
+
# @see #action_subscribe
|
157
|
+
#
|
158
|
+
# @param [string] action The action that will be checked
|
159
|
+
# @param [string] channel The channel that reactor has subscribed to
|
160
|
+
# @param [string] message The initial message used to subscribe
|
161
|
+
#
|
162
|
+
# @return [void]
|
163
|
+
#
|
164
|
+
# @api private
|
165
|
+
def action_success(action, channel, message)
|
166
|
+
action_subscribe?(action) ? message.merge('client_action' => 'successful_subscription', 'channel' => channel) : nil
|
167
|
+
end
|
168
|
+
|
169
|
+
# method used execute an action (subscribe or unsubscribe ) to redis
|
170
|
+
# @see #prepare_redis_action
|
171
|
+
# @see #action_success
|
172
|
+
# @see #register_subscription_callbacks
|
173
|
+
#
|
174
|
+
# @param [string] action The action that will be checked
|
175
|
+
# @param [string] channel The channel that reactor has subscribed to
|
176
|
+
# @param [string] message The initial message used to subscribe
|
177
|
+
#
|
178
|
+
# @return [void]
|
179
|
+
#
|
180
|
+
# @api private
|
181
|
+
def redis_action(action, channel = nil, message = {})
|
182
|
+
fetch_pubsub do |pubsub|
|
183
|
+
callback = prepare_redis_action(pubsub, action)
|
184
|
+
success_message = action_success(action, channel, message)
|
185
|
+
args = action_subscribe?(action) ? [channel, callback] : [channel]
|
186
|
+
subscription = pubsub.send(action, *args)
|
187
|
+
register_subscription_callbacks(subscription, action, success_message)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# method used check if the action is subscribe and write the incoming message to be websocket or log the message otherwise
|
192
|
+
# @see #log_unsubscriptions
|
193
|
+
# @see #action_subscribe
|
194
|
+
#
|
195
|
+
# @param [String] action The action that will be checked if it is subscribed
|
196
|
+
#
|
197
|
+
# @return [void]
|
198
|
+
#
|
199
|
+
# @api private
|
200
|
+
def prepare_redis_action(pubsub, action)
|
201
|
+
log_unsubscriptions(pubsub)
|
202
|
+
proc do |subscribed_message|
|
203
|
+
action_subscribe?(action) ? (@websocket << subscribed_message) : log_debug(message)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# method used to listen to unsubscriptions and log them to log file
|
208
|
+
# @see #register_redis_callback
|
209
|
+
# @see #register_redis_error_callback
|
210
|
+
#
|
211
|
+
# @param [EM::Hiredis::PubsubClient] pubsub The pubsub client that will be used to listen to unsubscriptions
|
212
|
+
#
|
213
|
+
# @return [void]
|
214
|
+
#
|
215
|
+
# @api private
|
216
|
+
def log_unsubscriptions(pubsub)
|
217
|
+
pubsub.on(:unsubscribe) do |subscribed_channel, remaining_subscriptions|
|
218
|
+
log_debug [:unsubscribe_happened, subscribed_channel, remaining_subscriptions].inspect
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# method used registers the sucess and error callabacks
|
223
|
+
# @see #register_redis_callback
|
224
|
+
# @see #register_redis_error_callback
|
225
|
+
#
|
226
|
+
# @param [EM::DefaultDeferrable] subscription The subscription object
|
227
|
+
# @param [string] action The action that will be checked
|
228
|
+
# @param [string] sucess_message The initial message used to subscribe
|
229
|
+
#
|
230
|
+
# @return [void]
|
231
|
+
#
|
232
|
+
# @api private
|
233
|
+
def register_subscription_callbacks(subscription, action, sucess_message = nil)
|
234
|
+
register_redis_callback(subscription, action, sucess_message)
|
235
|
+
register_redis_error_callback(subscription, action)
|
236
|
+
end
|
237
|
+
|
238
|
+
# the method will return true if debug is enabled
|
239
|
+
#
|
240
|
+
#
|
241
|
+
# @return [Boolean] returns true if debug is enabled otherwise false
|
242
|
+
#
|
243
|
+
# @api public
|
244
|
+
def debug_enabled?
|
245
|
+
@server.debug_enabled?
|
246
|
+
end
|
247
|
+
|
248
|
+
# method used to register a success callback and if action is subscribe will write
|
249
|
+
# back to the websocket a message that will say it is a successful_subscription
|
250
|
+
# If action is something else, will log the incoming message
|
251
|
+
# @see #log_debug
|
252
|
+
#
|
253
|
+
# @param [EM::DefaultDeferrable] subscription The subscription object
|
254
|
+
# @param [string] sucess_message The initial message used to subscribe
|
255
|
+
#
|
256
|
+
# @return [void]
|
257
|
+
#
|
258
|
+
# @api private
|
259
|
+
def register_redis_callback(subscription, action, sucess_message = nil)
|
260
|
+
subscription.callback do |subscriptions_ids|
|
261
|
+
if sucess_message.present?
|
262
|
+
@websocket << sucess_message.merge('subscriptions' => subscriptions_ids).to_json
|
263
|
+
else
|
264
|
+
log_debug "#{action} success #{sucess_message.inspect}"
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
# Register an error callback on the deferrable object and logs to file the incoming message
|
270
|
+
# @see #log_debug
|
271
|
+
#
|
272
|
+
# @param [EM::DefaultDeferrable] subscription The subscription object
|
273
|
+
# @param [string] action The action that will be checked
|
274
|
+
#
|
275
|
+
# @return [void]
|
276
|
+
#
|
277
|
+
# @api private
|
278
|
+
def register_redis_error_callback(subscription, action)
|
279
|
+
subscription.errback { |reply| log_debug "#{action} error #{reply.inspect}" }
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Returns the version of the gem as a <tt>Gem::Version</tt>
|
2
|
+
module CelluloidPubsubRedisAdapter
|
3
|
+
# it prints the gem version as a string
|
4
|
+
#
|
5
|
+
# @return [String]
|
6
|
+
#
|
7
|
+
# @api public
|
8
|
+
def self.gem_version
|
9
|
+
Gem::Version.new VERSION::STRING
|
10
|
+
end
|
11
|
+
|
12
|
+
# module used to generate the version string
|
13
|
+
# provides a easy way of getting the major, minor and tiny
|
14
|
+
module VERSION
|
15
|
+
# major release version
|
16
|
+
MAJOR = 0
|
17
|
+
# minor release version
|
18
|
+
MINOR = 0
|
19
|
+
# tiny release version
|
20
|
+
TINY = 1
|
21
|
+
# prelease version ( set this only if it is a prelease)
|
22
|
+
PRE = nil
|
23
|
+
|
24
|
+
# generates the version string
|
25
|
+
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
# encoding:utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe CelluloidPubsub::RedisReactor do
|
6
|
+
let(:websocket) { mock }
|
7
|
+
let(:server) { mock }
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
subject.stubs(:async).returns(subject)
|
11
|
+
server.stubs(:debug_enabled?).returns(false)
|
12
|
+
server.stubs(:async).returns(server)
|
13
|
+
server.stubs(:handle_dispatched_message)
|
14
|
+
server.stubs(:subscribers).returns({})
|
15
|
+
server.stubs(:redis_enabled?).returns(false)
|
16
|
+
websocket.stubs(:read)
|
17
|
+
websocket.stubs(:url)
|
18
|
+
websocket.stubs(:close)
|
19
|
+
websocket.stubs(:closed?).returns(false)
|
20
|
+
server.stubs(:alive?).returns(true)
|
21
|
+
subject.stubs(:inspect).returns(subject)
|
22
|
+
subject.stubs(:run)
|
23
|
+
subject.work(websocket, server)
|
24
|
+
subject.stubs(:unsubscribe_from_channel).returns(true)
|
25
|
+
Celluloid::Actor.stubs(:kill).returns(true)
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#work' do
|
29
|
+
it 'works ' do
|
30
|
+
subject.expects(:run)
|
31
|
+
subject.work(websocket, server)
|
32
|
+
expect(subject.websocket).to eq websocket
|
33
|
+
expect(subject.server).to eq server
|
34
|
+
expect(subject.channels).to eq []
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# describe '#rub' do
|
39
|
+
# let(:data) { 'some message' }
|
40
|
+
#
|
41
|
+
# it 'works ' do
|
42
|
+
# subject.unstub(:run)
|
43
|
+
# websocket.stubs(:read).returns(data)
|
44
|
+
# subject.expects(:handle_websocket_message).with(data)
|
45
|
+
# subject.run
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
|
49
|
+
describe '#parse_json_data' do
|
50
|
+
let(:data) { 'some message' }
|
51
|
+
let(:expected) { data.to_json }
|
52
|
+
|
53
|
+
it 'works with hash ' do
|
54
|
+
JSON.expects(:parse).with(data).returns(expected)
|
55
|
+
actual = subject.parse_json_data(data)
|
56
|
+
expect(actual).to eq expected
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'works with exception parsing ' do
|
60
|
+
JSON.expects(:parse).with(data).raises(StandardError)
|
61
|
+
actual = subject.parse_json_data(data)
|
62
|
+
expect(actual).to eq data
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#handle_websocket_message' do
|
67
|
+
let(:data) { 'some message' }
|
68
|
+
let(:json_data) { { a: 'b' } }
|
69
|
+
|
70
|
+
it 'handle_websocket_message' do
|
71
|
+
subject.expects(:parse_json_data).with(data).returns(json_data)
|
72
|
+
subject.expects(:handle_parsed_websocket_message).with(json_data)
|
73
|
+
subject.handle_websocket_message(data)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '#handle_parsed_websocket_message' do
|
78
|
+
it 'handle_websocket_message with a hash' do
|
79
|
+
data = { 'client_action' => 'b' }
|
80
|
+
data.expects(:stringify_keys).returns(data)
|
81
|
+
subject.expects(:delegate_action).with(data)
|
82
|
+
subject.handle_parsed_websocket_message(data)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'handle_websocket_message with something else than a hash' do
|
86
|
+
data = 'some message'
|
87
|
+
subject.expects(:handle_unknown_action).with(data)
|
88
|
+
subject.handle_parsed_websocket_message(data)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#delegate_action' do
|
93
|
+
it 'unsubscribes all' do
|
94
|
+
data = { 'client_action' => 'unsubscribe_all' }
|
95
|
+
subject.expects(:unsubscribe_all).returns('bla')
|
96
|
+
subject.delegate_action(data)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'unsubscribes all' do
|
100
|
+
data = { 'client_action' => 'unsubscribe', 'channel' => 'some channel' }
|
101
|
+
subject.expects(:unsubscribe).with(data['channel'])
|
102
|
+
subject.delegate_action(data)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'subscribes to channell' do
|
106
|
+
data = { 'client_action' => 'subscribe', 'channel' => 'some channel' }
|
107
|
+
subject.expects(:start_subscriber).with(data['channel'], data)
|
108
|
+
subject.delegate_action(data)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'publish' do
|
112
|
+
data = { 'client_action' => 'publish', 'channel' => 'some channel', 'data' => 'some data' }
|
113
|
+
subject.expects(:publish_event).with(data['channel'], data['data'].to_json)
|
114
|
+
subject.delegate_action(data)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'handles unknown' do
|
118
|
+
data = { 'client_action' => 'some action', 'channel' => 'some channel' }
|
119
|
+
subject.expects(:handle_unknown_action).with(data)
|
120
|
+
subject.delegate_action(data)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe '#handle_unknown_action' do
|
125
|
+
it 'handles unknown' do
|
126
|
+
data = 'some data'
|
127
|
+
server.expects(:handle_dispatched_message)
|
128
|
+
subject.handle_unknown_action(data)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe '#unsubscribe_client' do
|
133
|
+
let(:channel) { 'some channel' }
|
134
|
+
it 'returns nil' do
|
135
|
+
act = subject.unsubscribe('')
|
136
|
+
expect(act).to eq(nil)
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'unsubscribes' do
|
140
|
+
subject.channels.stubs(:blank?).returns(false)
|
141
|
+
subject.channels.expects(:delete).with(channel)
|
142
|
+
act = subject.unsubscribe(channel)
|
143
|
+
expect(act).to eq([])
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'unsubscribes' do
|
147
|
+
subject.channels.stubs(:blank?).returns(true)
|
148
|
+
subject.websocket.expects(:close)
|
149
|
+
act = subject.unsubscribe(channel)
|
150
|
+
expect(act).to eq([])
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'unsubscribes' do
|
154
|
+
subject.channels.stubs(:blank?).returns(false)
|
155
|
+
subject.channels.stubs(:delete)
|
156
|
+
server.stubs(:subscribers).returns("#{channel}" => [{ reactor: subject }])
|
157
|
+
subject.unsubscribe(channel)
|
158
|
+
expect(server.subscribers[channel]).to eq([])
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe '#shutdown' do
|
163
|
+
it 'shutdowns' do
|
164
|
+
subject.expects(:terminate)
|
165
|
+
subject.shutdown
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe '#start_subscriber' do
|
170
|
+
let(:channel) { 'some channel' }
|
171
|
+
let(:message) { { a: 'b' } }
|
172
|
+
|
173
|
+
it 'subscribes ' do
|
174
|
+
act = subject.start_subscriber('', message)
|
175
|
+
expect(act).to eq(nil)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'subscribes ' do
|
179
|
+
subject.stubs(:add_subscriber_to_channel).with(channel, message)
|
180
|
+
server.stubs(:redis_enabled?).returns(false)
|
181
|
+
subject.websocket.expects(:<<).with(message.merge('client_action' => 'successful_subscription', 'channel' => channel).to_json)
|
182
|
+
subject.start_subscriber(channel, message)
|
183
|
+
end
|
184
|
+
|
185
|
+
# it 'raises error' do
|
186
|
+
# subject.stubs(:add_subscriber_to_channel).raises(StandardError)
|
187
|
+
#
|
188
|
+
# expect do
|
189
|
+
# subject.start_subscriber(channel, message)
|
190
|
+
# end.to raise_error(StandardError) { |e|
|
191
|
+
# expect(e.message).to include(channel)
|
192
|
+
# }
|
193
|
+
# end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe '#add_subscriber_to_channel' do
|
197
|
+
let(:channel) { 'some channel' }
|
198
|
+
let(:message) { { a: 'b' } }
|
199
|
+
let(:subscribers) { mock }
|
200
|
+
|
201
|
+
it 'adds subscribed' do
|
202
|
+
CelluloidPubsub::Registry.channels.stubs(:include?).with(channel).returns(false)
|
203
|
+
CelluloidPubsub::Registry.channels.expects(:<<).with(channel)
|
204
|
+
subject.expects(:channel_subscribers).with(channel).returns(subscribers)
|
205
|
+
subscribers.expects(:push).with(reactor: subject, message: message)
|
206
|
+
subject.add_subscriber_to_channel(channel, message)
|
207
|
+
expect(subject.channels).to include(channel)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
describe '#unsubscribe_all' do
|
212
|
+
let(:channel) { 'some channel' }
|
213
|
+
let(:message) { { a: 'b' } }
|
214
|
+
|
215
|
+
it 'adds subscribed' do
|
216
|
+
CelluloidPubsub::Registry.stubs(:channels).returns([channel])
|
217
|
+
subject.expects(:unsubscribe_from_channel).with(channel)
|
218
|
+
subject.unsubscribe_all
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Configure Rails Envinronment
|
2
|
+
ENV['RAILS_ENV'] = 'test'
|
3
|
+
|
4
|
+
require 'simplecov'
|
5
|
+
require 'simplecov-summary'
|
6
|
+
require 'coveralls'
|
7
|
+
|
8
|
+
# require "codeclimate-test-reporter"
|
9
|
+
formatters = [SimpleCov::Formatter::HTMLFormatter]
|
10
|
+
|
11
|
+
formatters << Coveralls::SimpleCov::Formatter # if ENV['TRAVIS']
|
12
|
+
# formatters << CodeClimate::TestReporter::Formatter # if ENV['CODECLIMATE_REPO_TOKEN'] && ENV['TRAVIS']
|
13
|
+
|
14
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[*formatters]
|
15
|
+
|
16
|
+
Coveralls.wear!
|
17
|
+
SimpleCov.start 'rails' do
|
18
|
+
add_filter 'spec'
|
19
|
+
|
20
|
+
at_exit {}
|
21
|
+
end
|
22
|
+
|
23
|
+
# CodeClimate::TestReporter.configure do |config|
|
24
|
+
# config.logger.level = Logger::WARN
|
25
|
+
# end
|
26
|
+
# CodeClimate::TestReporter.start
|
27
|
+
|
28
|
+
require 'bundler/setup'
|
29
|
+
require 'celluloid_pubsub'
|
30
|
+
require 'celluloid_pubsub_redis_adapter'
|
31
|
+
|
32
|
+
RSpec.configure do |config|
|
33
|
+
require 'rspec/expectations'
|
34
|
+
config.include RSpec::Matchers
|
35
|
+
|
36
|
+
config.mock_with :mocha
|
37
|
+
|
38
|
+
config.after(:suite) do
|
39
|
+
if SimpleCov.running
|
40
|
+
silence_stream(STDOUT) do
|
41
|
+
SimpleCov::Formatter::HTMLFormatter.new.format(SimpleCov.result)
|
42
|
+
end
|
43
|
+
|
44
|
+
SimpleCov::Formatter::SummaryFormatter.new.format(SimpleCov.result)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|