faye 0.5.5 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of faye might be problematic. Click here for more details.
- data/History.txt +14 -0
- data/README.rdoc +98 -0
- data/Rakefile +17 -15
- data/lib/faye-browser-min.js +1 -1
- data/lib/faye.rb +14 -5
- data/lib/faye/adapters/rack_adapter.rb +12 -5
- data/lib/faye/engines/base.rb +62 -0
- data/lib/faye/engines/connection.rb +63 -0
- data/lib/faye/engines/memory.rb +89 -0
- data/lib/faye/engines/redis.rb +141 -0
- data/lib/faye/error.rb +16 -4
- data/lib/faye/mixins/publisher.rb +6 -0
- data/lib/faye/protocol/channel.rb +34 -86
- data/lib/faye/protocol/client.rb +36 -52
- data/lib/faye/protocol/extensible.rb +3 -0
- data/lib/faye/protocol/server.rb +119 -169
- data/lib/faye/transport/http.rb +45 -0
- data/lib/faye/transport/local.rb +15 -0
- data/lib/faye/{network → transport}/transport.rb +36 -49
- data/spec/browser.html +35 -0
- data/spec/install.sh +48 -0
- data/spec/javascript/channel_spec.js +15 -0
- data/spec/javascript/client_spec.js +610 -0
- data/spec/javascript/engine_spec.js +319 -0
- data/spec/javascript/faye_spec.js +15 -0
- data/spec/javascript/grammar_spec.js +66 -0
- data/spec/javascript/node_adapter_spec.js +276 -0
- data/spec/javascript/server/connect_spec.js +168 -0
- data/spec/javascript/server/disconnect_spec.js +121 -0
- data/spec/javascript/server/extensions_spec.js +60 -0
- data/spec/javascript/server/handshake_spec.js +153 -0
- data/spec/javascript/server/subscribe_spec.js +245 -0
- data/spec/javascript/server/unsubscribe_spec.js +245 -0
- data/spec/javascript/server_spec.js +146 -0
- data/spec/javascript/transport_spec.js +130 -0
- data/spec/node.js +34 -0
- data/spec/ruby/channel_spec.rb +17 -0
- data/spec/ruby/client_spec.rb +615 -0
- data/spec/ruby/engine_spec.rb +312 -0
- data/spec/ruby/faye_spec.rb +14 -0
- data/spec/ruby/grammar_spec.rb +68 -0
- data/spec/ruby/rack_adapter_spec.rb +209 -0
- data/spec/ruby/server/connect_spec.rb +170 -0
- data/spec/ruby/server/disconnect_spec.rb +120 -0
- data/spec/ruby/server/extensions_spec.rb +69 -0
- data/spec/ruby/server/handshake_spec.rb +151 -0
- data/spec/ruby/server/subscribe_spec.rb +247 -0
- data/spec/ruby/server/unsubscribe_spec.rb +247 -0
- data/spec/ruby/server_spec.rb +138 -0
- data/spec/ruby/transport_spec.rb +128 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/testswarm.pl +200 -0
- data/spec/thin_proxy.rb +36 -0
- metadata +119 -84
- data/Manifest.txt +0 -27
- data/README.txt +0 -98
- data/lib/faye/protocol/connection.rb +0 -111
- data/test/scenario.rb +0 -172
- data/test/test_channel.rb +0 -54
- data/test/test_clients.rb +0 -381
- data/test/test_grammar.rb +0 -86
- data/test/test_server.rb +0 -488
@@ -1,111 +0,0 @@
|
|
1
|
-
module Faye
|
2
|
-
class Connection
|
3
|
-
include EventMachine::Deferrable
|
4
|
-
include Publisher
|
5
|
-
include Timeouts
|
6
|
-
|
7
|
-
MAX_DELAY = 0.001
|
8
|
-
INTERVAL = 0.0
|
9
|
-
TIMEOUT = 60.0
|
10
|
-
|
11
|
-
attr_reader :id, :interval, :timeout
|
12
|
-
|
13
|
-
def initialize(id, options = {})
|
14
|
-
@id = id
|
15
|
-
@options = options
|
16
|
-
@interval = @options[:interval] || INTERVAL
|
17
|
-
@timeout = @options[:timeout] || TIMEOUT
|
18
|
-
@channels = Set.new
|
19
|
-
@inbox = Set.new
|
20
|
-
@connected = false
|
21
|
-
|
22
|
-
begin_deletion_timeout
|
23
|
-
end
|
24
|
-
|
25
|
-
def socket=(socket)
|
26
|
-
@connected = true
|
27
|
-
@socket = socket
|
28
|
-
end
|
29
|
-
|
30
|
-
def on_message(event)
|
31
|
-
return unless @inbox.add?(event)
|
32
|
-
@socket.send(JSON.unparse(event)) if @socket
|
33
|
-
begin_delivery_timeout
|
34
|
-
end
|
35
|
-
|
36
|
-
def subscribe(channel)
|
37
|
-
return unless @channels.add?(channel)
|
38
|
-
channel.add_subscriber(:message, method(:on_message))
|
39
|
-
end
|
40
|
-
|
41
|
-
def unsubscribe(channel)
|
42
|
-
return @channels.each(&method(:unsubscribe)) if channel == :all
|
43
|
-
return unless @channels.member?(channel)
|
44
|
-
@channels.delete(channel)
|
45
|
-
channel.remove_subscriber(:message, method(:on_message))
|
46
|
-
end
|
47
|
-
|
48
|
-
def connect(options, &block)
|
49
|
-
options = options || {}
|
50
|
-
timeout = options['timeout'] ? options['timeout'] / 1000.0 : @timeout
|
51
|
-
|
52
|
-
set_deferred_status(:deferred)
|
53
|
-
|
54
|
-
callback(&block)
|
55
|
-
return if @connected
|
56
|
-
|
57
|
-
@connected = true
|
58
|
-
remove_timeout(:deletion)
|
59
|
-
|
60
|
-
begin_delivery_timeout
|
61
|
-
begin_connection_timeout(timeout)
|
62
|
-
end
|
63
|
-
|
64
|
-
def flush!
|
65
|
-
return unless @connected
|
66
|
-
release_connection!
|
67
|
-
|
68
|
-
events = @inbox.entries
|
69
|
-
@inbox = Set.new
|
70
|
-
|
71
|
-
set_deferred_status(:succeeded, events)
|
72
|
-
set_deferred_status(:deferred)
|
73
|
-
end
|
74
|
-
|
75
|
-
def disconnect!
|
76
|
-
unsubscribe(:all)
|
77
|
-
flush!
|
78
|
-
end
|
79
|
-
|
80
|
-
private
|
81
|
-
|
82
|
-
def release_connection!
|
83
|
-
return if @socket
|
84
|
-
|
85
|
-
remove_timeout(:connection)
|
86
|
-
remove_timeout(:delivery)
|
87
|
-
@connected = false
|
88
|
-
|
89
|
-
begin_deletion_timeout
|
90
|
-
end
|
91
|
-
|
92
|
-
def begin_delivery_timeout
|
93
|
-
return unless @connected and not @inbox.empty?
|
94
|
-
add_timeout(:delivery, MAX_DELAY) { flush! }
|
95
|
-
end
|
96
|
-
|
97
|
-
def begin_connection_timeout(timeout)
|
98
|
-
return unless @connected
|
99
|
-
add_timeout(:connection, timeout) { flush! }
|
100
|
-
end
|
101
|
-
|
102
|
-
def begin_deletion_timeout
|
103
|
-
return if @connected
|
104
|
-
add_timeout(:deletion, TIMEOUT + 10 * @timeout) do
|
105
|
-
publish_event(:stale_connection, self)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
data/test/scenario.rb
DELETED
@@ -1,172 +0,0 @@
|
|
1
|
-
$VERBOSE = false
|
2
|
-
|
3
|
-
module Scenario
|
4
|
-
module ClassMethods
|
5
|
-
def scenario(name, &block)
|
6
|
-
define_method("test: #{name}", &block)
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.included(klass)
|
11
|
-
klass.extend ClassMethods
|
12
|
-
end
|
13
|
-
|
14
|
-
def setup
|
15
|
-
Thread.new { EM.run }
|
16
|
-
while not EM.reactor_running?; end
|
17
|
-
@scenario = AsyncScenario.new
|
18
|
-
@commands = []
|
19
|
-
@started = false
|
20
|
-
end
|
21
|
-
|
22
|
-
def teardown
|
23
|
-
while EM.reactor_running?; end
|
24
|
-
end
|
25
|
-
|
26
|
-
def run(runner)
|
27
|
-
@runner = runner
|
28
|
-
super
|
29
|
-
end
|
30
|
-
|
31
|
-
def method_missing(sym, *args)
|
32
|
-
@commands << [sym, args]
|
33
|
-
EM.next_tick { run_next_command unless @started }
|
34
|
-
end
|
35
|
-
|
36
|
-
def run_next_command
|
37
|
-
@started = true
|
38
|
-
command = @commands.shift
|
39
|
-
return finish if command.nil?
|
40
|
-
begin
|
41
|
-
@scenario.__send__(command.first, *command.last) do
|
42
|
-
run_next_command
|
43
|
-
end
|
44
|
-
rescue Object => e
|
45
|
-
@passed = false
|
46
|
-
add_failure(e.message, e.backtrace)
|
47
|
-
@runner.puke(self.class, self.name, e) if @runner.respond_to?(:puke)
|
48
|
-
block.call
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def finish
|
53
|
-
@scenario.finish { EM.stop }
|
54
|
-
end
|
55
|
-
|
56
|
-
class AsyncScenario
|
57
|
-
include Test::Unit::Assertions
|
58
|
-
|
59
|
-
def initialize
|
60
|
-
@clients = {}
|
61
|
-
@inbox = {}
|
62
|
-
@errors = {}
|
63
|
-
@pool = 0
|
64
|
-
end
|
65
|
-
|
66
|
-
def wait(time, &block)
|
67
|
-
EM.add_timer(time, &block)
|
68
|
-
end
|
69
|
-
|
70
|
-
def server(port, &block)
|
71
|
-
@endpoint = "http://0.0.0.0:#{port}/bayeux"
|
72
|
-
@bayeux = Faye::RackAdapter.new(:mount => '/bayeux', :timeout => 30)
|
73
|
-
Rack::Handler.get('thin').run(@bayeux, :Port => port) do |server|
|
74
|
-
@server = server
|
75
|
-
EM.next_tick(&block)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def http_client(name, channels = nil, &block)
|
80
|
-
setup_client(Faye::Client.new(@endpoint), name, channels, &block)
|
81
|
-
end
|
82
|
-
|
83
|
-
def local_client(name, channels = nil, &block)
|
84
|
-
setup_client(@bayeux.get_client, name, channels, &block)
|
85
|
-
end
|
86
|
-
|
87
|
-
def extend_server(stage, extension, &block)
|
88
|
-
object = Object.new
|
89
|
-
def object.added
|
90
|
-
@active = true
|
91
|
-
end
|
92
|
-
(class << object; self; end).send(:define_method, stage) do |*args|
|
93
|
-
extension.call(*args) if @active
|
94
|
-
end
|
95
|
-
@bayeux.add_extension(object)
|
96
|
-
block.call
|
97
|
-
end
|
98
|
-
|
99
|
-
def extend_client(name, stage, extension, &block)
|
100
|
-
object = Object.new
|
101
|
-
(class << object; self; end).send(:define_method, stage, &extension)
|
102
|
-
@clients[name].add_extension(object)
|
103
|
-
block.call
|
104
|
-
end
|
105
|
-
|
106
|
-
def listen_for_errors(name, &block)
|
107
|
-
@errors[name] = []
|
108
|
-
errors = @errors
|
109
|
-
|
110
|
-
extend_client(name, :incoming, lambda { |message, callback|
|
111
|
-
if message['successful'] == false
|
112
|
-
errors[name] << message['error']
|
113
|
-
end
|
114
|
-
callback.call(message)
|
115
|
-
}, &block)
|
116
|
-
end
|
117
|
-
|
118
|
-
def setup_client(client, name, channels, &block)
|
119
|
-
@clients[name] = client
|
120
|
-
@inbox[name] = {}
|
121
|
-
@pool += 1
|
122
|
-
|
123
|
-
return block.call if channels.nil?
|
124
|
-
|
125
|
-
channels.each { |channel| subscribe(name, channel) }
|
126
|
-
EM.add_timer(0.5 * channels.size, &block)
|
127
|
-
end
|
128
|
-
|
129
|
-
def subscribe(name, channel, &block)
|
130
|
-
client = @clients[name]
|
131
|
-
|
132
|
-
@last_sub = client.subscribe(channel) do |message|
|
133
|
-
box = @inbox[name]
|
134
|
-
box[channel] ||= []
|
135
|
-
box[channel] << message
|
136
|
-
end
|
137
|
-
|
138
|
-
@last_sub.callback(&block)
|
139
|
-
end
|
140
|
-
|
141
|
-
def cancel_last_subscription(&block)
|
142
|
-
@last_sub.cancel
|
143
|
-
EM.add_timer(0.5, &block)
|
144
|
-
end
|
145
|
-
|
146
|
-
def publish(from, channel, messages, &block)
|
147
|
-
messages = [messages].flatten
|
148
|
-
messages.each { |msg| @clients[from].publish(channel, msg) }
|
149
|
-
EM.add_timer(2, &block)
|
150
|
-
end
|
151
|
-
|
152
|
-
def check_inbox(expected_inbox, &block)
|
153
|
-
assert_equal expected_inbox, @inbox
|
154
|
-
EM.next_tick(&block)
|
155
|
-
end
|
156
|
-
|
157
|
-
def check_errors(name, expected_errors, &block)
|
158
|
-
assert_equal expected_errors, @errors[name]
|
159
|
-
EM.next_tick(&block)
|
160
|
-
end
|
161
|
-
|
162
|
-
def finish(&block)
|
163
|
-
@clients.each { |id,c| c.disconnect }
|
164
|
-
EM.add_timer(1) do
|
165
|
-
@server.stop!
|
166
|
-
block.call
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
end
|
172
|
-
|
data/test/test_channel.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
require "test/unit"
|
2
|
-
require File.dirname(__FILE__) + "/../lib/faye"
|
3
|
-
|
4
|
-
class TestChannel < Test::Unit::TestCase
|
5
|
-
include Faye
|
6
|
-
|
7
|
-
def test_channel_storage
|
8
|
-
tree = Channel::Tree.new
|
9
|
-
tree['invalid/name'] = 1
|
10
|
-
tree['/valid/name'] = 2
|
11
|
-
tree['/va()$$lid/name'] = 3
|
12
|
-
|
13
|
-
assert_equal nil, tree['invalid/name']
|
14
|
-
assert_equal 2, tree['/valid/name']
|
15
|
-
assert_equal 3, tree['/va()$$lid/name']
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_keys
|
19
|
-
tree = Channel::Tree.new
|
20
|
-
tree['/foo'] = tree['/bar'] = tree['/foo/bar'] = true
|
21
|
-
assert_equal %w[/bar /foo /foo/bar], tree.keys.sort
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_removal
|
25
|
-
tree = Channel::Tree.new
|
26
|
-
tree['/foo'] = tree['/bar'] = tree['/foo/bar'] = true
|
27
|
-
|
28
|
-
tree.remove('/foo/bar')
|
29
|
-
assert_equal %w[/bar /foo], tree.keys.sort
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_globbing
|
33
|
-
tree = Channel::Tree.new
|
34
|
-
tree['/foo/bar'] = 1
|
35
|
-
tree['/foo/boo'] = 2
|
36
|
-
tree['/foo'] = 3
|
37
|
-
tree['/foobar'] = 4
|
38
|
-
tree['/foo/bar/boo'] = 5
|
39
|
-
tree['/foobar/boo'] = 6
|
40
|
-
tree['/foo/*'] = 7
|
41
|
-
tree['/foo/**'] = 8
|
42
|
-
|
43
|
-
assert_equal [1,2,7,8], tree.glob('/foo/*').sort
|
44
|
-
assert_equal [1,7,8], tree.glob('/foo/bar').sort
|
45
|
-
assert_equal [1,2,5,7,8], tree.glob('/foo/**').sort
|
46
|
-
assert_equal [5,8], tree.glob('/foo/bar/boo').sort
|
47
|
-
|
48
|
-
tree['/channels/hello'] = 'A'
|
49
|
-
tree['/channels/name'] = 'B'
|
50
|
-
tree['/channels/nested/hello'] = 'C'
|
51
|
-
|
52
|
-
assert_equal %w[A B C], tree.glob('/channels/**').sort
|
53
|
-
end
|
54
|
-
end
|
data/test/test_clients.rb
DELETED
@@ -1,381 +0,0 @@
|
|
1
|
-
require "test/unit"
|
2
|
-
require File.dirname(__FILE__) + "/../lib/faye"
|
3
|
-
require "test/scenario"
|
4
|
-
|
5
|
-
class TestClients < Test::Unit::TestCase
|
6
|
-
include Faye
|
7
|
-
include Scenario
|
8
|
-
|
9
|
-
scenario "Client modifies incoming messages" do
|
10
|
-
server 8000
|
11
|
-
http_client :A, ['/channels/a']
|
12
|
-
http_client :B, ['/channels/b']
|
13
|
-
|
14
|
-
extend_client :A, :incoming, lambda { |message, callback|
|
15
|
-
if message['data']
|
16
|
-
message['data']['modified'] = 'hi'
|
17
|
-
end
|
18
|
-
callback.call(message)
|
19
|
-
}
|
20
|
-
|
21
|
-
publish :B, '/channels/a', 'welcome' => 'message'
|
22
|
-
check_inbox(
|
23
|
-
:A => {
|
24
|
-
'/channels/a' => ['welcome' => 'message', 'modified' => 'hi']
|
25
|
-
},
|
26
|
-
:B => {}
|
27
|
-
)
|
28
|
-
end
|
29
|
-
|
30
|
-
scenario "Client blocks incoming messages" do
|
31
|
-
server 8000
|
32
|
-
http_client :A, ['/channels/a']
|
33
|
-
http_client :B, ['/channels/b']
|
34
|
-
|
35
|
-
extend_client :A, :incoming, lambda { |message, callback|
|
36
|
-
callback.call(nil)
|
37
|
-
}
|
38
|
-
|
39
|
-
publish :B, '/channels/a', 'welcome' => 'message'
|
40
|
-
check_inbox( :A => {}, :B => {} )
|
41
|
-
end
|
42
|
-
|
43
|
-
scenario "Server requires authentication" do
|
44
|
-
server 8000
|
45
|
-
http_client :A, ['/channels/a']
|
46
|
-
http_client :B, ['/channels/b']
|
47
|
-
|
48
|
-
extend_server :incoming, lambda { |message, callback|
|
49
|
-
if message['ext'] and message['ext']['password']
|
50
|
-
callback.call(message)
|
51
|
-
end
|
52
|
-
}
|
53
|
-
|
54
|
-
extend_client :B, :outgoing, lambda { |message, callback|
|
55
|
-
message['ext'] = {'password' => true}
|
56
|
-
callback.call(message)
|
57
|
-
}
|
58
|
-
|
59
|
-
publish :A, '/channels/b', 'message_for' => 'B'
|
60
|
-
check_inbox( :A => {}, :B => {} )
|
61
|
-
|
62
|
-
publish :B, '/channels/a', 'message_for' => 'A'
|
63
|
-
check_inbox(
|
64
|
-
:A => {
|
65
|
-
'/channels/a' => ['message_for' => 'A']
|
66
|
-
},
|
67
|
-
:B => {}
|
68
|
-
)
|
69
|
-
end
|
70
|
-
|
71
|
-
scenario "Server blocks a message by setting an error" do
|
72
|
-
server 8000
|
73
|
-
http_client :A, ['/channels/a']
|
74
|
-
http_client :B, ['/channels/b']
|
75
|
-
|
76
|
-
extend_server :incoming, lambda { |message, callback|
|
77
|
-
if message['data']
|
78
|
-
message['error'] = Faye::Error.ext_mismatch
|
79
|
-
end
|
80
|
-
callback.call(message)
|
81
|
-
}
|
82
|
-
|
83
|
-
listen_for_errors :A
|
84
|
-
|
85
|
-
publish :A, '/channels/b', 'message_for' => 'B'
|
86
|
-
check_inbox( :A => {}, :B => {} )
|
87
|
-
check_errors :A, ['302::Extension mismatch']
|
88
|
-
end
|
89
|
-
|
90
|
-
scenario "Server modifies outgoing message" do
|
91
|
-
server 8000
|
92
|
-
http_client :A, []
|
93
|
-
http_client :B, ['/channels/b']
|
94
|
-
|
95
|
-
extend_server :outgoing, lambda { |message, callback|
|
96
|
-
message['data']['addition'] = 56 if message['data']
|
97
|
-
callback.call(message)
|
98
|
-
}
|
99
|
-
|
100
|
-
publish :A, '/channels/b', 'message_for' => 'B'
|
101
|
-
check_inbox(
|
102
|
-
:A => {},
|
103
|
-
:B => {
|
104
|
-
'/channels/b' => ['message_for' => 'B', 'addition' => 56]
|
105
|
-
}
|
106
|
-
)
|
107
|
-
end
|
108
|
-
|
109
|
-
[:incoming, :outgoing].each do |direction|
|
110
|
-
scenario "Server delays #{ direction } message" do
|
111
|
-
server 8000
|
112
|
-
http_client :A, []
|
113
|
-
http_client :B, ['/channels/b']
|
114
|
-
|
115
|
-
extend_server direction, lambda { |message, callback|
|
116
|
-
timeout = message['data'] ? 5 : 0
|
117
|
-
EM.add_timer(timeout) { callback.call(message) }
|
118
|
-
}
|
119
|
-
|
120
|
-
publish :A, '/channels/b', 'message_for' => 'B'
|
121
|
-
check_inbox( :A => {}, :B => {} )
|
122
|
-
|
123
|
-
wait 3
|
124
|
-
check_inbox( :A => {}, :B => {} )
|
125
|
-
|
126
|
-
wait 1
|
127
|
-
|
128
|
-
check_inbox(
|
129
|
-
:A => {},
|
130
|
-
:B => {
|
131
|
-
'/channels/b' => ['message_for' => 'B']
|
132
|
-
}
|
133
|
-
)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
scenario "Server blocks outgoing message" do
|
138
|
-
server 8000
|
139
|
-
http_client :A, []
|
140
|
-
http_client :B, ['/channels/b']
|
141
|
-
|
142
|
-
extend_server :outgoing, lambda { |message, callback|
|
143
|
-
if !message['data'] or message['data']['deliver'] == 'yes'
|
144
|
-
callback.call(message)
|
145
|
-
else
|
146
|
-
callback.call(nil)
|
147
|
-
end
|
148
|
-
}
|
149
|
-
|
150
|
-
publish :A, '/channels/b', [{'deliver' => 'no'}, {'deliver' => 'yes'}]
|
151
|
-
|
152
|
-
check_inbox(
|
153
|
-
:A => {},
|
154
|
-
:B => {
|
155
|
-
'/channels/b' => ['deliver' => 'yes']
|
156
|
-
}
|
157
|
-
)
|
158
|
-
end
|
159
|
-
|
160
|
-
scenario "Two HTTP clients, no messages delivered" do
|
161
|
-
server 8000
|
162
|
-
http_client :A, ['/channels/a']
|
163
|
-
http_client :B, []
|
164
|
-
publish :B, '/channels/b', 'hello' => 'world'
|
165
|
-
check_inbox(
|
166
|
-
:A => {},
|
167
|
-
:B => {}
|
168
|
-
)
|
169
|
-
end
|
170
|
-
|
171
|
-
scenario "Two HTTP clients, single subscription" do
|
172
|
-
server 8000
|
173
|
-
http_client :A, ['/channels/a']
|
174
|
-
http_client :B, []
|
175
|
-
publish :B, '/channels/a', 'hello' => 'world'
|
176
|
-
check_inbox(
|
177
|
-
:A => {
|
178
|
-
'/channels/a' => ['hello' => 'world']
|
179
|
-
},
|
180
|
-
:B => {}
|
181
|
-
)
|
182
|
-
end
|
183
|
-
|
184
|
-
scenario "Two HTTP clients, two identical messages sent together" do
|
185
|
-
server 8000
|
186
|
-
http_client :A, ['/channels/a']
|
187
|
-
http_client :B, []
|
188
|
-
publish :B, '/channels/a', [{'hello' => 'world'}, {'hello' => 'world'}]
|
189
|
-
check_inbox(
|
190
|
-
:A => {
|
191
|
-
'/channels/a' => [{'hello' => 'world'}, {'hello' => 'world'}]
|
192
|
-
},
|
193
|
-
:B => {}
|
194
|
-
)
|
195
|
-
end
|
196
|
-
|
197
|
-
scenario "Two HTTP clients, two message deliveries" do
|
198
|
-
server 8000
|
199
|
-
http_client :A, ['/channels/a']
|
200
|
-
http_client :B, []
|
201
|
-
publish :B, '/channels/a', 'hello' => 'world'
|
202
|
-
check_inbox(
|
203
|
-
:A => {
|
204
|
-
'/channels/a' => ['hello' => 'world']
|
205
|
-
},
|
206
|
-
:B => {}
|
207
|
-
)
|
208
|
-
wait 1
|
209
|
-
publish :B, '/channels/a', 'hello' => 'world'
|
210
|
-
check_inbox(
|
211
|
-
:A => {
|
212
|
-
'/channels/a' => [{'hello' => 'world'}, {'hello' => 'world'}]
|
213
|
-
},
|
214
|
-
:B => {}
|
215
|
-
)
|
216
|
-
end
|
217
|
-
|
218
|
-
scenario "Two HTTP clients, multiple subscriptions" do
|
219
|
-
server 8000
|
220
|
-
http_client :A, ['/channels/a', '/channels/*']
|
221
|
-
http_client :B, []
|
222
|
-
publish :B, '/channels/a', 'hello' => 'world'
|
223
|
-
check_inbox(
|
224
|
-
:A => {
|
225
|
-
'/channels/a' => ['hello' => 'world'],
|
226
|
-
'/channels/*' => ['hello' => 'world']
|
227
|
-
},
|
228
|
-
:B => {}
|
229
|
-
)
|
230
|
-
end
|
231
|
-
|
232
|
-
scenario "One HTTP client, one local with no subscriptions" do
|
233
|
-
server 8000
|
234
|
-
http_client :A, ['/channels/a']
|
235
|
-
local_client :B
|
236
|
-
publish :B, '/channels/a', 'hello' => 'world'
|
237
|
-
|
238
|
-
check_inbox(
|
239
|
-
:A => {
|
240
|
-
'/channels/a' => ['hello' => 'world']
|
241
|
-
},
|
242
|
-
:B => {}
|
243
|
-
)
|
244
|
-
end
|
245
|
-
|
246
|
-
scenario "Two HTTP clients, two subscriptions on the same channel" do
|
247
|
-
server 8000
|
248
|
-
http_client :A, ['/channels/a']
|
249
|
-
http_client :B, []
|
250
|
-
subscribe :A, '/channels/a'
|
251
|
-
publish :B, '/channels/a', 'hello' => 'world'
|
252
|
-
check_inbox(
|
253
|
-
:A => {
|
254
|
-
'/channels/a' => [{'hello' => 'world'}, {'hello' => 'world'}]
|
255
|
-
},
|
256
|
-
:B => {}
|
257
|
-
)
|
258
|
-
end
|
259
|
-
|
260
|
-
scenario "Two HTTP clients, two subscriptions and one unsubscription" do
|
261
|
-
server 8000
|
262
|
-
http_client :A, ['/channels/a']
|
263
|
-
http_client :B, []
|
264
|
-
subscribe :A, '/channels/a'
|
265
|
-
cancel_last_subscription
|
266
|
-
publish :B, '/channels/a', 'another' => 'message'
|
267
|
-
check_inbox(
|
268
|
-
:A => {
|
269
|
-
'/channels/a' => [{'another' => 'message'}]
|
270
|
-
},
|
271
|
-
:B => {}
|
272
|
-
)
|
273
|
-
end
|
274
|
-
|
275
|
-
scenario "Three HTTP clients, single receiver" do
|
276
|
-
server 8000
|
277
|
-
http_client :A, ['/channels/a']
|
278
|
-
http_client :B, []
|
279
|
-
http_client :C, ['/channels/c']
|
280
|
-
publish :B, '/channels/a', 'chunky' => 'bacon'
|
281
|
-
check_inbox(
|
282
|
-
:A => {
|
283
|
-
'/channels/a' => ['chunky' => 'bacon']
|
284
|
-
},
|
285
|
-
:B => {},
|
286
|
-
:C => {}
|
287
|
-
)
|
288
|
-
end
|
289
|
-
|
290
|
-
scenario "Three HTTP clients, multiple receivers" do
|
291
|
-
server 8000
|
292
|
-
http_client :A, ['/channels/shared']
|
293
|
-
http_client :B, []
|
294
|
-
http_client :C, ['/channels/shared']
|
295
|
-
publish :B, '/channels/shared', 'chunky' => 'bacon'
|
296
|
-
check_inbox(
|
297
|
-
:A => {
|
298
|
-
'/channels/shared' => ['chunky' => 'bacon']
|
299
|
-
},
|
300
|
-
:B => {},
|
301
|
-
:C => {
|
302
|
-
'/channels/shared' => ['chunky' => 'bacon']
|
303
|
-
}
|
304
|
-
)
|
305
|
-
end
|
306
|
-
|
307
|
-
scenario "Two HTTP clients, single wildcard on receiver" do
|
308
|
-
server 8000
|
309
|
-
http_client :A, ['/channels/*']
|
310
|
-
http_client :B, []
|
311
|
-
publish :B, '/channels/anything', 'msg' => 'hey'
|
312
|
-
check_inbox(
|
313
|
-
:A => {
|
314
|
-
'/channels/*' => ['msg' => 'hey']
|
315
|
-
},
|
316
|
-
:B => {}
|
317
|
-
)
|
318
|
-
end
|
319
|
-
|
320
|
-
scenario "Two HTTP clients, single wildcard on sender" do
|
321
|
-
server 8000
|
322
|
-
http_client :A, ['/channels/name', '/channels/hello', '/channels/nested/hello']
|
323
|
-
http_client :B, []
|
324
|
-
publish :B, '/channels/*', 'msg' => 'hey'
|
325
|
-
check_inbox(
|
326
|
-
:A => {
|
327
|
-
'/channels/name' => ['msg' => 'hey'],
|
328
|
-
'/channels/hello' => ['msg' => 'hey']
|
329
|
-
},
|
330
|
-
:B => {}
|
331
|
-
)
|
332
|
-
end
|
333
|
-
|
334
|
-
scenario "Two HTTP clients, single wildcard on both" do
|
335
|
-
server 8000
|
336
|
-
http_client :A, ['/channels/*']
|
337
|
-
http_client :B, []
|
338
|
-
publish :B, '/channels/*', 'msg' => 'hey'
|
339
|
-
check_inbox(
|
340
|
-
:A => {
|
341
|
-
'/channels/*' => ['msg' => 'hey']
|
342
|
-
},
|
343
|
-
:B => {}
|
344
|
-
)
|
345
|
-
end
|
346
|
-
|
347
|
-
scenario "Two local clients, double wildcard on sender" do
|
348
|
-
server 8000
|
349
|
-
local_client :A, ['/channels/name', '/channels/hello', '/channels/nested/hello']
|
350
|
-
local_client :B, []
|
351
|
-
publish :B, '/channels/**', 'msg' => 'hey'
|
352
|
-
check_inbox(
|
353
|
-
:A => {
|
354
|
-
'/channels/name' => ['msg' => 'hey'],
|
355
|
-
'/channels/hello' => ['msg' => 'hey'],
|
356
|
-
'/channels/nested/hello' => ['msg' => 'hey']
|
357
|
-
},
|
358
|
-
:B => {}
|
359
|
-
)
|
360
|
-
end
|
361
|
-
|
362
|
-
scenario "Two local clients, one HTTP, double wildcard on sender and one subscription" do
|
363
|
-
server 8000
|
364
|
-
local_client :A, ['/channels/hello', '/channels/nested/hello']
|
365
|
-
local_client :B, []
|
366
|
-
http_client :C, ['/channels/name', '/channels/foo/**']
|
367
|
-
publish :B, '/channels/**', 'msg' => 'hey'
|
368
|
-
check_inbox(
|
369
|
-
:A => {
|
370
|
-
'/channels/hello' => ['msg' => 'hey'],
|
371
|
-
'/channels/nested/hello' => ['msg' => 'hey']
|
372
|
-
},
|
373
|
-
:B => {},
|
374
|
-
:C => {
|
375
|
-
'/channels/name' => ['msg' => 'hey'],
|
376
|
-
'/channels/foo/**' => ['msg' => 'hey']
|
377
|
-
}
|
378
|
-
)
|
379
|
-
end
|
380
|
-
end
|
381
|
-
|