bushido-faye 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/History.txt +247 -0
  2. data/README.rdoc +92 -0
  3. data/lib/faye-browser-min.js +1 -0
  4. data/lib/faye.rb +121 -0
  5. data/lib/faye/adapters/rack_adapter.rb +209 -0
  6. data/lib/faye/engines/connection.rb +60 -0
  7. data/lib/faye/engines/memory.rb +112 -0
  8. data/lib/faye/engines/proxy.rb +111 -0
  9. data/lib/faye/error.rb +49 -0
  10. data/lib/faye/mixins/logging.rb +47 -0
  11. data/lib/faye/mixins/publisher.rb +30 -0
  12. data/lib/faye/mixins/timeouts.rb +22 -0
  13. data/lib/faye/protocol/channel.rb +124 -0
  14. data/lib/faye/protocol/client.rb +378 -0
  15. data/lib/faye/protocol/extensible.rb +43 -0
  16. data/lib/faye/protocol/grammar.rb +58 -0
  17. data/lib/faye/protocol/publication.rb +5 -0
  18. data/lib/faye/protocol/server.rb +282 -0
  19. data/lib/faye/protocol/subscription.rb +24 -0
  20. data/lib/faye/transport/http.rb +76 -0
  21. data/lib/faye/transport/local.rb +22 -0
  22. data/lib/faye/transport/transport.rb +115 -0
  23. data/lib/faye/transport/web_socket.rb +99 -0
  24. data/lib/faye/util/namespace.rb +20 -0
  25. data/spec/browser.html +45 -0
  26. data/spec/encoding_helper.rb +7 -0
  27. data/spec/install.sh +78 -0
  28. data/spec/javascript/channel_spec.js +15 -0
  29. data/spec/javascript/client_spec.js +714 -0
  30. data/spec/javascript/engine/memory_spec.js +7 -0
  31. data/spec/javascript/engine_spec.js +417 -0
  32. data/spec/javascript/faye_spec.js +15 -0
  33. data/spec/javascript/grammar_spec.js +66 -0
  34. data/spec/javascript/node_adapter_spec.js +307 -0
  35. data/spec/javascript/publisher_spec.js +27 -0
  36. data/spec/javascript/server/connect_spec.js +168 -0
  37. data/spec/javascript/server/disconnect_spec.js +121 -0
  38. data/spec/javascript/server/extensions_spec.js +60 -0
  39. data/spec/javascript/server/handshake_spec.js +145 -0
  40. data/spec/javascript/server/integration_spec.js +124 -0
  41. data/spec/javascript/server/publish_spec.js +85 -0
  42. data/spec/javascript/server/subscribe_spec.js +247 -0
  43. data/spec/javascript/server/unsubscribe_spec.js +245 -0
  44. data/spec/javascript/server_spec.js +110 -0
  45. data/spec/javascript/transport_spec.js +130 -0
  46. data/spec/node.js +55 -0
  47. data/spec/phantom.js +17 -0
  48. data/spec/ruby/channel_spec.rb +17 -0
  49. data/spec/ruby/client_spec.rb +724 -0
  50. data/spec/ruby/engine/memory_spec.rb +7 -0
  51. data/spec/ruby/engine_examples.rb +427 -0
  52. data/spec/ruby/faye_spec.rb +14 -0
  53. data/spec/ruby/grammar_spec.rb +68 -0
  54. data/spec/ruby/publisher_spec.rb +27 -0
  55. data/spec/ruby/rack_adapter_spec.rb +236 -0
  56. data/spec/ruby/server/connect_spec.rb +170 -0
  57. data/spec/ruby/server/disconnect_spec.rb +120 -0
  58. data/spec/ruby/server/extensions_spec.rb +68 -0
  59. data/spec/ruby/server/handshake_spec.rb +143 -0
  60. data/spec/ruby/server/integration_spec.rb +126 -0
  61. data/spec/ruby/server/publish_spec.rb +81 -0
  62. data/spec/ruby/server/subscribe_spec.rb +247 -0
  63. data/spec/ruby/server/unsubscribe_spec.rb +247 -0
  64. data/spec/ruby/server_spec.rb +110 -0
  65. data/spec/ruby/transport_spec.rb +134 -0
  66. data/spec/spec_helper.rb +11 -0
  67. data/spec/testswarm +29 -0
  68. data/spec/thin_proxy.rb +37 -0
  69. metadata +302 -0
