faye 0.8.8 → 0.8.9

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.

Files changed (67) hide show
  1. data/History.txt +16 -10
  2. data/README.rdoc +1 -1
  3. data/lib/faye-browser-min.js +1 -1
  4. data/lib/faye-browser-min.js.map +2 -2
  5. data/lib/faye-browser.js +302 -287
  6. data/lib/faye.rb +21 -21
  7. data/lib/faye/adapters/rack_adapter.rb +50 -48
  8. data/lib/faye/adapters/static_server.rb +22 -22
  9. data/lib/faye/engines/connection.rb +13 -13
  10. data/lib/faye/engines/memory.rb +21 -21
  11. data/lib/faye/engines/proxy.rb +23 -23
  12. data/lib/faye/error.rb +6 -6
  13. data/lib/faye/mixins/logging.rb +12 -12
  14. data/lib/faye/mixins/publisher.rb +6 -6
  15. data/lib/faye/mixins/timeouts.rb +1 -1
  16. data/lib/faye/protocol/channel.rb +24 -24
  17. data/lib/faye/protocol/client.rb +71 -73
  18. data/lib/faye/protocol/extensible.rb +7 -7
  19. data/lib/faye/protocol/grammar.rb +13 -13
  20. data/lib/faye/protocol/server.rb +57 -57
  21. data/lib/faye/protocol/socket.rb +4 -4
  22. data/lib/faye/protocol/subscription.rb +4 -4
  23. data/lib/faye/transport/http.rb +13 -13
  24. data/lib/faye/transport/local.rb +5 -5
  25. data/lib/faye/transport/transport.rb +25 -25
  26. data/lib/faye/transport/web_socket.rb +34 -30
  27. data/lib/faye/util/namespace.rb +4 -4
  28. data/spec/browser.html +5 -5
  29. data/spec/javascript/channel_spec.js +3 -3
  30. data/spec/javascript/client_spec.js +104 -98
  31. data/spec/javascript/engine/memory_spec.js +1 -1
  32. data/spec/javascript/engine_spec.js +70 -70
  33. data/spec/javascript/faye_spec.js +6 -6
  34. data/spec/javascript/grammar_spec.js +12 -12
  35. data/spec/javascript/node_adapter_spec.js +46 -46
  36. data/spec/javascript/publisher_spec.js +4 -4
  37. data/spec/javascript/server/connect_spec.js +21 -21
  38. data/spec/javascript/server/disconnect_spec.js +15 -15
  39. data/spec/javascript/server/extensions_spec.js +6 -6
  40. data/spec/javascript/server/handshake_spec.js +18 -18
  41. data/spec/javascript/server/integration_spec.js +23 -23
  42. data/spec/javascript/server/publish_spec.js +9 -9
  43. data/spec/javascript/server/subscribe_spec.js +30 -30
  44. data/spec/javascript/server/unsubscribe_spec.js +30 -30
  45. data/spec/javascript/server_spec.js +15 -15
  46. data/spec/javascript/transport_spec.js +32 -27
  47. data/spec/node.js +2 -2
  48. data/spec/ruby/channel_spec.rb +2 -2
  49. data/spec/ruby/client_spec.rb +100 -92
  50. data/spec/ruby/engine_examples.rb +51 -51
  51. data/spec/ruby/faye_spec.rb +5 -5
  52. data/spec/ruby/grammar_spec.rb +12 -12
  53. data/spec/ruby/publisher_spec.rb +4 -4
  54. data/spec/ruby/rack_adapter_spec.rb +34 -34
  55. data/spec/ruby/server/connect_spec.rb +22 -22
  56. data/spec/ruby/server/disconnect_spec.rb +16 -16
  57. data/spec/ruby/server/extensions_spec.rb +8 -8
  58. data/spec/ruby/server/handshake_spec.rb +20 -20
  59. data/spec/ruby/server/integration_spec.rb +22 -24
  60. data/spec/ruby/server/publish_spec.rb +9 -9
  61. data/spec/ruby/server/subscribe_spec.rb +31 -31
  62. data/spec/ruby/server/unsubscribe_spec.rb +31 -31
  63. data/spec/ruby/server_spec.rb +17 -17
  64. data/spec/ruby/transport_spec.rb +23 -23
  65. data/spec/testswarm +23 -10
  66. data/spec/thin_proxy.rb +5 -5
  67. metadata +90 -59
@@ -1,14 +1,14 @@
1
1
  module Faye
2
-
2
+
3
3
  class Transport::Local < Transport
4
4
  def self.usable?(client, endpoint, &callback)
5
5
  callback.call(endpoint.is_a?(Server))
6
6
  end
7
-
7
+
8
8
  def batching?
9
9
  false
10
10
  end
11
-
11
+
12
12
  def request(message, timeout)
13
13
  message = Faye.copy_object(message)
14
14
  @endpoint.process(message, true) do |responses|
@@ -16,7 +16,7 @@ module Faye
16
16
  end
