juggernaut 0.5.8 → 2.0.0.beta1
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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README +7 -0
- data/Rakefile +16 -14
- data/VERSION +1 -0
- data/juggernaut.gemspec +47 -0
- data/lib/juggernaut.rb +12 -151
- metadata +43 -60
- data/Manifest.txt +0 -11
- data/README.txt +0 -32
- data/bin/juggernaut +0 -4
- data/lib/juggernaut/client.rb +0 -263
- data/lib/juggernaut/message.rb +0 -19
- data/lib/juggernaut/miscel.rb +0 -27
- data/lib/juggernaut/runner.rb +0 -219
- data/lib/juggernaut/server.rb +0 -368
- data/lib/juggernaut/utils.rb +0 -11
- data/test/test_client.rb +0 -176
- data/test/test_juggernaut.rb +0 -34
- data/test/test_message.rb +0 -26
- data/test/test_runner.rb +0 -26
- data/test/test_server.rb +0 -573
- data/test/test_utils.rb +0 -26
data/lib/juggernaut/server.rb
DELETED
@@ -1,368 +0,0 @@
|
|
1
|
-
require 'eventmachine'
|
2
|
-
require 'socket'
|
3
|
-
require 'json'
|
4
|
-
require 'open-uri'
|
5
|
-
require 'fileutils'
|
6
|
-
require 'digest/sha1'
|
7
|
-
|
8
|
-
module Juggernaut
|
9
|
-
class Server < EventMachine::Connection
|
10
|
-
include Juggernaut::Miscel
|
11
|
-
|
12
|
-
class InvalidRequest < Juggernaut::JuggernautError #:nodoc:
|
13
|
-
end
|
14
|
-
|
15
|
-
class InvalidCommand < Juggernaut::JuggernautError #:nodoc:
|
16
|
-
end
|
17
|
-
|
18
|
-
class CorruptJSON < Juggernaut::JuggernautError #:nodoc:
|
19
|
-
end
|
20
|
-
|
21
|
-
class MalformedBroadcast < Juggernaut::JuggernautError #:nodoc:
|
22
|
-
end
|
23
|
-
|
24
|
-
class MalformedSubscribe < Juggernaut::JuggernautError #:nodoc:
|
25
|
-
end
|
26
|
-
|
27
|
-
class UnauthorisedSubscription < Juggernaut::JuggernautError #:nodoc:
|
28
|
-
end
|
29
|
-
|
30
|
-
class MalformedQuery < Juggernaut::JuggernautError #:nodoc:
|
31
|
-
end
|
32
|
-
|
33
|
-
class UnauthorisedBroadcast < Juggernaut::JuggernautError #:nodoc:
|
34
|
-
end
|
35
|
-
|
36
|
-
class UnauthorisedQuery < Juggernaut::JuggernautError #:nodoc:
|
37
|
-
end
|
38
|
-
|
39
|
-
POLICY_FILE = <<-EOF
|
40
|
-
<cross-domain-policy>
|
41
|
-
<allow-access-from domain="*" to-ports="PORT" />
|
42
|
-
</cross-domain-policy>
|
43
|
-
EOF
|
44
|
-
|
45
|
-
POLICY_REQUEST = "<policy-file-request/>"
|
46
|
-
|
47
|
-
CR = "\0"
|
48
|
-
|
49
|
-
attr_reader :current_msg_id
|
50
|
-
attr_reader :messages
|
51
|
-
attr_reader :connected
|
52
|
-
attr_reader :logout_timeout
|
53
|
-
attr_reader :status
|
54
|
-
attr_reader :channels
|
55
|
-
attr_reader :client
|
56
|
-
|
57
|
-
# EM methods
|
58
|
-
|
59
|
-
def post_init
|
60
|
-
logger.debug "New client [#{client_ip}]"
|
61
|
-
@client = nil
|
62
|
-
@channels = []
|
63
|
-
@current_msg_id = 0
|
64
|
-
@connected = true
|
65
|
-
@logout_timeout = nil
|
66
|
-
@buffer = ''
|
67
|
-
end
|
68
|
-
|
69
|
-
# Juggernaut packets are terminated with "\0"
|
70
|
-
# so we need to buffer the data until we find the
|
71
|
-
# terminating "\0"
|
72
|
-
def receive_data(data)
|
73
|
-
@buffer << data
|
74
|
-
@buffer = process_whole_messages(@buffer)
|
75
|
-
end
|
76
|
-
|
77
|
-
# process any whole messages in the buffer,
|
78
|
-
# and return the new contents of the buffer
|
79
|
-
def process_whole_messages(data)
|
80
|
-
return data if data !~ /\0/ # only process if data contains a \0 char
|
81
|
-
messages = data.split("\0")
|
82
|
-
if data =~ /\0$/
|
83
|
-
data = ''
|
84
|
-
else
|
85
|
-
# remove the last message from the list (because it is incomplete) before processing
|
86
|
-
data = messages.pop
|
87
|
-
end
|
88
|
-
messages.each {|message| process_message(message.strip)}
|
89
|
-
return data
|
90
|
-
end
|
91
|
-
|
92
|
-
def process_message(ln)
|
93
|
-
logger.debug "Processing message: #{ln}"
|
94
|
-
@request = nil
|
95
|
-
|
96
|
-
if ln == POLICY_REQUEST
|
97
|
-
logger.debug "Sending crossdomain file"
|
98
|
-
send_data POLICY_FILE.gsub('PORT', (options[:public_port]||options[:port]).to_s)
|
99
|
-
close_connection_after_writing
|
100
|
-
return
|
101
|
-
end
|
102
|
-
|
103
|
-
begin
|
104
|
-
@request = JSON.parse(ln) unless ln.empty?
|
105
|
-
rescue
|
106
|
-
raise CorruptJSON, ln
|
107
|
-
end
|
108
|
-
|
109
|
-
raise InvalidRequest, ln if !@request
|
110
|
-
|
111
|
-
@request.symbolize_keys!
|
112
|
-
|
113
|
-
# For debugging
|
114
|
-
@request[:ip] = client_ip
|
115
|
-
|
116
|
-
@request[:channels] = (@request[:channels] || []).compact.select {|c| !!c && c != '' }.uniq
|
117
|
-
|
118
|
-
if @request[:client_ids]
|
119
|
-
@request[:client_ids] = @request[:client_ids].to_a.compact.select {|c| !!c && c != '' }.uniq
|
120
|
-
end
|
121
|
-
|
122
|
-
case @request[:command].to_sym
|
123
|
-
when :broadcast
|
124
|
-
broadcast_command
|
125
|
-
when :subscribe
|
126
|
-
subscribe_command
|
127
|
-
when :query
|
128
|
-
query_command
|
129
|
-
when :noop
|
130
|
-
noop_command
|
131
|
-
else
|
132
|
-
raise InvalidCommand, @request
|
133
|
-
end
|
134
|
-
|
135
|
-
rescue JuggernautError => e
|
136
|
-
logger.error("#{e} - #{e.message.inspect}")
|
137
|
-
close_connection
|
138
|
-
# So as to stop em quitting
|
139
|
-
rescue => e
|
140
|
-
logger ? logger.error(e) : puts(e)
|
141
|
-
end
|
142
|
-
|
143
|
-
def unbind
|
144
|
-
if @client
|
145
|
-
# todo - should be called after timeout?
|
146
|
-
@client.logout_connection_request(@channels)
|
147
|
-
logger.debug "Lost client #{@client.friendly_id}"
|
148
|
-
end
|
149
|
-
mark_dead('Unbind called')
|
150
|
-
end
|
151
|
-
|
152
|
-
# As far as I'm aware, send_data
|
153
|
-
# never throws an exception
|
154
|
-
def publish(msg)
|
155
|
-
logger.debug "Sending msg: #{msg.to_s} to client #{@request[:client_id]} (session #{@request[:session_id]})"
|
156
|
-
send_data(msg.to_s + CR)
|
157
|
-
end
|
158
|
-
|
159
|
-
# Connection methods
|
160
|
-
|
161
|
-
def broadcast(bdy)
|
162
|
-
msg = Juggernaut::Message.new(@current_msg_id += 1, bdy, self.signature)
|
163
|
-
publish(msg)
|
164
|
-
end
|
165
|
-
|
166
|
-
def mark_dead(reason = "Unknown error")
|
167
|
-
# Once dead, a client never recovers since a reconnection
|
168
|
-
# attempt would hook onto a new em instance. A client
|
169
|
-
# usually dies through an unbind
|
170
|
-
@connected = false
|
171
|
-
@client.remove_connection(self) if @client
|
172
|
-
end
|
173
|
-
|
174
|
-
def alive?
|
175
|
-
@connected == true
|
176
|
-
end
|
177
|
-
|
178
|
-
def has_channels?(channels)
|
179
|
-
channels.each {|channel|
|
180
|
-
return true if has_channel?(channel)
|
181
|
-
}
|
182
|
-
false
|
183
|
-
end
|
184
|
-
|
185
|
-
def has_channel?(channel)
|
186
|
-
@channels.include?(channel)
|
187
|
-
end
|
188
|
-
|
189
|
-
def add_channel(chan_name)
|
190
|
-
return if !chan_name or chan_name == ''
|
191
|
-
@channels << chan_name unless has_channel?(chan_name)
|
192
|
-
end
|
193
|
-
|
194
|
-
def add_channels(chan_names)
|
195
|
-
chan_names.to_a.each do |chan_name|
|
196
|
-
add_channel(chan_name)
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
def remove_channel!(chan_name)
|
201
|
-
@channels.delete(chan_name)
|
202
|
-
end
|
203
|
-
|
204
|
-
def remove_channels!(chan_names)
|
205
|
-
chan_names.to_a.each do |chan_name|
|
206
|
-
remove_channel!(chan_name)
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
protected
|
211
|
-
|
212
|
-
# Commands
|
213
|
-
|
214
|
-
def broadcast_command
|
215
|
-
raise MalformedBroadcast, @request unless @request[:type]
|
216
|
-
|
217
|
-
raise UnauthorisedBroadcast, @request unless authenticate_broadcast_or_query
|
218
|
-
|
219
|
-
case @request[:type].to_sym
|
220
|
-
when :to_channels
|
221
|
-
# if channels is a blank array, sends to everybody!
|
222
|
-
broadcast_to_channels(@request[:body], @request[:channels])
|
223
|
-
when :to_clients
|
224
|
-
broadcast_needs :client_ids
|
225
|
-
@request[:client_ids].each do |client_id|
|
226
|
-
# if channels aren't empty, scopes broadcast to clients on those channels
|
227
|
-
broadcast_to_client(@request[:body], client_id, @request[:channels])
|
228
|
-
end
|
229
|
-
else
|
230
|
-
raise MalformedBroadcast, @request
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
def query_command
|
235
|
-
raise MalformedQuery, @request unless @request[:type]
|
236
|
-
|
237
|
-
raise UnauthorisedQuery, @request unless authenticate_broadcast_or_query
|
238
|
-
|
239
|
-
case @request[:type].to_sym
|
240
|
-
when :remove_channels_from_all_clients
|
241
|
-
query_needs :channels
|
242
|
-
clients = Juggernaut::Client.find_all
|
243
|
-
clients.each {|client| client.remove_channels!(@request[:channels]) }
|
244
|
-
when :remove_channels_from_client
|
245
|
-
query_needs :client_ids, :channels
|
246
|
-
@request[:client_ids].each do |client_id|
|
247
|
-
client = Juggernaut::Client.find_by_id(client_id)
|
248
|
-
client.remove_channels!(@request[:channels]) if client
|
249
|
-
end
|
250
|
-
when :show_channels_for_client
|
251
|
-
query_needs :client_id
|
252
|
-
if client = Juggernaut::Client.find_by_id(@request[:client_id])
|
253
|
-
publish client.channels.to_json
|
254
|
-
else
|
255
|
-
publish nil.to_json
|
256
|
-
end
|
257
|
-
when :show_clients
|
258
|
-
if @request[:client_ids] and @request[:client_ids].any?
|
259
|
-
clients = @request[:client_ids].collect{ |client_id| Client.find_by_id(client_id) }.compact.uniq
|
260
|
-
else
|
261
|
-
clients = Juggernaut::Client.find_all
|
262
|
-
end
|
263
|
-
publish clients.to_json
|
264
|
-
when :show_client
|
265
|
-
query_needs :client_id
|
266
|
-
publish Juggernaut::Client.find_by_id(@request[:client_id]).to_json
|
267
|
-
when :show_clients_for_channels
|
268
|
-
query_needs :channels
|
269
|
-
publish Juggernaut::Client.find_by_channels(@request[:channels]).to_json
|
270
|
-
else
|
271
|
-
raise MalformedQuery, @request
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
def noop_command
|
276
|
-
logger.debug "NOOP"
|
277
|
-
end
|
278
|
-
|
279
|
-
def subscribe_command
|
280
|
-
logger.debug "SUBSCRIBE: #{@request.inspect}"
|
281
|
-
|
282
|
-
if channels = @request[:channels]
|
283
|
-
add_channels(channels)
|
284
|
-
end
|
285
|
-
|
286
|
-
@client = Juggernaut::Client.find_or_create(self, @request)
|
287
|
-
|
288
|
-
if !@client.subscription_request(@channels)
|
289
|
-
raise UnauthorisedSubscription, @client
|
290
|
-
end
|
291
|
-
|
292
|
-
if options[:store_messages]
|
293
|
-
@client.send_queued_messages(self)
|
294
|
-
end
|
295
|
-
end
|
296
|
-
|
297
|
-
private
|
298
|
-
|
299
|
-
# Different broadcast types
|
300
|
-
|
301
|
-
def broadcast_to_channels(msg, channels = [])
|
302
|
-
Juggernaut::Client.find_all.each {|client| client.send_message(msg, channels) }
|
303
|
-
end
|
304
|
-
|
305
|
-
def broadcast_to_client(body, client_id, channels)
|
306
|
-
client = Juggernaut::Client.find_by_id(client_id)
|
307
|
-
client.send_message(body, channels) if client
|
308
|
-
end
|
309
|
-
|
310
|
-
# Helper methods
|
311
|
-
|
312
|
-
def broadcast_needs(*args)
|
313
|
-
args.each do |arg|
|
314
|
-
raise MalformedBroadcast, @request unless @request.has_key?(arg)
|
315
|
-
end
|
316
|
-
end
|
317
|
-
|
318
|
-
def subscribe_needs(*args)
|
319
|
-
args.each do |arg|
|
320
|
-
raise MalformedSubscribe, @request unless @request.has_key?(arg)
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
def query_needs(*args)
|
325
|
-
args.each do |arg|
|
326
|
-
raise MalformedQuery, @request unless @request.has_key?(arg)
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
def authenticate_broadcast_or_query
|
331
|
-
if options[:allowed_ips]
|
332
|
-
return true if options[:allowed_ips].include?(client_ip)
|
333
|
-
elsif !@request[:secret_key]
|
334
|
-
return true if broadcast_query_request
|
335
|
-
elsif options[:secret_key]
|
336
|
-
return true if @request[:secret_key] == options[:secret_key]
|
337
|
-
end
|
338
|
-
if !options[:allowed_ips] and !options[:secret_key] and !options[:broadcast_query_login_url]
|
339
|
-
return true
|
340
|
-
end
|
341
|
-
false
|
342
|
-
end
|
343
|
-
|
344
|
-
def broadcast_query_request
|
345
|
-
return false unless options[:broadcast_query_login_url]
|
346
|
-
url = URI.parse(options[:broadcast_query_login_url])
|
347
|
-
params = []
|
348
|
-
params << "client_id=#{@request[:client_id]}" if @request[:client_id]
|
349
|
-
params << "session_id=#{URI.escape(@request[:session_id])}" if @request[:session_id]
|
350
|
-
params << "type=#{@request[:type]}"
|
351
|
-
params << "command=#{@request[:command]}"
|
352
|
-
(@request[:channels] || []).each {|chan| params << "channels[]=#{chan}" }
|
353
|
-
url.query = params.join('&')
|
354
|
-
begin
|
355
|
-
open(url.to_s, "User-Agent" => "Ruby/#{RUBY_VERSION}")
|
356
|
-
rescue Timeout::Error
|
357
|
-
return false
|
358
|
-
rescue
|
359
|
-
return false
|
360
|
-
end
|
361
|
-
true
|
362
|
-
end
|
363
|
-
|
364
|
-
def client_ip
|
365
|
-
Socket.unpack_sockaddr_in(get_peername)[1] rescue nil
|
366
|
-
end
|
367
|
-
end
|
368
|
-
end
|
data/lib/juggernaut/utils.rb
DELETED
data/test/test_client.rb
DELETED
@@ -1,176 +0,0 @@
|
|
1
|
-
|
2
|
-
$:.unshift "../lib"
|
3
|
-
require "juggernaut"
|
4
|
-
require "test/unit"
|
5
|
-
require "shoulda"
|
6
|
-
require "mocha"
|
7
|
-
|
8
|
-
class TestClient < Test::Unit::TestCase
|
9
|
-
|
10
|
-
CONFIG = File.join(File.dirname(__FILE__), "files", "juggernaut.yml")
|
11
|
-
|
12
|
-
class DummySubscriber; end
|
13
|
-
|
14
|
-
EXAMPLE_URL = "http://localhost:5000/callbacks/example"
|
15
|
-
SECURE_URL = "https://localhost:5000/callbacks/example"
|
16
|
-
|
17
|
-
context "Client" do
|
18
|
-
|
19
|
-
setup do
|
20
|
-
Juggernaut.options = {
|
21
|
-
:logout_connection_url => "http://localhost:5000/callbacks/logout_connection",
|
22
|
-
:logout_url => "http://localhost:5000/callbacks/logout",
|
23
|
-
:subscription_url => "http://localhost:5000/callbacks/subscription"
|
24
|
-
}
|
25
|
-
@s1 = DummySubscriber.new
|
26
|
-
@request = {
|
27
|
-
:client_id => "jonny",
|
28
|
-
:session_id => rand(1_000_000).to_s(16)
|
29
|
-
}
|
30
|
-
@client = Juggernaut::Client.find_or_create(@s1, @request)
|
31
|
-
end
|
32
|
-
|
33
|
-
teardown do
|
34
|
-
Juggernaut::Client.reset!
|
35
|
-
end
|
36
|
-
|
37
|
-
should "have correct JSON representation" do
|
38
|
-
assert_nothing_raised do
|
39
|
-
json = {
|
40
|
-
"client_id" => "jonny",
|
41
|
-
"num_connections" => 1,
|
42
|
-
"session_id" => @request[:session_id]
|
43
|
-
}
|
44
|
-
assert_equal json, JSON.parse(@client.to_json)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
should "return the client based on subscriber's signature" do
|
49
|
-
@s1.stubs(:signature).returns("012345")
|
50
|
-
assert_equal @client, Juggernaut::Client.find_by_signature("012345")
|
51
|
-
end
|
52
|
-
|
53
|
-
should "return the client based on client ID and channel list" do
|
54
|
-
@client.stubs(:has_channels?).with(%w(a couple of channels)).returns(true)
|
55
|
-
assert_equal @client, Juggernaut::Client.find_by_id_and_channels("jonny", %w(a couple of channels))
|
56
|
-
assert_nil Juggernaut::Client.find_by_id_and_channels("peter", %w(a couple of channels))
|
57
|
-
@client.stubs(:has_channels?).with(%w(something else)).returns(false)
|
58
|
-
assert_nil Juggernaut::Client.find_by_id_and_channels("jonny", %w(something else))
|
59
|
-
end
|
60
|
-
|
61
|
-
should "automatically be registered, and can unregister" do
|
62
|
-
assert @client.send(:registered?)
|
63
|
-
assert_equal @client, @client.send(:unregister)
|
64
|
-
assert_equal false, @client.send(:registered?)
|
65
|
-
end
|
66
|
-
|
67
|
-
should "be alive if at least one subscriber is alive" do
|
68
|
-
@s1.stubs(:alive?).returns(true)
|
69
|
-
@s2 = DummySubscriber.new
|
70
|
-
@client.add_new_connection(@s2)
|
71
|
-
@s2.stubs(:alive?).returns(false)
|
72
|
-
assert @client.alive?
|
73
|
-
end
|
74
|
-
|
75
|
-
should "not be alive if no subscriber is alive" do
|
76
|
-
@s1.stubs(:alive?).returns(false)
|
77
|
-
@s2 = DummySubscriber.new
|
78
|
-
@client.add_new_connection(@s2)
|
79
|
-
@s2.stubs(:alive?).returns(false)
|
80
|
-
assert_equal false, @client.alive?
|
81
|
-
end
|
82
|
-
|
83
|
-
should "not give up if within the timeout period" do
|
84
|
-
Juggernaut.options[:timeout] = 10
|
85
|
-
@s1.stubs(:alive?).returns(false)
|
86
|
-
@client.send(:reset_logout_timeout!)
|
87
|
-
assert_equal false, @client.give_up?
|
88
|
-
end
|
89
|
-
|
90
|
-
should "not give up if at least one subscriber is alive" do
|
91
|
-
Juggernaut.options[:timeout] = 0
|
92
|
-
@s1.stubs(:alive?).returns(true)
|
93
|
-
@client.send(:reset_logout_timeout!)
|
94
|
-
assert_equal false, @client.give_up?
|
95
|
-
end
|
96
|
-
|
97
|
-
should "send logouts after timeout" do
|
98
|
-
Juggernaut.options[:timeout] = 0
|
99
|
-
@s1.stubs(:alive?).returns(false)
|
100
|
-
@client.send(:reset_logout_timeout!)
|
101
|
-
@client.expects(:logout_request).once
|
102
|
-
Juggernaut::Client.send_logouts_after_timeout
|
103
|
-
end
|
104
|
-
|
105
|
-
%w(subscription logout_connection).each do |type|
|
106
|
-
|
107
|
-
context "#{type} request" do
|
108
|
-
|
109
|
-
should "post to the correct URL" do
|
110
|
-
@client.expects(:post_request).with(Juggernaut.options[:"#{type}_url"], %w(master), :timeout => 5).returns(true)
|
111
|
-
assert_equal true, @client.send("#{type}_request", %w(master))
|
112
|
-
end
|
113
|
-
|
114
|
-
should "not raise exceptions if posting raises an exception" do
|
115
|
-
@client.expects(:post_request).with(Juggernaut.options[:"#{type}_url"], %w(master), :timeout => 5).returns(false)
|
116
|
-
assert_nothing_raised {
|
117
|
-
assert_equal false, @client.send("#{type}_request", %w(master))
|
118
|
-
}
|
119
|
-
end
|
120
|
-
|
121
|
-
end
|
122
|
-
|
123
|
-
end
|
124
|
-
|
125
|
-
context "post to URL" do
|
126
|
-
|
127
|
-
should "return true when successful" do
|
128
|
-
Net::HTTP.any_instance.
|
129
|
-
expects(:post).
|
130
|
-
with("/callbacks/example", "client_id=jonny&session_id=#{@request[:session_id]}&channels[]=master&channels[]=slave", {"User-Agent" => "Ruby/#{RUBY_VERSION}"}).
|
131
|
-
returns([Net::HTTPOK.new('1.1', '200', 'OK'), ''])
|
132
|
-
assert_equal true, @client.send(:post_request, EXAMPLE_URL, %w(master slave))
|
133
|
-
end
|
134
|
-
|
135
|
-
should "return false on an internal server error" do
|
136
|
-
Net::HTTP.any_instance.expects(:post).returns([Net::HTTPInternalServerError.new('1.1', '500', 'Internal Server Error'), ''])
|
137
|
-
assert_equal false, @client.send(:post_request, EXAMPLE_URL, %w(master slave))
|
138
|
-
end
|
139
|
-
|
140
|
-
should "return false when a runtime error is caught" do
|
141
|
-
Net::HTTP.any_instance.expects(:post).raises(RuntimeError)
|
142
|
-
assert_equal false, @client.send(:post_request, EXAMPLE_URL, %w(master slave))
|
143
|
-
end
|
144
|
-
|
145
|
-
should "return false when callback times out" do
|
146
|
-
Net::HTTP.any_instance.expects(:post).raises(Timeout::Error)
|
147
|
-
assert_equal false, @client.send(:post_request, EXAMPLE_URL, %w(master slave))
|
148
|
-
end
|
149
|
-
|
150
|
-
context "using a secure URL" do
|
151
|
-
|
152
|
-
should "return true when successful" do
|
153
|
-
Net::HTTP.any_instance.expects(:post).returns([Net::HTTPOK.new('1.1', '200', 'OK'), ''])
|
154
|
-
Net::HTTP.any_instance.expects(:use_ssl=).with(true).returns(true)
|
155
|
-
assert_equal true, @client.send(:post_request, SECURE_URL, %w(master slave))
|
156
|
-
end
|
157
|
-
|
158
|
-
end
|
159
|
-
|
160
|
-
end
|
161
|
-
|
162
|
-
context "channel list" do
|
163
|
-
|
164
|
-
should "be the unique list of all channels in the subscribers" do
|
165
|
-
@s1.stubs(:channels).returns(%w(master slave1))
|
166
|
-
@s2 = DummySubscriber.new
|
167
|
-
@s2.stubs(:channels).returns(%w(master slave2))
|
168
|
-
@client.add_new_connection(@s2)
|
169
|
-
assert_same_elements %w(master slave1 slave2), @client.channels
|
170
|
-
end
|
171
|
-
|
172
|
-
end
|
173
|
-
|
174
|
-
end
|
175
|
-
|
176
|
-
end
|