@@ -0,0 +1,7 @@
1
+ require "spec_helper"
2
+
3
+ describe Faye::Engine::Memory do
4
+ let(:engine_opts) { {:type => Faye::Engine::Memory} }
5
+ it_should_behave_like "faye engine"
6
+ end
7
+
@@ -0,0 +1,427 @@
1
+ # encoding=utf-8
2
+
3
+ root = File.expand_path('../../..', __FILE__)
4
+
5
+ require root + '/vendor/em-rspec/lib/em-rspec'
6
+ require root + '/spec/encoding_helper'
7
+
8
+ require root + '/lib/faye/mixins/logging'
9
+ require root + '/lib/faye/mixins/publisher'
10
+ require root + '/lib/faye/mixins/timeouts'
11
+
12
+ require root + '/lib/faye/protocol/channel'
13
+ require root + '/lib/faye/protocol/grammar'
14
+ require root + '/lib/faye/engines/proxy'
15
+
16
+ EngineSteps = EM::RSpec.async_steps do
17
+ def create_client(name, &resume)
18
+ @inboxes ||= {}
19
+ @clients ||= {}
20
+ engine.create_client do |client_id|
21
+ @clients[name] = client_id
22
+ @inboxes[name] ||= []
23
+ resume.call
24
+ end
25
+ end
26
+
27
+ def connect(name, engine, &resume)
28
+ engine.connect(@clients[name]) do |m|
29
+ m.each do |message|
30
+ message.delete("id")
31
+ @inboxes[name] << message
32
+ end
33
+ end
34
+ EM.add_timer(0.01, &resume)
35
+ end
36
+
37
+ def destroy_client(name, &resume)
38
+ engine.destroy_client(@clients[name], &resume)
39
+ end
40
+
41
+ def check_client_id(name, pattern, &resume)
42
+ @clients[name].should =~ pattern
43
+ resume.call
44
+ end
45
+
46
+ def check_num_clients(n, &resume)
47
+ ids = Set.new
48
+ @clients.each { |name,id| ids.add(id) }
49
+ ids.size.should == n
50
+ resume.call
51
+ end
52
+
53
+ def check_client_exists(name, exists, &resume)
54
+ engine.client_exists(@clients[name]) do |actual|
55
+ actual.should == exists
56
+ resume.call
57
+ end
58
+ end
59
+
60
+ def subscribe(name, channel, &resume)
61
+ engine.subscribe(@clients[name], channel, &resume)
62
+ end
63
+
64
+ def unsubscribe(name, channel, &resume)
65
+ engine.unsubscribe(@clients[name], channel, &resume)
66
+ end
67
+
68
+ def publish(messages, &resume)
69
+ messages = [messages].flatten
70
+ messages.each do |message|
71
+ message = {"id" => Faye::Engine.random}.merge(message)
72
+ engine.publish(message)
73
+ end
74
+ EM.add_timer(0.01, &resume)
75
+ end
76
+
77
+ def publish_by(name, message, &resume)
78
+ message = {"clientId" => @clients[name], "id" => Faye::Engine.random}.merge(message)
79
+ engine.publish(message)
80
+ EM.add_timer(0.01, &resume)
81
+ end
82
+
83
+ def ping(name, &resume)
84
+ engine.ping(@clients[name])
85
+ resume.call
86
+ end
87
+
88
+ def clock_tick(time, &resume)
89
+ clock.tick(time)
90
+ resume.call
91
+ end
92
+
93
+ def expect_event(name, event, args, &resume)
94
+ params = [@clients[name]] + args
95
+ handler = lambda { |*a| }
96
+ engine.bind(event, &handler)
97
+ handler.should_receive(:call).with(*params)
98
+ resume.call
99
+ end
100
+
101
+ def expect_no_event(name, event, args, &resume)
102
+ params = [@clients[name]] + args
103
+ handler = lambda { |*a| }
104
+ engine.bind(event, &handler)
105
+ handler.should_not_receive(:call).with(*params)
106
+ resume.call
107
+ end
108
+
109
+ def expect_message(name, messages, &resume)
110
+ @inboxes[name].should == messages
111
+ resume.call
112
+ end
113
+
114
+ def expect_no_message(name, &resume)
115
+ @inboxes[name].should == []
116
+ resume.call
117
+ end
118
+
119
+ def check_different_messages(a, b, &resume)
120
+ @inboxes[a].first.should_not be_equal(@inboxes[b].first)
121
+ resume.call
122
+ end
123
+ end
124
+
125
+ describe "Pub/sub engines" do
126
+ shared_examples_for "faye engine" do
127
+ include EncodingHelper
128
+ include EngineSteps
129
+
130
+ def create_engine
131
+ opts = options.merge(engine_opts)
132
+ Faye::Engine::Proxy.new(opts)
133
+ end
134
+
135
+ let(:options) { {:timeout => 1} }
136
+ let(:engine) { create_engine }
137
+
138
+ before do
139
+ Faye.stub(:logger)
140
+ Faye::Engine.ensure_reactor_running!
141
+ create_client :alice
142
+ create_client :bob
143
+ create_client :carol
144
+ end
145
+
146
+ describe :create_client do
147
+ it "returns a client id" do
148
+ create_client :dave
149
+ check_client_id :dave, /^[a-z0-9]+$/
150
+ end
151
+
152
+ it "returns a different id every time" do
153
+ 1.upto(7) { |i| create_client "client#{i}" }
154
+ check_num_clients 10
155
+ end
156
+
157
+ it "publishes an event" do
158
+ engine.should_receive(:trigger).with(:handshake, match(/^[a-z0-9]+$/)).exactly(4)
159
+ create_client :dave
160
+ end
161
+ end
162
+
163
+ describe :client_exists do
164
+ it "returns true if the client id exists" do
165
+ check_client_exists :alice, true
166
+ end
167
+
168
+ it "returns false if the client id does not exist" do
169
+ check_client_exists :anything, false
170
+ end
171
+ end
172
+ =begin
173
+ describe :ping do
174
+ it "removes a client if it does not ping often enough" do
175
+ clock_tick 2
176
+ check_client_exists :alice, false
177
+ end
178
+
179
+ it "prolongs the life of a client" do
180
+ clock_tick 1
181
+ ping :alice
182
+ clock_tick 1
183
+ check_client_exists :alice, true
184
+ clock_tick 1
185
+ check_client_exists :alice, false
186
+ end
187
+ end
188
+ =end
189
+ describe :destroy_client do
190
+ it "removes the given client" do
191
+ destroy_client :alice
192
+ check_client_exists :alice, false
193
+ end
194
+
195
+ it "publishes an event" do
196
+ expect_event :alice, :disconnect, []
197
+ destroy_client :alice
198
+ end
199
+
200
+ describe "when the client has subscriptions" do
201
+ before do
202
+ @message = {"channel" => "/messages/foo", "data" => "ok"}
203
+ subscribe :alice, "/messages/foo"
204
+ end
205
+
206
+ it "stops the client receiving messages" do
207
+ connect :alice, engine
208
+ destroy_client :alice
209
+ publish @message
210
+ expect_no_message :alice
211
+ end
212
+
213
+ it "publishes an event" do
214
+ expect_event :alice, :disconnect, []
215
+ destroy_client :alice
216
+ end
217
+ end
218
+ end
219
+
220
+ describe :subscribe do
221
+ it "publishes an event" do
222
+ expect_event :alice, :subscribe, ["/messages/foo"]
223
+ subscribe :alice, "/messages/foo"
224
+ end
225
+
226
+ describe "when the client is subscribed to the channel" do
227
+ before { subscribe :alice, "/messages/foo" }
228
+
229
+ it "does not publish an event" do
230
+ expect_no_event :alice, :subscribe, ["/messages/foo"]
231
+ subscribe :alice, "/messages/foo"
232
+ end
233
+ end
234
+ end
235
+
236
+ describe :unsubscribe do
237
+ before { subscribe :alice, "/messages/bar" }
238
+
239
+ it "does not publish an event" do
240
+ expect_no_event :alice, :unsubscribe, ["/messages/foo"]
241
+ unsubscribe :alice, "/messages/foo"
242
+ end
243
+
244
+ describe "when the client is subscribed to the channel" do
245
+ before { subscribe :alice, "/messages/foo" }
246
+
247
+ it "publishes an event" do
248
+ expect_event :alice, :unsubscribe, ["/messages/foo"]
249
+ unsubscribe :alice, "/messages/foo"
250
+ end
251
+ end
252
+ end
253
+
254
+ describe :publish do
255
+ before do
256
+ @message = {"channel" => "/messages/foo", "data" => "ok"}
257
+ connect :alice, engine
258
+ connect :bob, engine
259
+ connect :carol, engine
260
+ end
261
+
262
+ describe "with no subscriptions" do
263
+ it "delivers no messages" do
264
+ publish @message
265
+ expect_no_message :alice
266
+ expect_no_message :bob
267
+ expect_no_message :carol
268
+ end
269
+
270
+ it "publishes a :publish event with a clientId" do
271
+ expect_event :bob, :publish, ["/messages/foo", "ok"]
272
+ publish_by :bob, @message
273
+ end
274
+
275
+ it "publishes a :publish event with no clientId" do
276
+ expect_event nil, :publish, ["/messages/foo", "ok"]
277
+ publish @message
278
+ end
279
+ end
280
+
281
+ describe "with a subscriber" do
282
+ before { subscribe :alice, "/messages/foo" }
283
+
284
+ it "delivers messages to the subscribed client" do
285
+ publish @message
286
+ expect_message :alice, [@message]
287
+ end
288
+
289
+ it "delivers multibyte messages correctly" do
290
+ @message["data"] = encode "Apple = "
291
+ publish @message
292
+ expect_message :alice, [@message]
293
+ end
294
+
295
+ it "publishes a :publish event" do
296
+ expect_event :bob, :publish, ["/messages/foo", "ok"]
297
+ publish_by :bob, @message
298
+ end
299
+ end
300
+
301
+ describe "with a subscriber that is removed" do
302
+ before do
303
+ subscribe :alice, "/messages/foo"
304
+ unsubscribe :alice, "/messages/foo"
305
+ end
306
+
307
+ it "does not deliver messages to unsubscribed clients" do
308
+ publish @message
309
+ expect_no_message :alice
310
+ expect_no_message :bob
311
+ expect_no_message :carol
312
+ end
313
+
314
+ it "publishes a :publish event" do
315
+ expect_event :bob, :publish, ["/messages/foo", "ok"]
316
+ publish_by :bob, @message
317
+ end
318
+ end
319
+
320
+ describe "with multiple subscribers" do
321
+ before do
322
+ subscribe :alice, "/messages/foo"
323
+ subscribe :bob, "/messages/bar"
324
+ subscribe :carol, "/messages/foo"
325
+ end
326
+
327
+ it "delivers messages to the subscribed clients" do
328
+ publish @message
329
+ expect_message :alice, [@message]
330
+ expect_no_message :bob
331
+ expect_message :carol, [@message]
332
+ end
333
+ end
334
+
335
+ describe "with a single wildcard" do
336
+ before do
337
+ subscribe :alice, "/messages/*"
338
+ subscribe :bob, "/messages/bar"
339
+ subscribe :carol, "/*"
340
+ end
341
+
342
+ it "delivers messages to matching subscriptions" do
343
+ publish @message
344
+ expect_message :alice, [@message]
345
+ expect_no_message :bob
346
+ expect_no_message :carol
347
+ end
348
+ end
349
+
350
+ describe "with a double wildcard" do
351
+ before do
352
+ subscribe :alice, "/messages/**"
353
+ subscribe :bob, "/messages/bar"
354
+ subscribe :carol, "/**"
355
+ end
356
+
357
+ it "delivers messages to matching subscriptions" do
358
+ publish @message
359
+ expect_message :alice, [@message]
360
+ expect_no_message :bob
361
+ expect_message :carol, [@message]
362
+ end
363
+
364
+ it "delivers a unique copy of the message to each client" do
365
+ publish @message
366
+ check_different_messages :alice, :carol
367
+ end
368
+ end
369
+
370
+ describe "with multiple matching subscriptions for the same client" do
371
+ before do
372
+ subscribe :alice, "/messages/foo"
373
+ subscribe :alice, "/messages/*"
374
+ end
375
+
376
+ it "delivers each message once to each client" do
377
+ publish @message
378
+ expect_message :alice, [@message]
379
+ end
380
+
381
+ it "delivers the message as many times as it is published" do
382
+ publish [@message, @message]
383
+ expect_message :alice, [@message, @message]
384
+ end
385
+ end
386
+ end
387
+ end
388
+
389
+ shared_examples_for "distributed engine" do
390
+ include EngineSteps
391
+
392
+ def create_engine
393
+ opts = options.merge(engine_opts)
394
+ Faye::Engine::Proxy.new(opts)
395
+ end
396
+
397
+ let(:options) { {} }
398
+ let(:left) { create_engine }
399
+ let(:right) { create_engine }
400
+
401
+ alias :engine :left
402
+
403
+ before do
404
+ Faye.stub(:logger)
405
+ Faye::Engine.ensure_reactor_running!
406
+ create_client :alice
407
+ create_client :bob
408
+
409
+ connect :alice, left
410
+ end
411
+
412
+ describe :publish do
413
+ before do
414
+ subscribe :alice, "/foo"
415
+ publish "channel" => "/foo", "data" => "first"
416
+ end
417
+
418
+ it "only delivers each message once" do
419
+ expect_message :alice, ["channel" => "/foo", "data" => "first"]
420
+ publish "channel" => "/foo", "data" => "second"
421
+ connect :alice, right
422
+ expect_message :alice, [{"channel" => "/foo", "data" => "first"}, {"channel" => "/foo", "data" => "second"}]
423
+ end
424
+ end
425
+ end
426
+ end
427
+
@@ -0,0 +1,14 @@
1
+ require "spec_helper"
2
+
3
+ describe Faye do
4
+ describe :random do
5
+ it "returns a 128-bit random number in base 36" do
6
+ Faye.random.should =~ /^[a-z0-9]+$/
7
+ end
8
+
9
+ it "always produces the same length of string" do
10
+ ids = (1..100).map { Faye.random }
11
+ ids.should be_all { |id| id.size == 25 }
12
+ end
13
+ end
14
+ end