17
17
  end
18
18
  end
19
-
19
+
20
20
  Transport.register 'in-process', Transport::Local
21
-
21
+
22
22
  end
@@ -1,12 +1,12 @@
1
1
  module Faye
2
2
  class Transport
3
-
3
+
4
4
  include Logging
5
5
  include Publisher
6
6
  include Timeouts
7
-
7
+
8
8
  attr_accessor :cookies, :endpoint, :headers
9
-
9
+
10
10
  def initialize(client, endpoint)
11
11
  @client = client
12
12
  @endpoint = endpoint
@@ -16,14 +16,14 @@ module Faye
16
16
  def batching?
17
17
  true
18
18
  end
19
-
19
+
20
20
  def close
21
21
  end
22
-
22
+
23
23
  def connection_type
24
24
  self.class.connection_type
25
25
  end
26
-
26
+
27
27
  def send(message, timeout)
28
28
  debug('Client ? sending message to ?: ?', @client.client_id, @endpoint, message)
29
29
 
@@ -55,62 +55,62 @@ module Faye
55
55
  @connection_message = nil
56
56
  @outbox = []
57
57
  end
58
-
58
+
59
59
  def receive(responses)
60
60
  debug('Client ? received from ?: ?', @client.client_id, @endpoint, responses)
61
61
  responses.each { |response| @client.receive_message(response) }
62
62
  end
63
-
63
+
64
64
  def retry_block(message, timeout)
65
65
  lambda do
66
66
  EventMachine.add_timer(@client.retry) { request(message, timeout) }
67
67
  end
68
68
  end
69
-
69
+
70
70
  @transports = []
71
-
71
+
72
72
  class << self
73
73
  attr_accessor :connection_type
74
-
75
- def get(client, connection_types = nil, &callback)
74
+
75
+ def get(client, allowed, disabled, &callback)
76
76
  endpoint = client.endpoint
77
- connection_types ||= supported_connection_types
78
-
77
+
79
78
  select = lambda do |(conn_type, klass), resume|
80
79
  conn_endpoint = client.endpoints[conn_type] || endpoint
81
- unless connection_types.include?(conn_type)
80
+
81
+ if disabled.include?(conn_type)
82
+ next resume.call
83
+ end
84
+
85
+ unless allowed.include?(conn_type)
82
86
  klass.usable?(client, conn_endpoint) { |u| }
83
87
  next resume.call
84
88
  end
85
-
89
+
86
90
  klass.usable?(client, conn_endpoint) do |is_usable|
87
91
  next resume.call unless is_usable
88
92
  transport = klass.respond_to?(:create) ? klass.create(client, conn_endpoint) : klass.new(client, conn_endpoint)
89
93
  callback.call(transport)
90
94
  end
91
95
  end
92
-
96
+
93
97
  error = lambda do
94
98
  raise "Could not find a usable connection type for #{ endpoint }"
95
99
  end
96
-
100
+
97
101
  Faye.async_each(@transports, select, error)
98
102
  end
99
-
103
+
100
104
  def register(type, klass)
101
105
  @transports << [type, klass]
102
106
  klass.connection_type = type
103
107
  end
104
-
105
- def supported_connection_types
106
- @transports.map { |t| t.first }
107
- end
108
108
  end
109
-
109
+
110
110
  %w[local web_socket http].each do |type|
111
111
  require File.join(ROOT, 'faye', 'transport', type)
112
112
  end
113
-
113
+
114
114
  end
115
115
  end
116
116
 
@@ -1,31 +1,31 @@
1
1
  module Faye
2
-
2
+
3
3
  class Transport::WebSocket < Transport
4
- UNCONNECTED = 1
5
- CONNECTING = 2
6
- CONNECTED = 3
7
-
4
+ UNCONNECTED = 1
5
+ CONNECTING = 2
6
+ CONNECTED = 3
7
+
8
8
  include EventMachine::Deferrable
9
-
9
+
10
10
  def self.usable?(client, endpoint, &callback)
11
11
  create(client, endpoint).usable?(&callback)
12
12
  end
13
-
13
+
14
14
  def self.create(client, endpoint)
15
15
  sockets = client.transports[:websocket] ||= {}
16
16
  sockets[endpoint] ||= new(client, endpoint)
17
17
  end
18
-
18
+
19
19
  def batching?
20
20
  false
21
21
  end
22
-
22
+
23
23
  def usable?(&callback)
24
24
  self.callback { callback.call(true) }
25
25
  self.errback { callback.call(false) }
26
26
  connect
27
27
  end
28
-
28
+
29
29
  def request(messages, timeout = nil)
30
30
  return if messages.empty?
31
31
  @messages ||= {}
@@ -33,56 +33,60 @@ module Faye
33
33
  callback { |socket| socket.send(Faye.to_json(messages)) }
34
34
  connect
35
35
  end
36
-
36
+
37
37
  def close
