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,121 @@
1
+ JS.ENV.Server.DisconnectSpec = JS.Test.describe("Server disconnect", function() { with(this) {
2
+ before(function() { with(this) {
3
+ this.engine = {}
4
+ stub(Faye.Engine, "get").returns(engine)
5
+ this.server = new Faye.Server()
6
+ }})
7
+
8
+ describe("#disconnect", function() { with(this) {
9
+ before(function() { with(this) {
10
+ this.clientId = "fakeclientid"
11
+ this.message = {channel: "/meta/disconnect",
12
+ clientId: "fakeclientid"}
13
+ }})
14
+
15
+ describe("with valid parameters", function() { with(this) {
16
+ before(function() { with(this) {
17
+ expect(engine, "clientExists").given(clientId).yielding([true])
18
+ }})
19
+
20
+ it("destroys the client", function() { with(this) {
21
+ expect(engine, "destroyClient").given(clientId)
22
+ server.disconnect(message, false, function() {})
23
+ }})
24
+
25
+ it("returns a successful response", function() { with(this) {
26
+ stub(engine, "destroyClient")
27
+ server.disconnect(message, false, function(response) {
28
+ assertEqual({
29
+ channel: "/meta/disconnect",
30
+ successful: true,
31
+ clientId: clientId
32
+ }, response)
33
+ })
34
+ }})
35
+
36
+ describe("with a message id", function() { with(this) {
37
+ before(function() { this.message.id = "foo" })
38
+
39
+ it("returns the same id", function() { with(this) {
40
+ stub(engine, "destroyClient")
41
+ server.disconnect(message, false, function(response) {
42
+ assertEqual({
43
+ channel: "/meta/disconnect",
44
+ successful: true,
45
+ clientId: clientId,
46
+ id: "foo"
47
+ }, response)
48
+ })
49
+ }})
50
+ }})
51
+ }})
52
+
53
+ describe("with an unknown client", function() { with(this) {
54
+ before(function() { with(this) {
55
+ expect(engine, "clientExists").given(clientId).yielding([false])
56
+ }})
57
+
58
+ it("does not destroy the client", function() { with(this) {
59
+ expect(engine, "destroyClient").exactly(0)
60
+ server.disconnect(message, false, function() {})
61
+ }})
62
+
63
+ it("returns an unsuccessful response", function() { with(this) {
64
+ stub(engine, "destroyClient")
65
+ server.disconnect(message, false, function(response) {
66
+ assertEqual({
67
+ channel: "/meta/disconnect",
68
+ successful: false,
69
+ error: "401:fakeclientid:Unknown client"
70
+ }, response)
71
+ })
72
+ }})
73
+ }})
74
+
75
+ describe("missing clientId", function() { with(this) {
76
+ before(function() { with(this) {
77
+ delete message.clientId
78
+ expect(engine, "clientExists").given(undefined).yielding([false])
79
+ }})
80
+
81
+ it("does not destroy the client", function() { with(this) {
82
+ expect(engine, "destroyClient").exactly(0)
83
+ server.disconnect(message, false, function() {})
84
+ }})
85
+
86
+ it("returns an unsuccessful response", function() { with(this) {
87
+ stub(engine, "destroyClient")
88
+ server.disconnect(message, false, function(response) {
89
+ assertEqual({
90
+ channel: "/meta/disconnect",
91
+ successful: false,
92
+ error: "402:clientId:Missing required parameter"
93
+ }, response)
94
+ })
95
+ }})
96
+ }})
97
+
98
+ describe("with an error", function() { with(this) {
99
+ before(function() { with(this) {
100
+ message.error = "invalid"
101
+ expect(engine, "clientExists").given(clientId).yielding([true])
102
+ }})
103
+
104
+ it("does not destroy the client", function() { with(this) {
105
+ expect(engine, "destroyClient").exactly(0)
106
+ server.disconnect(message, false, function() {})
107
+ }})
108
+
109
+ it("returns an unsuccessful response", function() { with(this) {
110
+ stub(engine, "destroyClient")
111
+ server.disconnect(message, false, function(response) {
112
+ assertEqual({
113
+ channel: "/meta/disconnect",
114
+ successful: false,
115
+ error: "invalid"
116
+ }, response)
117
+ })
118
+ }})
119
+ }})
120
+ }})
121
+ }})
@@ -0,0 +1,60 @@
1
+ JS.ENV.Server.ExtensionsSpec = JS.Test.describe("Server extensions", function() { with(this) {
2
+ before(function() { with(this) {
3
+ this.engine = {}
4
+ stub(Faye.Engine, "get").returns(engine)
5
+ this.server = new Faye.Server()
6
+ }})
7
+
8
+ describe("with an incoming extension installed", function() { with(this) {
9
+ before(function() { with(this) {
10
+ var extension = {
11
+ incoming: function(message, callback) {
12
+ message.ext = {auth: "password"}
13
+ callback(message)
14
+ }
15
+ }
16
+ server.addExtension(extension)
17
+ this.message = {channel: "/foo", data: "hello"}
18
+ }})
19
+
20
+ it("passes incoming messages through the extension", function() { with(this) {
21
+ expect(engine, "publish").given({channel: "/foo", data: "hello", ext: {auth: "password"}})
22
+ server.process(message, false, function() {})
23
+ }})
24
+
25
+ it("does not pass outgoing messages through the extension", function() { with(this) {
26
+ stub(server, "handshake").yields([message])
27
+ stub(engine, "publish")
28
+ var response = null
29
+ server.process({channel: "/meta/handshake"}, false, function(r) { response = r })
30
+ assertEqual( [{channel: "/foo", data: "hello"}], response )
31
+ }})
32
+ }})
33
+
34
+ describe("with an outgoing extension installed", function() { with(this) {
35
+ before(function() { with(this) {
36
+ var extension = {
37
+ outgoing: function(message, callback) {
38
+ message.ext = {auth: "password"}
39
+ callback(message)
40
+ }
41
+ }
42
+ server.addExtension(extension)
43
+ this.message = {channel: "/foo", data: "hello"}
44
+ }})
45
+
46
+ it("does not pass incoming messages through the extension", function() { with(this) {
47
+ expect(engine, "publish").given({channel: "/foo", data: "hello"})
48
+ server.process(message, false, function() {})
49
+ }})
50
+
51
+ it("passes outgoing messages through the extension", function() { with(this) {
52
+ stub(server, "handshake").yields([message])
53
+ stub(engine, "publish")
54
+ var response = null
55
+ server.process({channel: "/meta/handshake"}, false, function(r) { response = r })
56
+ assertEqual( [{channel: "/foo", data: "hello", ext: {auth: "password"}}], response )
57
+ }})
58
+ }})
59
+ }})
60
+
@@ -0,0 +1,145 @@
1
+ JS.ENV.Server.HandshakeSpec = JS.Test.describe("Server handshake", function() { with(this) {
2
+ before(function() { with(this) {
3
+ this.engine = {}
4
+ stub(Faye.Engine, "get").returns(engine)
5
+ this.server = new Faye.Server()
6
+
7
+ this.connectionTypes = ["long-polling", "cross-origin-long-polling",
8
+ "callback-polling","websocket",
9
+ "eventsource","in-process"]
10
+ }})
11
+
12
+ describe("#handshake", function() { with(this) {
13
+ before(function() { with(this) {
14
+ this.message = {channel: "/meta/handshake",
15
+ version: "1.0",
16
+ supportedConnectionTypes: ["long-polling"]}
17
+ }})
18
+
19
+ describe("with valid parameters", function() { with(this) {
20
+ it("creates a client", function() { with(this) {
21
+ expect(engine, "createClient")
22
+ server.handshake(message, false, function() {})
23
+ }})
24
+
25
+ it("returns a successful response", function() { with(this) {
26
+ stub(engine, "createClient").yields(["clientid"])
27
+ server.handshake(message, false, function(response) {
28
+ assertEqual({
29
+ channel: "/meta/handshake",
30
+ successful: true,
31
+ version: "1.0",
32
+ supportedConnectionTypes: connectionTypes,
33
+ clientId: "clientid"
34
+ }, response)
35
+ })
36
+ }})
37
+
38
+ describe("with a message id", function() { with(this) {
39
+ before(function() { this.message.id = "foo" })
40
+
41
+ it("returns the same id", function() { with(this) {
42
+ stub(engine, "createClient").yields(["clientid"])
43
+ server.handshake(message, false, function(response) {
44
+ assertEqual({
45
+ channel: "/meta/handshake",
46
+ successful: true,
47
+ version: "1.0",
48
+ supportedConnectionTypes: connectionTypes,
49
+ clientId: "clientid",
50
+ id: "foo"
51
+ }, response)
52
+ })
53
+ }})
54
+ }})
55
+ }})
56
+
57
+ describe("missing version", function() { with(this) {
58
+ before(function() { delete this.message.version })
59
+
60
+ it("does not create a client", function() { with(this) {
61
+ expect(engine, "createClient").exactly(0)
62
+ server.handshake(message, false, function() {})
63
+ }})
64
+
65
+ it("returns an unsuccessful response", function() { with(this) {
66
+ server.handshake(message, false, function(response) {
67
+ assertEqual({
68
+ channel: "/meta/handshake",
69
+ successful: false,
70
+ error: "402:version:Missing required parameter",
71
+ version: "1.0",
72
+ supportedConnectionTypes: connectionTypes
73
+ }, response)
74
+ })
75
+ }})
76
+ }})
77
+
78
+ describe("missing supportedConnectionTypes", function() { with(this) {
79
+ before(function() { delete this.message.supportedConnectionTypes })
80
+
81
+ it("does not create a client", function() { with(this) {
82
+ expect(engine, "createClient").exactly(0)
83
+ server.handshake(message, false, function() {})
84
+ }})
85
+
86
+ it("returns an unsuccessful response", function() { with(this) {
87
+ server.handshake(message, false, function(response) {
88
+ assertEqual({
89
+ channel: "/meta/handshake",
90
+ successful: false,
91
+ error: "402:supportedConnectionTypes:Missing required parameter",
92
+ version: "1.0",
93
+ supportedConnectionTypes: connectionTypes
94
+ }, response)
95
+ })
96
+ }})
97
+ }})
98
+
99
+ describe("with no matching supportedConnectionTypes", function() { with(this) {
100
+ before(function() { with(this) {
101
+ message.supportedConnectionTypes = ["iframe", "flash"]
102
+ }})
103
+
104
+ it("does not create a client", function() { with(this) {
105
+ expect(engine, "createClient").exactly(0)
106
+ server.handshake(message, false, function() {})
107
+ }})
108
+
109
+ it("returns an unsuccessful response", function() { with(this) {
110
+ server.handshake(message, false, function(response) {
111
+ assertEqual({
112
+ channel: "/meta/handshake",
113
+ successful: false,
114
+ error: "301:iframe,flash:Connection types not supported",
115
+ version: "1.0",
116
+ supportedConnectionTypes: connectionTypes
117
+ }, response)
118
+ })
119
+ }})
120
+ }})
121
+
122
+ describe("with an error", function() { with(this) {
123
+ before(function() { with(this) {
124
+ message.error = "invalid"
125
+ }})
126
+
127
+ it("does not create a client", function() { with(this) {
128
+ expect(engine, "createClient").exactly(0)
129
+ server.handshake(message, false, function() {})
130
+ }})
131
+
132
+ it("returns an unsuccessful response", function() { with(this) {
133
+ server.handshake(message, false, function(response) {
134
+ assertEqual({
135
+ channel: "/meta/handshake",
136
+ successful: false,
137
+ error: "invalid",
138
+ version: "1.0",
139
+ supportedConnectionTypes: connectionTypes
140
+ }, response)
141
+ })
142
+ }})
143
+ }})
144
+ }})
145
+ }})
@@ -0,0 +1,124 @@
1
+ JS.ENV.IntegrationSteps = JS.Test.asyncSteps({
2
+ server: function(port, ssl, callback) {
3
+ var shared = __dirname + '/../../../examples/shared',
4
+
5
+ options = ssl
6
+ ? { key: shared + '/server.key', cert: shared + '/server.crt' }
7
+ : null
8
+
9
+ this._adapter = new Faye.NodeAdapter({mount: "/bayeux", timeout: 2})
10
+ this._port = port
11
+ this._secure = ssl
12
+ this._adapter.listen(port, options, callback)
13
+ },
14
+
15
+ stop: function(callback) {
16
+ for (var id in this._clients) this._clients[id].disconnect()
17
+ var self = this
18
+ setTimeout(function() { self._adapter.stop(callback) }, 100)
19
+ },
20
+
21
+ client: function(name, channels, callback) {
22
+ var scheme = this._secure ? "https" : "http"
23
+ this._clients = this._clients || {}
24
+ this._inboxes = this._inboxes || {}
25
+ this._clients[name] = new Faye.Client(scheme + "://0.0.0.0:" + this._port + "/bayeux")
26
+ this._inboxes[name] = {}
27
+
28
+ var n = channels.length
29
+ if (n === 0) return this._clients[name].connect(callback)
30
+
31
+ for (var i = 0; i < n; i++)
32
+ (function(channel) {
33
+ var subscription = this._clients[name].subscribe(channel, function(message) {
34
+ this._inboxes[name][channel] = this._inboxes[name][channel] || []
35
+ this._inboxes[name][channel].push(message)
36
+ }, this)
37
+ subscription.callback(function() {
38
+ n -= 1
39
+ if (n === 0) callback()
40
+ })
41
+ }).call(this, channels[i]);
42
+ },
43
+
44
+ publish: function(name, channel, message, callback) {
45
+ this._clients[name].publish(channel, message)
46
+ setTimeout(callback, 100)
47
+ },
48
+
49
+ check_inbox: function(name, channel, messages, callback) {
50
+ var inbox = this._inboxes[name][channel] || []
51
+ this.assertEqual(messages, inbox)
52
+ callback()
53
+ }
54
+ })
55
+
56
+ JS.ENV.Server.IntegrationSpec = JS.Test.describe("Server integration", function() { with(this) {
57
+ include(IntegrationSteps)
58
+
59
+ sharedExamplesFor("message bus", function() { with(this) {
60
+ before(function() { with(this) {
61
+ server(8000, serverOptions.ssl)
62
+ client("alice", [])
63
+ client("bob", ["/foo"])
64
+ }})
65
+
66
+ after(function() { this.stop() })
67
+
68
+ it("delivers a message between clients", function() { with(this) {
69
+ publish("alice", "/foo", {hello: "world"})
70
+ check_inbox("bob", "/foo", [{hello: "world"}])
71
+ }})
72
+
73
+ it("does not deliver messages for unsubscribed channels", function() { with(this) {
74
+ publish("alice", "/bar", {hello: "world"})
75
+ check_inbox("bob", "/foo", [])
76
+ }})
77
+
78
+ it("delivers multiple messages", function() { with(this) {
79
+ publish("alice", "/foo", {hello: "world"})
80
+ publish("alice", "/foo", {hello: "world"})
81
+ check_inbox("bob", "/foo", [{hello: "world"},{hello: "world"}])
82
+ }})
83
+
84
+ it("delivers multibyte strings", function() { with(this) {
85
+ publish("alice", "/foo", {hello: "Apple = "})
86
+ check_inbox("bob", "/foo", [{hello: "Apple = "}])
87
+ }})
88
+ }})
89
+
90
+ sharedExamplesFor("network transports", function() { with(this) {
91
+ describe("with HTTP transport", function() { with(this) {
92
+ before(function() { with(this) {
93
+ stub(Faye.Transport.WebSocket, "isUsable").yields([false])
94
+ }})
95
+
96
+ itShouldBehaveLike("message bus")
97
+ }})
98
+
99
+ describe("with WebSocket transport", function() { with(this) {
100
+ before(function() { with(this) {
101
+ stub(Faye.Transport.WebSocket, "isUsable").yields([true])
102
+ }})
103
+
104
+ itShouldBehaveLike("message bus")
105
+ }})
106
+ }})
107
+
108
+ describe("with HTTP server", function() { with(this) {
109
+ before(function() { with(this) {
110
+ this.serverOptions = {ssl: false}
111
+ }})
112
+
113
+ itShouldBehaveLike("network transports")
114
+ }})
115
+
116
+ describe("with HTTPS server", function() { with(this) {
117
+ before(function() { with(this) {
118
+ this.serverOptions = {ssl: true}
119
+ }})
120
+
121
+ itShouldBehaveLike("network transports")
122
+ }})
123
+ }})
124
+