38
- return if @closed
39
- @closed = true
40
- @socket.close if @socket
38
+ return unless @socket
39
+ @socket.onclose = @socket.onerror = nil
40
+ @socket.close
41
+ @socket = nil
42
+ set_deferred_status(:deferred)
43
+ @state = UNCONNECTED
41
44
  end
42
-
45
+
43
46
  def connect
44
- return if @closed
45
-
46
47
  @state ||= UNCONNECTED
47
48
  return unless @state == UNCONNECTED
48
-
49
+
49
50
  @state = CONNECTING
50
-
51
+
51
52
  @socket = Faye::WebSocket::Client.new(@endpoint.gsub(/^http(s?):/, 'ws\1:'))
52
-
53
+
53
54
  @socket.onopen = lambda do |*args|
54
55
  @state = CONNECTED
55
56
  @ever_connected = true
56
57
  set_deferred_status(:succeeded, @socket)
57
58
  trigger(:up)
58
59
  end
59
-
60
+
60
61
  @socket.onmessage = lambda do |event|
61
- messages = [Yajl::Parser.parse(event.data)].flatten
62
+ messages = Yajl::Parser.parse(event.data)
63
+ next if messages.nil?
64
+ messages = [messages].flatten
62
65
  messages.each { |message| @messages.delete(message['id']) }
63
66
  receive(messages)
64
67
  end
65
-
66
- @socket.onclose = lambda do |*args|
68
+
69
+ @socket.onclose = @socket.onerror = lambda do |*args|
67
70
  was_connected = (@state == CONNECTED)
68
71
  set_deferred_status(:deferred)
69
72
  @state = UNCONNECTED
70
- @socket = nil
71
-
73
+
74
+ close
75
+
72
76
  next resend if was_connected
73
77
  next set_deferred_status(:failed) unless @ever_connected
74
-
78
+
75
79
  EventMachine.add_timer(@client.retry) { connect }
76
80
  trigger(:down)
77
81
  end
78
82
  end
79
-
83
+
80
84
  def resend
81
85
  return unless @messages
82
86
  request(@messages.values)
83
87
  end
84
88
  end
85
-
89
+
86
90
  Transport.register 'websocket', Transport::WebSocket
87
-
91
+
88
92
  end
@@ -1,20 +1,20 @@
1
1
  module Faye
2
2
  class Namespace
3
-
3
+
4
4
  extend Forwardable
5
5
  def_delegator :@used, :delete, :release
6
6
  def_delegator :@used, :has_key?, :exists?
7
-
7
+
8
8
  def initialize
9
9
  @used = {}
10
10
  end
11
-
11
+
12
12
  def generate
13
13
  name = Engine.random
14
14
  name = Engine.random while @used.has_key?(name)
15
15
  @used[name] = name
16
16
  end
17
-
17
+
18
18
  end
19
19
  end
20
20
 
@@ -7,7 +7,7 @@
7
7
  </head>
8
8
  <body>
9
9
  <script type="text/javascript">
10
-
10
+
11
11
  if (typeof TestSwarm === 'undefined')
12
12
  TestSwarm = {
13
13
  submit: function(result) {
@@ -15,9 +15,9 @@
15
15
  },
16
16
  heartbeat: function() {}
17
17
  }
18
-
18
+
19
19
  JS.cacheBust = true
20
-
20
+
21
21
  JS.Packages(function() { with(this) {
22
22
  file('../build/browser/faye-browser-min.js').provides('Faye')
23
23
  autoload(/.*Spec/, {from: './javascript'})
@@ -30,7 +30,7 @@
30
30
  return function(actual) { testcase.assertEqual(expected, actual) }
31
31
  }
32
32
  })
33
-
33
+
34
34
  JS.require( 'FayeSpec',
35
35
  'GrammarSpec',
36
36
  'ChannelSpec',
@@ -38,7 +38,7 @@
38
38
  'TransportSpec',
39
39
  JS.Test.method('autorun'))
40
40
  })
41
-
41
+
42
42
  </script>
43
43
  </body>
44
44
  </html>
@@ -1,13 +1,13 @@
1
1
  JS.ENV.ChannelSpec = JS.Test.describe("Channel", function() { with(this) {
2
2
  describe("expand", function() { with(this) {
3
3
  it("returns all patterns that match a channel", function() { with(this) {
4
-
4
+
5
5
  assertEqual( ["/**", "/foo", "/*"],
6
6
  Faye.Channel.expand("/foo") )
7
-
7
+
8
8
  assertEqual( ["/**", "/foo/bar", "/foo/*", "/foo/**"],
9
9
  Faye.Channel.expand("/foo/bar") )
10
-
10
+
11
11
  assertEqual( ["/**", "/foo/bar/qux", "/foo/bar/*", "/foo/**", "/foo/bar/**"],
12
12
  Faye.Channel.expand("/foo/bar/qux") )
13
13
  }})
@@ -4,11 +4,11 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
4
4
  Faye.extend(transport, Faye.Publisher)
5
5
  stub(Faye.Transport, "get").yields([transport])
6
6
  }})
7
-
7
+
8
8
  before(function() { with(this) {
9
9
  stub("setTimeout")
10
10
  }})
11
-
11
+
12
12
  define("stubResponse", function(response) { with(this) {
13
13
  stub(transport, "send", function(message) {
14
14
  response.id = message.id
@@ -19,7 +19,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
19
19
  define("createClient", function() { with(this) {
20
20
  this.client = new Faye.Client("http://localhost/")
21
21
  }})
22
-
22
+
23
23
  define("createConnectedClient", function() { with(this) {
24
24
  createClient()
25
25
  stubResponse({channel: "/meta/handshake",
@@ -27,29 +27,22 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
27
27
  version: "1.0",
28
28
  supportedConnectionTypes: ["websocket"],
29
29
  clientId: "fakeid" })
30
-
30
+
31
31
  client.handshake()
32
32
  }})
33
-
33
+
34
34
  define("subscribe", function(client, channel, callback) { with(this) {
35
35
  stubResponse({channel: "/meta/subscribe",
36
36
  successful: true,
37
37
  clientId: "fakeid",
38
38
  subscription: channel })
39
-
39
+
40
40
  this.subsCalled = 0
41
41
  callback = callback || function() { subsCalled += 1 }
42
42
  client.subscribe(channel, callback)
43
43
  }})
44
44
 
45
45
  describe("initialize", function() { with(this) {
46
- it("creates a transport the server must support", function() { with(this) {
47
- expect(Faye.Transport, "get").given(instanceOf(Faye.Client),
48
- ["long-polling", "callback-polling", "in-process"])
49
- .yielding([transport])
50
- new Faye.Client("http://localhost/")
51
- }})
52
-
53
46
  it("puts the client in the UNCONNECTED state", function() { with(this) {
54
47
  stub(Faye.Transport, "get")
55
48
  var client = new Faye.Client("http://localhost/")
@@ -60,7 +53,15 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
60
53
  describe("handshake", function() { with(this) {
61
54
  before(function() { this.createClient() })
62
55
 
63
- it("sends a handshake message to the server", function() { with(this) {
56
+ it("creates a transport the server must support", function() { with(this) {
57
+ expect(Faye.Transport, "get").given(instanceOf(Faye.Client),
58
+ ["long-polling", "callback-polling", "in-process"],
59
+ [])
60
+ .yielding([transport])
61
+ client.handshake()
62
+ }})
63
+
64
+ it("sends a handshake message to the server", function() { with(this) {
64
65
  expect(transport, "send").given({
65
66
  channel: "/meta/handshake",
66
67
  version: "1.0",
@@ -75,7 +76,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
75
76
  client.handshake()
76
77
  assertEqual( "CONNECTING", client.getState() )
77
78
  }})
78
-
79
+
79
80
  describe("with an outgoing extension installed", function() { with(this) {
80
81
  before(function() { with(this) {
81
82
  var extension = {
@@ -86,7 +87,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
86
87
  }
87
88
  client.addExtension(extension)
88
89
  }})
89
-
90
+
90
91
  it("passes the handshake message through the extension", function() { with(this) {
91
92
  expect(transport, "send").given({
92
93
  channel: "/meta/handshake",
@@ -117,23 +118,25 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
117
118
  client.handshake()
118
119
  assertEqual( "CONNECTED", client.getState() )
119
120
  }})
120
-
121
+
121
122
  it("registers any pre-existing subscriptions", function() { with(this) {
122
123
  expect(client, "subscribe").given([], true)
123
124
  client.handshake()
124
125
  }})
125
-
126
+
126
127
  it("selects a new transport based on what the server supports", function() { with(this) {
127
- expect(Faye.Transport, "get").given(instanceOf(Faye.Client), ["long-polling", "websocket"])
128
+ expect(Faye.Transport, "get").given(instanceOf(Faye.Client), ["long-polling", "websocket"], [])
128
129
  .yielding([transport])
129
130
  client.handshake()
130
131
  }})
131
-
132
+
132
133
  describe("with websocket disabled", function() { with(this) {
133
134
  before(function() { this.client.disable('websocket') })
134
-
135
+
135
136
  it("selects a new transport, excluding websocket", function() { with(this) {
136
- expect(Faye.Transport, "get").given(instanceOf(Faye.Client), ["long-polling"])
137
+ expect(Faye.Transport, "get").given(instanceOf(Faye.Client),
138
+ ["long-polling", "websocket"],
139
+ ["websocket"])
137
140
  .yielding([transport])
138
141
  client.handshake()
139
142
  }})
@@ -159,16 +162,16 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
159
162
  assertEqual( "UNCONNECTED", client.getState() )
160
163
  }})
161
164
  }})
162
-
165
+
163
166
  describe("with existing subscriptions after a server restart", function() { with(this) {
164
167
  before(function() { with(this) {
165
168
  createConnectedClient()
166
-
169
+
167
170
  this.message = null
168
171
  subscribe(client, "/messages/foo", function(m) { message = m })
169
-
172
+
170
173
  client.receiveMessage({advice: {reconnect: "handshake"}})
171
-
174
+
172
175
  stubResponse({channel: "/meta/handshake",
173
176
  successful: true,
174
177
  version: "1.0",
@@ -176,7 +179,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
176
179
  clientId: "reconnectid",
177
180
  subscription: "/messages/foo" }) // tacked on to trigger subscribe() callback
178
181
  }})
179
-
182
+
180
183
  it("resends the subscriptions to the server", function() { with(this) {
181
184
  expect(transport, "send").given({
182
185
  channel: "/meta/subscribe",
@@ -186,17 +189,17 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
186
189
  }, 60)
187
190
  client.handshake()
188
191
  }})
189
-
192
+
190
193
  it("retains the listeners for the subscriptions", function() { with(this) {
191
194
  client.handshake()
192
195
  client.receiveMessage({channel: "/messages/foo", "data": "ok"})
193
196
  assertEqual( "ok", message )
194
197
  }})
195
198
  }})
196
-
199
+
197
200
  describe("with a connected client", function() { with(this) {
198
201
  before(function() { this.createConnectedClient() })
199
-
202
+
200
203
  it("does not send a handshake message to the server", function() { with(this) {
201
204
  expect(transport, "send").given({
202
205
  channel: "/meta/handshake",
@@ -205,12 +208,12 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
205
208
  id: instanceOf("string")
206
209
  }, 60)
207
210
  .exactly(0)
208
-
211
+
209
212
  client.handshake()
210
213
  }})
211
214
  }})
212
215
  }})
213
-
216
+
214
217
  describe("connect", function() { with(this) {
215
218
  describe("with an unconnected client", function() { with(this) {
216
219
  before(function() { with(this) {
@@ -219,10 +222,10 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
219
222
  version: "1.0",
220
223
  supportedConnectionTypes: ["websocket"],
221
224
  clientId: "handshakeid" })
222
-
225
+
223
226
  createClient()
224
227
  }})
225
-
228
+
226
229
  it("handshakes before connecting", function() { with(this) {
227
230
  expect(transport, "send").given({
228
231
  channel: "/meta/connect",
@@ -233,10 +236,10 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
233
236
  client.connect()
234
237
  }})
235
238
  }})
236
-
239
+
237
240
  describe("with a connected client", function() { with(this) {
238
241
  before(function() { this.createConnectedClient() })
239
-
242
+
240
243
  it("sends a connect message to the server", function() { with(this) {
241
244
  expect(transport, "send").given({
242
245
  channel: "/meta/connect",
@@ -246,7 +249,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
246
249
  }, 60)
247
250
  client.connect()
248
251
  }})
249
-
252
+
250
253
  it("only opens one connect request at a time", function() { with(this) {
251
254
  expect(transport, "send").given({
252
255
  channel: "/meta/connect",
@@ -255,16 +258,16 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
255
258
  id: instanceOf("string")
256
259
  }, 60)
257
260
  .exactly(1)
258
-
261
+
259
262
  client.connect()
260
263
  client.connect()
261
264
  }})
262
265
  }})
263
266
  }})
264
-
267
+
265
268
  describe("disconnect", function() { with(this) {
266
269
  before(function() { this.createConnectedClient() })
267
-
270
+
268
271
  it("sends a disconnect message to the server", function() { with(this) {
269
272
  expect(transport, "send").given({
270
273
  channel: "/meta/disconnect",
@@ -273,27 +276,27 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
273
276
  }, 60)
274
277
  client.disconnect()
275
278
  }})
276
-
279
+
277
280
  it("puts the client in the DISCONNECTED state", function() { with(this) {
278
281
  stub(transport, "close")
279
282
  client.disconnect()
280
283
  assertEqual( "DISCONNECTED", client.getState() )
281
284
  }})
282
-
285
+
283
286
  describe("on successful response", function() { with(this) {
284
287
  before(function() { with(this) {
285
288
  stubResponse({channel: "/meta/disconnect",
286
289
  successful: true,
287
290
  clientId: "fakeid" })
288
291
  }})
289
-
292
+
290
293
  it("closes the transport", function() { with(this) {
291
294
  expect(transport, "close")
292
295
  client.disconnect()
293
296
  }})
294
297
  }})
295
298
  }})
296
-
299
+
297
300
  describe("subscribe", function() { with(this) {
298
301
  before(function() { with(this) {
299
302
  createConnectedClient()
@@ -304,13 +307,13 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
304
307
  id: instanceOf("string")
305
308
  }
306
309
  }})
307
-
310
+
308
311
  describe("with no prior subscriptions", function() { with(this) {
309
312
  it("sends a subscribe message to the server", function() { with(this) {
310
313
  expect(transport, "send").given(subscribeMessage, 60)
311
314
  client.subscribe("/foo")
312
315
  }})
313
-
316
+
314
317
  // The Bayeux spec says the server should accept a list of subscriptions
315
318
  // in one message but the cometD server doesn't actually support this
316
319
  describe("with an array of subscriptions", function() { with(this) {
@@ -329,7 +332,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
329
332
  }, 60)
330
333
  client.subscribe(["/foo", "/bar"])
331
334
  }})
332
-
335
+
333
336
  it("returns an array of subscriptions", function() { with(this) {
334
337
  stub(transport, "send")
335
338
  var subs = client.subscribe(["/foo", "/bar"])
@@ -337,7 +340,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
337
340
  assertKindOf( Faye.Subscription, subs[0] )
338
341
  }})
339
342
  }})
340
-
343
+
341
344
  describe("on successful response", function() { with(this) {
342
345
  before(function() { with(this) {
343
346
  stubResponse({channel: "/meta/subscribe",
@@ -345,27 +348,27 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
345
348
  clientId: "fakeid",
346
349
  subscription: "/foo/*" })
347
350
  }})
348
-
351
+
349
352
  it("sets up a listener for the subscribed channel", function() { with(this) {
350
353
  var message
351
354
  client.subscribe("/foo/*", function(m) { message = m })
352
355
  client.receiveMessage({channel: "/foo/bar", data: "hi"})
353
356
  assertEqual( "hi", message )
354
357
  }})
355
-
358
+
356
359
  it("does not call the listener for non-matching channels", function() { with(this) {
357
360
  var message
358
361
  client.subscribe("/foo/*", function(m) { message = m })
359
362
  client.receiveMessage({channel: "/bar", data: "hi"})
360
363
  assertEqual( undefined, message )
361
364
  }})
362
-
365
+
363
366
  it("activates the subscription", function() { with(this) {
364
367
  var active = false
365
368
  client.subscribe("/foo/*").callback(function() { active = true })
366
369
  assert( active )
367
370
  }})
368
-
371
+
369
372
  describe("with an incoming extension installed", function() { with(this) {
370
373
  before(function() { with(this) {
371
374
  var extension = {
@@ -378,13 +381,13 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
378
381
  this.message = null
379
382
  client.subscribe("/foo/*", function(m) { message = m })
380
383
  }})
381
-
384
+
382
385
  it("passes delivered messages through the extension", function() { with(this) {
383
386
  client.receiveMessage({channel: "/foo/bar", data: {hello: "there"}})
384
387
  assertEqual( {hello: "there", changed: true}, message )
385
388
  }})
386
389
  }})
387
-
390
+
388
391
  describe("with an outgoing extension installed", function() { with(this) {
389
392
  before(function() { with(this) {
390
393
  var extension = {
@@ -397,13 +400,13 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
397
400
  this.message = null
398
401
  client.subscribe("/foo/*", function(m) { message = m })
399
402
  }})
400
-
403
+
401
404
  it("leaves messages unchanged", function() { with(this) {
402
405
  client.receiveMessage({channel: "/foo/bar", data: {hello: "there"}})
403
406
  assertEqual( {hello: "there"}, message )
404
407
  }})
405
408
  }})
406
-
409
+
407
410
  describe("with an incoming extension that invalidates the response", function() { with(this) {
408
411
  before(function() { with(this) {
409
412
  var extension = {
@@ -414,14 +417,14 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
414
417
  }
415
418
  client.addExtension(extension)
416
419
  }})
417
-
420
+
418
421
  it("does not set up a listener for the subscribed channel", function() { with(this) {
419
422
  var message
420
423
  client.subscribe("/foo/*", function(m) { message = m })
421
424
  client.receiveMessage({channel: "/foo/bar", data: "hi"})
422
425
  assertEqual( undefined, message )
423
426
  }})
424
-
427
+
425
428
  it("does not activate the subscription", function() { with(this) {
426
429
  var active = false
427
430
  client.subscribe("/foo/*").callback(function() { active = true })
@@ -429,7 +432,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
429
432
  }})
430
433
  }})
431
434
  }})
432
-
435
+
433
436
  describe("on unsuccessful response", function() { with(this) {
434
437
  before(function() { with(this) {
435
438
  stubResponse({channel: "/meta/subscribe",
@@ -438,14 +441,14 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
438
441
  clientId: "fakeid",
439
442
  subscription: "/meta/foo" })
440
443
  }})
441
-
444
+
442
445
  it("does not set up a listener for the subscribed channel", function() { with(this) {
443
446
  var message
444
447
  client.subscribe("/meta/foo", function(m) { message = m })
445
448
  client.receiveMessage({channel: "/meta/foo", data: "hi"})
446
449
  assertEqual( undefined, message )
447
450
  }})
448
-
451
+
449
452
  it("does not activate the subscription", function() { with(this) {
450
453
  var active = false
451
454
  client.subscribe("/meta/foo").callback(function() { active = true })
@@ -459,23 +462,23 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
459
462
  }})
460
463
  }})
461
464
  }})
462
-
465
+
463
466
  describe("with an existing subscription", function() { with(this) {
464
467
  before(function() { with(this) {
465
468
  subscribe(client, "/foo/*")
466
469
  }})
467
-
470
+
468
471
  it("does not send another subscribe message to the server", function() { with(this) {
469
472
  expect(transport, "send").given(subscribeMessage, 60).exactly(0)
470
473
  client.subscribe("/foo/*")
471
474
  }})
472
-
475
+
473
476
  it("sets up another listener on the channel", function() { with(this) {
474
477
  client.subscribe("/foo/*", function() { subsCalled += 1 })
475
478
  client.receiveMessage({channel: "/foo/bar", data: "hi"})
476
479
  assertEqual( 2, subsCalled )
477
480
  }})
478
-
481
+
479
482
  it("activates the subscription", function() { with(this) {
480
483
  var active = false
481
484
  client.subscribe("/foo/*").callback(function() { active = true })
@@ -483,7 +486,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
483
486
  }})
484
487
  }})
485
488
  }})
486
-
489
+
487
490
  describe("unsubscribe", function() { with(this) {
488
491
  before(function() { with(this) {
489
492
  createConnectedClient()
@@ -494,26 +497,26 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
494
497
  id: instanceOf("string")
495
498
  }
496
499
  }})
497
-
500
+
498
501
  describe("with no subscriptions", function() { with(this) {
499
502
  it("does not send an unsubscribe message to the server", function() { with(this) {
500
503
  expect(transport, "send").given(unsubscribeMessage, 60).exactly(0)
501
504
  client.unsubscribe("/foo/*")
502
505
  }})
503
506
  }})
504
-
507
+
505
508
  describe("with a single subscription", function() { with(this) {
506
509
  before(function() { with(this) {
507
510
  this.message = null
508
511
  this.listener = function(m) { message = m }
509
512
  subscribe(client, "/foo/*", listener)
510
513
  }})
511
-
514
+
512
515
  it("sends an unsubscribe message to the server", function() { with(this) {
513
516
  expect(transport, "send").given(unsubscribeMessage, 60)
514
517
  client.unsubscribe("/foo/*")
515
518
  }})
516
-
519
+
517
520
  it("removes the listener from the channel", function() { with(this) {
518
521
  client.receiveMessage({channel: "/foo/bar", data: "first"})
519
522
  client.unsubscribe("/foo/*", listener)
@@ -521,7 +524,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
521
524
  assertEqual( "first", message )
522
525
  }})
523
526
  }})
524
-
527
+
525
528
  describe("with multiple subscriptions to the same channel", function() { with(this) {
526
529
  before(function() { with(this) {
527
530
  this.messages = []
@@ -530,37 +533,37 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
530
533
  subscribe(client, "/foo/*", hey)
531
534
  subscribe(client, "/foo/*", bye)
532
535
  }})
533
-
536
+
534
537
  it("removes one of the listeners from the channel", function() { with(this) {
535
538
  client.receiveMessage({channel: "/foo/bar", data: {text: "you"}})
536
539
  client.unsubscribe("/foo/*", hey)
537
540
  client.receiveMessage({channel: "/foo/bar", data: {text: "you"}})
538
541
  assertEqual( ["hey you", "bye you", "bye you"], messages)
539
542
  }})
540
-
543
+
541
544
  it("does not send an unsubscribe message if one listener is removed", function() { with(this) {
542
545
  expect(transport, "send").given(unsubscribeMessage, 60).exactly(0)
543
546
  client.unsubscribe("/foo/*", bye)
544
547
  }})
545
-
548
+
546
549
  it("sends an unsubscribe message if each listener is removed", function() { with(this) {
547
550
  expect(transport, "send").given(unsubscribeMessage, 60)
548
551
  client.unsubscribe("/foo/*", bye)
549
552
  client.unsubscribe("/foo/*", hey)
550
553
  }})
551
-
554
+
552
555
  it("sends an unsubscribe message if all listeners are removed", function() { with(this) {
553
556
  expect(transport, "send").given(unsubscribeMessage, 60)
554
557
  client.unsubscribe("/foo/*")
555
558
  }})
556
559
  }})
557
-
560
+
558
561
  describe("with multiple subscriptions to different channels", function() { with(this) {
559
562
  before(function() { with(this) {
560
563
  subscribe(client, "/foo")
561
564
  subscribe(client, "/bar")
562
565
  }})
563
-
566
+
564
567
  it("sends multiple unsubscribe messages if given an array", function() { with(this) {
565
568
  expect(transport, "send").given({
566
569
  channel: "/meta/unsubscribe",
@@ -578,10 +581,10 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
578
581
  }})
579
582
  }})
580
583
  }})
581
-
584
+
582
585
  describe("publish", function() { with(this) {
583
586
  before(function() { this.createConnectedClient() })
584
-
587
+
585
588
  it("sends the message to the server with an ID", function() { with(this) {
586
589
  expect(transport, "send").given({
587
590
  channel: "/messages/foo",
@@ -591,7 +594,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
591
594
  }, 60)
592
595
  client.publish("/messages/foo", {hello: "world"})
593
596
  }})
594
-
597
+
595
598
  describe("on publish failure", function() { with(this) {
596
599
  before(function() { with(this) {
597
600
  stubResponse({channel: "/messages/foo",
@@ -599,13 +602,13 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
599
602
  successful: false,
600
603
  clientId: "fakeid" })
601
604
  }})
602
-
605
+
603
606
  it("should not be published", function() { with(this) {
604
607
  var published = false
605
608
  client.publish("/messages/foo", {text: "hi"}).callback(function() { published = true })
606
609
  assert( !published )
607
610
  }})
608
-
611
+
609
612
  it("reports the error through an errback", function() { with(this) {
610
613
  var error = null
611
614
  client.publish("/messages/foo", {text: "hi"}).errback(function(e) { error = e })
@@ -614,14 +617,14 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
614
617
  assertEqual( "Failed to publish", error.message )
615
618
  }})
616
619
  }})
617
-
620
+
618
621
  describe("on receipt of the published message", function() { with(this) {
619
622
  before(function() { with(this) {
620
623
  stubResponse({channel: "/messages/foo",
621
624
  data: {text: "hi"},
622
625
  clientId: "fakeid" })
623
626
  }})
624
-
627
+
625
628
  it("does not trigger the callbacks", function() { with(this) {
626
629
  var published = false
627
630
  var publication = client.publish("/messages/foo", {text: "hi"})
@@ -630,7 +633,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
630
633
  assert( !published )
631
634
  }})
632
635
  }})
633
-
636
+
634
637
  describe("with an outgoing extension installed", function() { with(this) {
635
638
  before(function() { with(this) {
636
639
  var extension = {
@@ -641,7 +644,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
641
644
  }
642
645
  client.addExtension(extension)
643
646
  }})
644
-
647
+
645
648
  it("passes messages through the extension", function() { with(this) {
646
649
  expect(transport, "send").given({
647
650
  channel: "/messages/foo",
@@ -653,7 +656,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
653
656
  client.publish("/messages/foo", {hello: "world"})
654
657
  }})
655
658
  }})
656
-
659
+
657
660
  describe("with an incoming extension installed", function() { with(this) {
658
661
  before(function() { with(this) {
659
662
  var extension = {
@@ -664,7 +667,7 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
664
667
  }
665
668
  client.addExtension(extension)
666
669
  }})
667
-
670
+
668
671
  it("leaves the message unchanged", function() { with(this) {
669
672
  expect(transport, "send").given({
670
673
  channel: "/messages/foo",
@@ -676,44 +679,47 @@ JS.ENV.ClientSpec = JS.Test.describe("Client", function() { with(this) {
676
679
  }})
677
680
  }})
678
681
  }})
679
-
682
+
680
683
  describe("network notifications", function() { with(this) {
681
- before(function() { this.createClient() })
682
-
684
+ before(function() { with(this) {
685
+ createClient()
686
+ client.handshake()
687
+ }})
688
+
683
689
  describe("in the default state", function() { with(this) {
684
690
  it("broadcasts a down notification", function() { with(this) {
685
691
  expect(client, "trigger").given("transport:down")
686
692
  transport.trigger("down")
687
693
  }})
688
-
694
+
689
695
  it("broadcasts an up notification", function() { with(this) {
690
696
  expect(client, "trigger").given("transport:up")
691
697
  transport.trigger("up")
692
698
  }})
693
699
  }})
694
-
700
+
695
701
  describe("when the transport is up", function() { with(this) {
696
702
  before(function() { this.transport.trigger("up") })
697
-
703
+
698
704
  it("broadcasts a down notification", function() { with(this) {
699
705
  expect(client, "trigger").given("transport:down")
700
706
  transport.trigger("down")
701
707
  }})
702
-
708
+
703
709
  it("does not broadcast an up notification", function() { with(this) {
704
710
  expect(client, "trigger").exactly(0)
705
711
  transport.trigger("up")
706
712
  }})
707
713
  }})
708
-
714
+
709
715
  describe("when the transport is down", function() { with(this) {
710
716
  before(function() { this.transport.trigger("down") })
711
-
717
+
712
718
  it("does not broadcast a down notification", function() { with(this) {
713
719
  expect(client, "trigger").exactly(0)
714
720
  transport.trigger("down")
715
721
  }})
716
-
722
+
717
723
  it("broadcasts an up notification", function() { with(this) {
718
724
  expect(client, "trigger").given("transport:up")
719
725
  transport.trigger("up")