faye 0.8.11 → 1.0.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 → CHANGELOG.md} +126 -105
- data/README.md +36 -0
- data/lib/faye-browser-min.js +2 -1
- data/lib/faye-browser-min.js.map +1 -8
- data/lib/faye-browser.js +923 -607
- data/lib/faye.rb +11 -5
- data/lib/faye/adapters/rack_adapter.rb +80 -85
- data/lib/faye/engines/connection.rb +7 -9
- data/lib/faye/engines/memory.rb +1 -0
- data/lib/faye/engines/proxy.rb +7 -6
- data/lib/faye/mixins/deferrable.rb +15 -0
- data/lib/faye/mixins/logging.rb +11 -22
- data/lib/faye/mixins/publisher.rb +9 -20
- data/lib/faye/protocol/channel.rb +2 -1
- data/lib/faye/protocol/client.rb +70 -48
- data/lib/faye/protocol/envelope.rb +24 -0
- data/lib/faye/protocol/extensible.rb +7 -4
- data/lib/faye/protocol/publication.rb +1 -1
- data/lib/faye/protocol/server.rb +8 -11
- data/lib/faye/protocol/socket.rb +6 -4
- data/lib/faye/protocol/subscription.rb +1 -1
- data/lib/faye/transport/http.rb +20 -27
- data/lib/faye/transport/local.rb +5 -5
- data/lib/faye/transport/transport.rb +42 -12
- data/lib/faye/transport/web_socket.rb +71 -38
- metadata +169 -137
- checksums.yaml +0 -7
- data/README.rdoc +0 -83
- data/spec/browser.html +0 -45
- data/spec/encoding_helper.rb +0 -7
- data/spec/install.sh +0 -78
- data/spec/javascript/channel_spec.js +0 -15
- data/spec/javascript/client_spec.js +0 -729
- data/spec/javascript/dispatcher_spec.js +0 -122
- data/spec/javascript/engine/memory_spec.js +0 -7
- data/spec/javascript/engine_spec.js +0 -417
- data/spec/javascript/faye_spec.js +0 -34
- data/spec/javascript/grammar_spec.js +0 -66
- data/spec/javascript/node_adapter_spec.js +0 -314
- data/spec/javascript/publisher_spec.js +0 -27
- data/spec/javascript/server/connect_spec.js +0 -168
- data/spec/javascript/server/disconnect_spec.js +0 -121
- data/spec/javascript/server/extensions_spec.js +0 -60
- data/spec/javascript/server/handshake_spec.js +0 -145
- data/spec/javascript/server/integration_spec.js +0 -131
- data/spec/javascript/server/publish_spec.js +0 -85
- data/spec/javascript/server/subscribe_spec.js +0 -247
- data/spec/javascript/server/unsubscribe_spec.js +0 -245
- data/spec/javascript/server_spec.js +0 -121
- data/spec/javascript/transport_spec.js +0 -135
- data/spec/node.js +0 -55
- data/spec/phantom.js +0 -17
- data/spec/ruby/channel_spec.rb +0 -17
- data/spec/ruby/client_spec.rb +0 -741
- data/spec/ruby/engine/memory_spec.rb +0 -7
- data/spec/ruby/engine_examples.rb +0 -427
- data/spec/ruby/faye_spec.rb +0 -30
- data/spec/ruby/grammar_spec.rb +0 -68
- data/spec/ruby/publisher_spec.rb +0 -27
- data/spec/ruby/rack_adapter_spec.rb +0 -241
- data/spec/ruby/server/connect_spec.rb +0 -170
- data/spec/ruby/server/disconnect_spec.rb +0 -120
- data/spec/ruby/server/extensions_spec.rb +0 -68
- data/spec/ruby/server/handshake_spec.rb +0 -143
- data/spec/ruby/server/integration_spec.rb +0 -133
- data/spec/ruby/server/publish_spec.rb +0 -81
- data/spec/ruby/server/subscribe_spec.rb +0 -247
- data/spec/ruby/server/unsubscribe_spec.rb +0 -247
- data/spec/ruby/server_spec.rb +0 -121
- data/spec/ruby/transport_spec.rb +0 -136
- data/spec/spec_helper.rb +0 -11
- data/spec/testswarm +0 -42
- data/spec/thin_proxy.rb +0 -37
@@ -1,121 +0,0 @@
|
|
1
|
-
JS.ENV.ServerSpec = JS.Test.describe("Server", 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("#process", function() { with(this) {
|
9
|
-
before(function() { with(this) {
|
10
|
-
this.handshake = {channel: "/meta/handshake", data: "handshake"}
|
11
|
-
this.connect = {channel: "/meta/connect", data: "connect"}
|
12
|
-
this.disconnect = {channel: "/meta/disconnect", data: "disconnect"}
|
13
|
-
this.subscribe = {channel: "/meta/subscribe", data: "subscribe"}
|
14
|
-
this.unsubscribe = {channel: "/meta/unsubscribe", data: "unsubscribe"}
|
15
|
-
this.publish = {channel: "/some/channel", data: "publish"}
|
16
|
-
|
17
|
-
stub(engine, "interval", 0)
|
18
|
-
stub(engine, "timeout", 60)
|
19
|
-
}})
|
20
|
-
|
21
|
-
it("returns an empty response for no messages", function() { with(this) {
|
22
|
-
var response = null
|
23
|
-
server.process([], false, function(r) { response = r})
|
24
|
-
assertEqual( [], response )
|
25
|
-
}})
|
26
|
-
|
27
|
-
it("ignores invalid messages", function() { with(this) {
|
28
|
-
var response = null
|
29
|
-
server.process([{}, {channel: "invalid"}], false, function(r) { response = r})
|
30
|
-
assertEqual([
|
31
|
-
{ successful: false,
|
32
|
-
error: "405::Invalid channel"
|
33
|
-
},
|
34
|
-
{ channel: "invalid",
|
35
|
-
successful: false,
|
36
|
-
error: "405:invalid:Invalid channel"
|
37
|
-
}
|
38
|
-
], response)
|
39
|
-
}})
|
40
|
-
|
41
|
-
it("rejects unknown meta channels", function() { with(this) {
|
42
|
-
var response = null
|
43
|
-
server.process([{channel: "/meta/p"}], false, function(r) { response = r })
|
44
|
-
assertEqual([
|
45
|
-
{ channel: "/meta/p",
|
46
|
-
successful: false,
|
47
|
-
error: "403:/meta/p:Forbidden channel"
|
48
|
-
}
|
49
|
-
], response)
|
50
|
-
}})
|
51
|
-
|
52
|
-
it("routes single messages to appropriate handlers", function() { with(this) {
|
53
|
-
expect(server, "handshake").given(handshake, false).yielding([{}])
|
54
|
-
server.process(handshake, false, function() {})
|
55
|
-
}})
|
56
|
-
|
57
|
-
it("routes a list of messages to appropriate handlers", function() { with(this) {
|
58
|
-
expect(server, "handshake").given(handshake, false).yielding([{}])
|
59
|
-
expect(server, "connect").given(connect, false).yielding([{}])
|
60
|
-
expect(server, "disconnect").given(disconnect, false).yielding([{}])
|
61
|
-
expect(server, "subscribe").given(subscribe, false).yielding([{}])
|
62
|
-
expect(server, "unsubscribe").given(unsubscribe, false).yielding([{}])
|
63
|
-
|
64
|
-
expect(engine, "publish").given(handshake).exactly(0)
|
65
|
-
expect(engine, "publish").given(connect).exactly(0)
|
66
|
-
expect(engine, "publish").given(disconnect).exactly(0)
|
67
|
-
expect(engine, "publish").given(subscribe).exactly(0)
|
68
|
-
expect(engine, "publish").given(unsubscribe).exactly(0)
|
69
|
-
|
70
|
-
expect(engine, "publish").given(publish)
|
71
|
-
|
72
|
-
server.process([handshake, connect, disconnect, subscribe, unsubscribe, publish], false, function() {})
|
73
|
-
}})
|
74
|
-
|
75
|
-
describe("handshaking", function() { with(this) {
|
76
|
-
before(function() { with(this) {
|
77
|
-
expect(server, "handshake").given(handshake, false).yielding([{channel: "/meta/handshake", successful: true}])
|
78
|
-
}})
|
79
|
-
|
80
|
-
it("returns the handshake response with advice", function() { with(this) {
|
81
|
-
server.process(handshake, false, function(response) {
|
82
|
-
assertEqual([
|
83
|
-
{ channel: "/meta/handshake",
|
84
|
-
successful: true,
|
85
|
-
advice: {reconnect: "retry", interval: 0, timeout: 60000}
|
86
|
-
}
|
87
|
-
], response)
|
88
|
-
})
|
89
|
-
}})
|
90
|
-
}})
|
91
|
-
|
92
|
-
describe("connecting for messages", function() { with(this) {
|
93
|
-
before(function() { with(this) {
|
94
|
-
this.messages = [{channel: "/a"}, {channel: "/b"}]
|
95
|
-
expect(server, "connect").given(connect, false).yielding([messages])
|
96
|
-
}})
|
97
|
-
|
98
|
-
it("returns the new messages", function() { with(this) {
|
99
|
-
server.process(connect, false, function(response) {
|
100
|
-
assertEqual( messages, response )
|
101
|
-
})
|
102
|
-
}})
|
103
|
-
}})
|
104
|
-
}})
|
105
|
-
|
106
|
-
describe("#flushConnection", function() { with(this) {
|
107
|
-
before(function() { with(this) {
|
108
|
-
this.message = {clientId: "fakeclientid"}
|
109
|
-
}})
|
110
|
-
|
111
|
-
it("flushes the connection when given one message", function() { with(this) {
|
112
|
-
expect(engine, "flush").given("fakeclientid")
|
113
|
-
server.flushConnection(message)
|
114
|
-
}})
|
115
|
-
|
116
|
-
it("flushes the connection when given a list of messages", function() { with(this) {
|
117
|
-
expect(engine, "flush").given("fakeclientid")
|
118
|
-
server.flushConnection([message])
|
119
|
-
}})
|
120
|
-
}})
|
121
|
-
}})
|
@@ -1,135 +0,0 @@
|
|
1
|
-
JS.ENV.TransportSpec = JS.Test.describe("Transport", function() { with(this) {
|
2
|
-
before(function() { with(this) {
|
3
|
-
this.client = {
|
4
|
-
endpoint: "http://example.com/",
|
5
|
-
endpoints: {},
|
6
|
-
transports: {},
|
7
|
-
getClientId: function() {}
|
8
|
-
}
|
9
|
-
|
10
|
-
if (Faye.Transport.NodeLocal) {
|
11
|
-
this.LocalTransport = Faye.Transport.NodeLocal
|
12
|
-
this.HttpTransport = Faye.Transport.NodeHttp
|
13
|
-
this.inProcess = "in-process"
|
14
|
-
this.longPolling = "long-polling"
|
15
|
-
} else {
|
16
|
-
this.LocalTransport = Faye.Transport.WebSocket
|
17
|
-
this.HttpTransport = Faye.Transport.XHR
|
18
|
-
this.inProcess = "websocket"
|
19
|
-
this.longPolling = "long-polling"
|
20
|
-
}
|
21
|
-
}})
|
22
|
-
|
23
|
-
describe("get", function() { with(this) {
|
24
|
-
before(function() { with(this) {
|
25
|
-
stub(HttpTransport, "isUsable").yields([false])
|
26
|
-
stub(LocalTransport, "isUsable").yields([false])
|
27
|
-
}})
|
28
|
-
|
29
|
-
describe("when no transport is usable", function() { with(this) {
|
30
|
-
it("raises an exception", function() { with(this) {
|
31
|
-
assertThrows(Error, function() { Faye.Transport.get(client, [longPolling, inProcess], []) })
|
32
|
-
}})
|
33
|
-
}})
|
34
|
-
|
35
|
-
describe("when a less preferred transport is usable", function() { with(this) {
|
36
|
-
before(function() { with(this) {
|
37
|
-
stub(HttpTransport, "isUsable").yields([true])
|
38
|
-
}})
|
39
|
-
|
40
|
-
it("returns a transport of the usable type", function() { with(this) {
|
41
|
-
Faye.Transport.get(client, [longPolling, inProcess], [], function(transport) {
|
42
|
-
assertKindOf( HttpTransport, transport )
|
43
|
-
})
|
44
|
-
}})
|
45
|
-
|
46
|
-
it("raises an exception if the usable type is not requested", function() { with(this) {
|
47
|
-
assertThrows(Error, function() { Faye.Transport.get(client, [inProcess], []) })
|
48
|
-
}})
|
49
|
-
|
50
|
-
it("allows the usable type to be specifically selected", function() { with(this) {
|
51
|
-
Faye.Transport.get(client, [longPolling], [], function(transport) {
|
52
|
-
assertKindOf( HttpTransport, transport )
|
53
|
-
})
|
54
|
-
}})
|
55
|
-
}})
|
56
|
-
|
57
|
-
describe("when all transports are usable", function() { with(this) {
|
58
|
-
before(function() { with(this) {
|
59
|
-
stub(LocalTransport, "isUsable").yields([true])
|
60
|
-
stub(HttpTransport, "isUsable").yields([true])
|
61
|
-
}})
|
62
|
-
|
63
|
-
it("returns the most preferred type", function() { with(this) {
|
64
|
-
Faye.Transport.get(client, [longPolling, inProcess], [], function(transport) {
|
65
|
-
assertKindOf( LocalTransport, transport )
|
66
|
-
})
|
67
|
-
}})
|
68
|
-
|
69
|
-
it("allows types to be specifically selected", function() { with(this) {
|
70
|
-
Faye.Transport.get(client, [inProcess], [], function(transport) {
|
71
|
-
assertKindOf( LocalTransport, transport )
|
72
|
-
})
|
73
|
-
Faye.Transport.get(client, [longPolling], [], function(transport) {
|
74
|
-
assertKindOf( HttpTransport, transport )
|
75
|
-
})
|
76
|
-
}})
|
77
|
-
}})
|
78
|
-
}})
|
79
|
-
|
80
|
-
describe("send", function() { with(this) {
|
81
|
-
include(JS.Test.FakeClock)
|
82
|
-
before(function() { this.clock.stub() })
|
83
|
-
after(function() { this.clock.reset() })
|
84
|
-
|
85
|
-
describe("for batching transports", function() { with(this) {
|
86
|
-
before(function() { with(this) {
|
87
|
-
this.Transport = Faye.Class(Faye.Transport, {batching: true})
|
88
|
-
this.transport = new Transport(client)
|
89
|
-
}})
|
90
|
-
|
91
|
-
it("does not make an immediate request", function() { with(this) {
|
92
|
-
expect(transport, "request").exactly(0)
|
93
|
-
transport.send({batch: "me"}, 60)
|
94
|
-
}})
|
95
|
-
|
96
|
-
it("queues the message to be sent after a timeout", function() { with(this) {
|
97
|
-
expect(transport, "request").given([{batch: "me"}], 60)
|
98
|
-
transport.send({batch: "me"}, 60)
|
99
|
-
clock.tick(10)
|
100
|
-
}})
|
101
|
-
|
102
|
-
it("allows multiple messages to be batched together", function() { with(this) {
|
103
|
-
expect(transport, "request").given([{id: 1}, {id: 2}], 60)
|
104
|
-
transport.send({id: 1}, 60)
|
105
|
-
transport.send({id: 2}, 60)
|
106
|
-
clock.tick(10)
|
107
|
-
}})
|
108
|
-
|
109
|
-
it("adds advice to connect messages sent with others", function() { with(this) {
|
110
|
-
expect(transport, "request").given([{channel: "/meta/connect", advice: {timeout: 0}}, {}], 60)
|
111
|
-
transport.send({channel: "/meta/connect"}, 60)
|
112
|
-
transport.send({}, 60)
|
113
|
-
clock.tick(10)
|
114
|
-
}})
|
115
|
-
|
116
|
-
it("adds no advice to connect messages sent alone", function() { with(this) {
|
117
|
-
expect(transport, "request").given([{channel: "/meta/connect"}], 60)
|
118
|
-
transport.send({channel: "/meta/connect"}, 60)
|
119
|
-
clock.tick(10)
|
120
|
-
}})
|
121
|
-
}})
|
122
|
-
|
123
|
-
describe("for non-batching transports", function() { with(this) {
|
124
|
-
before(function() { with(this) {
|
125
|
-
this.Transport = Faye.Class(Faye.Transport, {batching: false})
|
126
|
-
this.transport = new Transport(client)
|
127
|
-
}})
|
128
|
-
|
129
|
-
it("makes a request immediately", function() { with(this) {
|
130
|
-
expect(transport, "request").given([{no: "batch"}], 60)
|
131
|
-
transport.send({no: "batch"}, 60)
|
132
|
-
}})
|
133
|
-
}})
|
134
|
-
}})
|
135
|
-
}})
|
data/spec/node.js
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
require('jsclass')
|
2
|
-
Faye = require('../build/node/faye-node')
|
3
|
-
Faye.logger = function() {}
|
4
|
-
|
5
|
-
JS.Packages(function() { with(this) {
|
6
|
-
autoload(/.*Spec/, {from: 'spec/javascript'})
|
7
|
-
}})
|
8
|
-
|
9
|
-
FakeSocket = function() {
|
10
|
-
this._fragments = []
|
11
|
-
}
|
12
|
-
FakeSocket.prototype.write = function(buffer, encoding) {
|
13
|
-
this._fragments.push([buffer, encoding])
|
14
|
-
}
|
15
|
-
FakeSocket.prototype.read = function() {
|
16
|
-
var output = []
|
17
|
-
this._fragments.forEach(function(buffer, i) {
|
18
|
-
for (var j = 0, n = buffer[0].length; j < n; j++)
|
19
|
-
output.push(buffer[0][j])
|
20
|
-
})
|
21
|
-
return output
|
22
|
-
}
|
23
|
-
FakeSocket.prototype.addListener = function() {}
|
24
|
-
|
25
|
-
JS.require('Faye', 'JS.Test', 'JS.Range', function() {
|
26
|
-
JS.Test.Unit.Assertions.include({
|
27
|
-
assertYield: function(expected) {
|
28
|
-
var testcase = this
|
29
|
-
return function(actual) { testcase.assertEqual(expected, actual) }
|
30
|
-
}
|
31
|
-
})
|
32
|
-
|
33
|
-
JS.ENV.Engine = {}
|
34
|
-
JS.ENV.Server = {}
|
35
|
-
|
36
|
-
JS.require( 'FayeSpec',
|
37
|
-
'GrammarSpec',
|
38
|
-
'PublisherSpec',
|
39
|
-
'ChannelSpec',
|
40
|
-
'EngineSpec',
|
41
|
-
'Engine.MemorySpec',
|
42
|
-
'ServerSpec',
|
43
|
-
'Server.HandshakeSpec',
|
44
|
-
'Server.ConnectSpec',
|
45
|
-
'Server.DisconnectSpec',
|
46
|
-
'Server.SubscribeSpec',
|
47
|
-
'Server.UnsubscribeSpec',
|
48
|
-
'Server.PublishSpec',
|
49
|
-
'Server.ExtensionsSpec',
|
50
|
-
'Server.IntegrationSpec',
|
51
|
-
'NodeAdapterSpec',
|
52
|
-
'ClientSpec',
|
53
|
-
'TransportSpec',
|
54
|
-
JS.Test.method('autorun'))
|
55
|
-
})
|
data/spec/phantom.js
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
// This script should be run with PhantomJS
|
2
|
-
// http://www.phantomjs.org/
|
3
|
-
|
4
|
-
var page = new WebPage()
|
5
|
-
|
6
|
-
page.onConsoleMessage = function(message) {
|
7
|
-
try {
|
8
|
-
var result = JSON.parse(message)
|
9
|
-
if ('total' in result && 'fail' in result) {
|
10
|
-
console.log(message)
|
11
|
-
var status = (!result.fail && !result.error) ? 0 : 1
|
12
|
-
phantom.exit(status)
|
13
|
-
}
|
14
|
-
} catch (e) {}
|
15
|
-
}
|
16
|
-
|
17
|
-
page.open('spec/browser.html')
|
data/spec/ruby/channel_spec.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Faye::Channel do
|
4
|
-
describe :expand do
|
5
|
-
it "returns all patterns that match a channel" do
|
6
|
-
Faye::Channel.expand("/foo").should == [
|
7
|
-
"/**", "/foo", "/*"]
|
8
|
-
|
9
|
-
Faye::Channel.expand("/foo/bar").should == [
|
10
|
-
"/**", "/foo/bar", "/foo/*", "/foo/**"]
|
11
|
-
|
12
|
-
Faye::Channel.expand("/foo/bar/qux").should == [
|
13
|
-
"/**", "/foo/bar/qux", "/foo/bar/*", "/foo/**", "/foo/bar/**"]
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
data/spec/ruby/client_spec.rb
DELETED
@@ -1,741 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Faye::Client do
|
4
|
-
let :transport do
|
5
|
-
transport = mock("transport", :cookies= => nil, :endpoint => "http://www.example.com/faye", :headers= => nil)
|
6
|
-
transport.stub(:connection_type).and_return "fake"
|
7
|
-
transport.stub(:send)
|
8
|
-
transport.extend(Faye::Publisher)
|
9
|
-
transport
|
10
|
-
end
|
11
|
-
|
12
|
-
before { EM.stub(:add_timer) }
|
13
|
-
|
14
|
-
def stub_response(response)
|
15
|
-
transport.stub(:send) do |message, *args|
|
16
|
-
response["id"] = message["id"]
|
17
|
-
@client.receive_message(response)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def create_client
|
22
|
-
Faye::Transport.stub(:get).and_yield(transport)
|
23
|
-
@client = Faye::Client.new("http://localhost/")
|
24
|
-
end
|
25
|
-
|
26
|
-
def create_connected_client
|
27
|
-
create_client
|
28
|
-
stub_response "channel" => "/meta/handshake",
|
29
|
-
"successful" => true,
|
30
|
-
"version" => "1.0",
|
31
|
-
"supportedConnectionTypes" => ["websocket"],
|
32
|
-
"clientId" => "fakeid"
|
33
|
-
|
34
|
-
@client.handshake
|
35
|
-
end
|
36
|
-
|
37
|
-
def subscribe(client, channel, callback = nil)
|
38
|
-
stub_response "channel" => "/meta/subscribe",
|
39
|
-
"successful" => true,
|
40
|
-
"clientId" => "fakeid",
|
41
|
-
"subscription" => channel
|
42
|
-
|
43
|
-
@subs_called = 0
|
44
|
-
callback ||= lambda { |m| @subs_called = 1 }
|
45
|
-
@client.subscribe(channel, &callback)
|
46
|
-
end
|
47
|
-
|
48
|
-
describe :initialize do
|
49
|
-
it "puts the client in the UNCONNECTED state" do
|
50
|
-
Faye::Transport.stub(:get)
|
51
|
-
client = Faye::Client.new("http://localhost/")
|
52
|
-
client.state.should == :UNCONNECTED
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
describe :handshake do
|
57
|
-
before { create_client }
|
58
|
-
|
59
|
-
it "creates a transport the server must support" do
|
60
|
-
Faye::Transport.should_receive(:get).with(instance_of(Faye::Client),
|
61
|
-
["long-polling", "callback-polling", "in-process"],
|
62
|
-
[]).
|
63
|
-
and_yield(transport)
|
64
|
-
@client.handshake
|
65
|
-
end
|
66
|
-
|
67
|
-
it "sends a handshake message to the server" do
|
68
|
-
transport.should_receive(:send).with({
|
69
|
-
"channel" => "/meta/handshake",
|
70
|
-
"version" => "1.0",
|
71
|
-
"supportedConnectionTypes" => ["fake"],
|
72
|
-
"id" => instance_of(String)
|
73
|
-
}, 60)
|
74
|
-
@client.handshake
|
75
|
-
end
|
76
|
-
|
77
|
-
it "puts the client in the CONNECTING state" do
|
78
|
-
transport.stub(:send)
|
79
|
-
@client.handshake
|
80
|
-
@client.state.should == :CONNECTING
|
81
|
-
end
|
82
|
-
|
83
|
-
describe "with an outgoing extension installed" do
|
84
|
-
before do
|
85
|
-
extension = Class.new do
|
86
|
-
def outgoing(message, callback)
|
87
|
-
message["ext"] = {"auth" => "password"}
|
88
|
-
callback.call(message)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
@client.add_extension(extension.new)
|
92
|
-
end
|
93
|
-
|
94
|
-
it "passes the handshake message through the extension" do
|
95
|
-
transport.should_receive(:send).with({
|
96
|
-
"channel" => "/meta/handshake",
|
97
|
-
"version" => "1.0",
|
98
|
-
"supportedConnectionTypes" => ["fake"],
|
99
|
-
"id" => instance_of(String),
|
100
|
-
"ext" => {"auth" => "password"}
|
101
|
-
}, 60)
|
102
|
-
@client.handshake
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
describe "on successful response" do
|
107
|
-
before do
|
108
|
-
stub_response "channel" => "/meta/handshake",
|
109
|
-
"successful" => true,
|
110
|
-
"version" => "1.0",
|
111
|
-
"supportedConnectionTypes" => ["long-polling", "websocket"],
|
112
|
-
"clientId" => "fakeid"
|
113
|
-
end
|
114
|
-
|
115
|
-
it "stores the clientId" do
|
116
|
-
@client.handshake
|
117
|
-
@client.client_id.should == "fakeid"
|
118
|
-
end
|
119
|
-
|
120
|
-
it "puts the client in the CONNECTED state" do
|
121
|
-
@client.handshake
|
122
|
-
@client.state.should == :CONNECTED
|
123
|
-
end
|
124
|
-
|
125
|
-
it "registers any pre-existing subscriptions" do
|
126
|
-
@client.should_receive(:subscribe).with([], true)
|
127
|
-
@client.handshake
|
128
|
-
end
|
129
|
-
|
130
|
-
it "selects a new transport based on what the server supports" do
|
131
|
-
Faye::Transport.should_receive(:get).with(instance_of(Faye::Client),
|
132
|
-
["long-polling", "websocket"],
|
133
|
-
[]).
|
134
|
-
and_return(transport)
|
135
|
-
@client.handshake
|
136
|
-
end
|
137
|
-
|
138
|
-
describe "with websocket disabled" do
|
139
|
-
before { @client.disable("websocket") }
|
140
|
-
|
141
|
-
it "selects a new transport, excluding websocket" do
|
142
|
-
Faye::Transport.should_receive(:get).with(instance_of(Faye::Client),
|
143
|
-
["long-polling", "websocket"],
|
144
|
-
["websocket"]).
|
145
|
-
and_return(transport)
|
146
|
-
@client.handshake
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
describe "on unsuccessful response" do
|
152
|
-
before do
|
153
|
-
stub_response "channel" => "/meta/handshake",
|
154
|
-
"successful" => false,
|
155
|
-
"version" => "1.0",
|
156
|
-
"supportedConnectionTypes" => ["websocket"]
|
157
|
-
end
|
158
|
-
|
159
|
-
it "schedules a retry" do
|
160
|
-
EM.should_receive(:add_timer)
|
161
|
-
@client.handshake
|
162
|
-
end
|
163
|
-
|
164
|
-
it "puts the client in the UNCONNECTED state" do
|
165
|
-
EM.stub(:add_timer)
|
166
|
-
@client.handshake
|
167
|
-
@client.state.should == :UNCONNECTED
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
describe "with existing subscriptions after a server restart" do
|
172
|
-
before do
|
173
|
-
create_connected_client
|
174
|
-
|
175
|
-
@message = nil
|
176
|
-
subscribe @client, "/messages/foo", lambda { |m| @message = m }
|
177
|
-
|
178
|
-
@client.receive_message "advice" => {"reconnect" => "handshake"}
|
179
|
-
|
180
|
-
stub_response "channel" => "/meta/handshake",
|
181
|
-
"successful" => true,
|
182
|
-
"version" => "1.0",
|
183
|
-
"supportedConnectionTypes" => ["websocket"],
|
184
|
-
"clientId" => "reconnectid"
|
185
|
-
end
|
186
|
-
|
187
|
-
it "resends the subscriptions to the server" do
|
188
|
-
transport.should_receive(:send).with(hash_including("channel" => "/meta/handshake"), 60)
|
189
|
-
transport.should_receive(:send).with({
|
190
|
-
"channel" => "/meta/subscribe",
|
191
|
-
"clientId" => "reconnectid",
|
192
|
-
"subscription" => "/messages/foo",
|
193
|
-
"id" => instance_of(String)
|
194
|
-
}, 60)
|
195
|
-
@client.handshake
|
196
|
-
end
|
197
|
-
|
198
|
-
it "retains the listeners for the subscriptions" do
|
199
|
-
@client.handshake
|
200
|
-
@client.receive_message("channel" => "/messages/foo", "data" => "ok")
|
201
|
-
@message.should == "ok"
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
describe "with a connected client" do
|
206
|
-
before { create_connected_client }
|
207
|
-
|
208
|
-
it "does not send a handshake message to the server" do
|
209
|
-
transport.should_not_receive(:send).with({
|
210
|
-
"channel" => "/meta/handshake",
|
211
|
-
"version" => "1.0",
|
212
|
-
"supportedConnectionTypes" => ["fake"],
|
213
|
-
"id" => instance_of(String)
|
214
|
-
}, 60)
|
215
|
-
@client.handshake
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
describe :connect do
|
221
|
-
describe "with an unconnected client" do
|
222
|
-
before do
|
223
|
-
stub_response "channel" => "/meta/handshake",
|
224
|
-
"successful" => true,
|
225
|
-
"version" => "1.0",
|
226
|
-
"supportedConnectionTypes" => ["websocket"],
|
227
|
-
"clientId" => "handshakeid"
|
228
|
-
|
229
|
-
create_client
|
230
|
-
end
|
231
|
-
|
232
|
-
it "handshakes before connecting" do
|
233
|
-
transport.should_receive(:send).with({
|
234
|
-
"channel" => "/meta/connect",
|
235
|
-
"clientId" => "handshakeid",
|
236
|
-
"connectionType" => "fake",
|
237
|
-
"id" => instance_of(String)
|
238
|
-
}, 60)
|
239
|
-
@client.connect
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
describe "with a connected client" do
|
244
|
-
before { create_connected_client }
|
245
|
-
|
246
|
-
it "sends a connect message to the server" do
|
247
|
-
transport.should_receive(:send).with({
|
248
|
-
"channel" => "/meta/connect",
|
249
|
-
"clientId" => "fakeid",
|
250
|
-
"connectionType" => "fake",
|
251
|
-
"id" => instance_of(String)
|
252
|
-
}, 60)
|
253
|
-
@client.connect
|
254
|
-
end
|
255
|
-
|
256
|
-
it "only opens one connect request at a time" do
|
257
|
-
transport.should_receive(:send).with({
|
258
|
-
"channel" => "/meta/connect",
|
259
|
-
"clientId" => "fakeid",
|
260
|
-
"connectionType" => "fake",
|
261
|
-
"id" => instance_of(String)
|
262
|
-
}, 60).
|
263
|
-
exactly(1).
|
264
|
-
and_return # override stub implementation
|
265
|
-
|
266
|
-
@client.connect
|
267
|
-
@client.connect
|
268
|
-
end
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
describe :disconnect do
|
273
|
-
before { create_connected_client }
|
274
|
-
|
275
|
-
it "sends a disconnect message to the server" do
|
276
|
-
transport.stub(:close)
|
277
|
-
transport.should_receive(:send).with({
|
278
|
-
"channel" => "/meta/disconnect",
|
279
|
-
"clientId" => "fakeid",
|
280
|
-
"id" => instance_of(String)
|
281
|
-
}, 60)
|
282
|
-
@client.disconnect
|
283
|
-
end
|
284
|
-
|
285
|
-
it "puts the client in the DISCONNECTED state" do
|
286
|
-
transport.stub(:close)
|
287
|
-
@client.disconnect
|
288
|
-
@client.state.should == :DISCONNECTED
|
289
|
-
end
|
290
|
-
|
291
|
-
describe "on successful response" do
|
292
|
-
before do
|
293
|
-
stub_response "channel" => "/meta/disconnect",
|
294
|
-
"successful" => true,
|
295
|
-
"clientId" => "fakeid"
|
296
|
-
end
|
297
|
-
|
298
|
-
it "closes the transport" do
|
299
|
-
transport.should_receive(:close)
|
300
|
-
@client.disconnect
|
301
|
-
end
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
describe :subscribe do
|
306
|
-
before do
|
307
|
-
create_connected_client
|
308
|
-
@subscribe_message = {
|
309
|
-
"channel" => "/meta/subscribe",
|
310
|
-
"clientId" => "fakeid",
|
311
|
-
"subscription" => "/foo/*",
|
312
|
-
"id" => instance_of(String)
|
313
|
-
}
|
314
|
-
end
|
315
|
-
|
316
|
-
describe "with no prior subscriptions" do
|
317
|
-
it "sends a subscribe message to the server" do
|
318
|
-
transport.should_receive(:send).with(@subscribe_message, 60)
|
319
|
-
@client.subscribe("/foo/*")
|
320
|
-
end
|
321
|
-
|
322
|
-
# The Bayeux spec says the server should accept a list of subscriptions
|
323
|
-
# in one message but the cometD server doesn't actually support this
|
324
|
-
describe "with an array of subscriptions" do
|
325
|
-
it "sends multiple subscribe messages" do
|
326
|
-
transport.should_receive(:send).with({
|
327
|
-
"channel" => "/meta/subscribe",
|
328
|
-
"clientId" => "fakeid",
|
329
|
-
"subscription" => "/foo",
|
330
|
-
"id" => instance_of(String)
|
331
|
-
}, 60)
|
332
|
-
transport.should_receive(:send).with({
|
333
|
-
"channel" => "/meta/subscribe",
|
334
|
-
"clientId" => "fakeid",
|
335
|
-
"subscription" => "/bar",
|
336
|
-
"id" => instance_of(String)
|
337
|
-
}, 60)
|
338
|
-
@client.subscribe(["/foo", "/bar"])
|
339
|
-
end
|
340
|
-
|
341
|
-
it "returns an array of subscriptions" do
|
342
|
-
transport.stub(:send)
|
343
|
-
subs = @client.subscribe(["/foo", "/bar"])
|
344
|
-
subs.size.should == 2
|
345
|
-
subs.should be_all { |s| Faye::Subscription === s }
|
346
|
-
end
|
347
|
-
end
|
348
|
-
|
349
|
-
describe "on successful response" do
|
350
|
-
before do
|
351
|
-
stub_response "channel" => "/meta/subscribe",
|
352
|
-
"successful" => true,
|
353
|
-
"clientId" => "fakeid",
|
354
|
-
"subscription" => "/foo/*"
|
355
|
-
end
|
356
|
-
|
357
|
-
it "sets up a listener for the subscribed channel" do
|
358
|
-
@message = nil
|
359
|
-
@client.subscribe("/foo/*") { |m| @message = m }
|
360
|
-
@client.receive_message("channel" => "/foo/bar", "data" => "hi")
|
361
|
-
@message.should == "hi"
|
362
|
-
end
|
363
|
-
|
364
|
-
it "does not call the listener for non-matching channels" do
|
365
|
-
@message = nil
|
366
|
-
@client.subscribe("/foo/*") { |m| @message = m }
|
367
|
-
@client.receive_message("channel" => "/bar", "data" => "hi")
|
368
|
-
@message.should be_nil
|
369
|
-
end
|
370
|
-
|
371
|
-
it "activates the subscription" do
|
372
|
-
active = false
|
373
|
-
@client.subscribe("/foo/*").callback { active = true }
|
374
|
-
active.should be_true
|
375
|
-
end
|
376
|
-
|
377
|
-
describe "with an incoming extension installed" do
|
378
|
-
before do
|
379
|
-
extension = Class.new do
|
380
|
-
def incoming(message, callback)
|
381
|
-
message["data"]["changed"] = true if message["data"]
|
382
|
-
callback.call(message)
|
383
|
-
end
|
384
|
-
end
|
385
|
-
@client.add_extension(extension.new)
|
386
|
-
@message = nil
|
387
|
-
@client.subscribe("/foo/*") { |m| @message = m }
|
388
|
-
end
|
389
|
-
|
390
|
-
it "passes delivered messages through the extension" do
|
391
|
-
@client.receive_message("channel" => "/foo/bar", "data" => {"hello" => "there"})
|
392
|
-
@message.should == {"hello" => "there", "changed" => true}
|
393
|
-
end
|
394
|
-
end
|
395
|
-
|
396
|
-
describe "with an outgoing extension installed" do
|
397
|
-
before do
|
398
|
-
extension = Class.new do
|
399
|
-
def outgoing(message, callback)
|
400
|
-
message["data"]["changed"] = true if message["data"]
|
401
|
-
callback.call(message)
|
402
|
-
end
|
403
|
-
end
|
404
|
-
@client.add_extension(extension.new)
|
405
|
-
@message = nil
|
406
|
-
@client.subscribe("/foo/*") { |m| @message = m }
|
407
|
-
end
|
408
|
-
|
409
|
-
it "leaves messages unchanged" do
|
410
|
-
@client.receive_message("channel" => "/foo/bar", "data" => {"hello" => "there"})
|
411
|
-
@message.should == {"hello" => "there"}
|
412
|
-
end
|
413
|
-
end
|
414
|
-
|
415
|
-
describe "with an incoming extension that invalidates the response" do
|
416
|
-
before do
|
417
|
-
extension = Class.new do
|
418
|
-
def incoming(message, callback)
|
419
|
-
message["successful"] = false if message["channel"] == "/meta/subscribe"
|
420
|
-
callback.call(message)
|
421
|
-
end
|
422
|
-
end
|
423
|
-
@client.add_extension(extension.new)
|
424
|
-
end
|
425
|
-
|
426
|
-
it "does not set up a listener for the subscribed channel" do
|
427
|
-
@message = nil
|
428
|
-
@client.subscribe("/foo/*") { |m| @message = m }
|
429
|
-
@client.receive_message("channel" => "/foo/bar", "data" => "hi")
|
430
|
-
@message.should be_nil
|
431
|
-
end
|
432
|
-
|
433
|
-
it "does not activate the subscription" do
|
434
|
-
active = false
|
435
|
-
@client.subscribe("/foo/*").callback { active = true }
|
436
|
-
active.should be_false
|
437
|
-
end
|
438
|
-
end
|
439
|
-
end
|
440
|
-
|
441
|
-
describe "on unsuccessful response" do
|
442
|
-
before do
|
443
|
-
stub_response "channel" => "/meta/subscribe",
|
444
|
-
"error" => "403:/meta/foo:Forbidden channel",
|
445
|
-
"successful" => false,
|
446
|
-
"clientId" => "fakeid",
|
447
|
-
"subscription" => "/meta/foo"
|
448
|
-
end
|
449
|
-
|
450
|
-
it "does not set up a listener for the subscribed channel" do
|
451
|
-
@message = nil
|
452
|
-
@client.subscribe("/meta/foo") { |m| @message = m }
|
453
|
-
@client.receive_message("channel" => "/meta/foo", "data" => "hi")
|
454
|
-
@message.should be_nil
|
455
|
-
end
|
456
|
-
|
457
|
-
it "does not activate the subscription" do
|
458
|
-
active = false
|
459
|
-
@client.subscribe("/meta/foo").callback { active = true }
|
460
|
-
active.should be_false
|
461
|
-
end
|
462
|
-
|
463
|
-
it "reports the error through an errback" do
|
464
|
-
error = nil
|
465
|
-
@client.subscribe("/meta/foo").errback { |e| error = e }
|
466
|
-
error.code.should == 403
|
467
|
-
error.params.should == ["/meta/foo"]
|
468
|
-
error.message.should == "Forbidden channel"
|
469
|
-
end
|
470
|
-
end
|
471
|
-
end
|
472
|
-
|
473
|
-
describe "with an existing subscription" do
|
474
|
-
before do
|
475
|
-
subscribe @client, "/foo/*"
|
476
|
-
end
|
477
|
-
|
478
|
-
it "does not send another subscribe message to the server" do
|
479
|
-
transport.should_not_receive(:send).with(@subscribe_message, 60)
|
480
|
-
@client.subscribe("/foo/*")
|
481
|
-
end
|
482
|
-
|
483
|
-
it "sets up another listener on the channel" do
|
484
|
-
@client.subscribe("/foo/*") { @subs_called += 1 }
|
485
|
-
@client.receive_message("channel" => "/foo/bar", "data" => "hi")
|
486
|
-
@subs_called.should == 2
|
487
|
-
end
|
488
|
-
|
489
|
-
it "activates the subscription" do
|
490
|
-
active = false
|
491
|
-
@client.subscribe("/foo/*").callback { active = true }
|
492
|
-
active.should be_true
|
493
|
-
end
|
494
|
-
end
|
495
|
-
end
|
496
|
-
|
497
|
-
describe :unsubscribe do
|
498
|
-
before do
|
499
|
-
create_connected_client
|
500
|
-
@unsubscribe_message = {
|
501
|
-
"channel" => "/meta/unsubscribe",
|
502
|
-
"clientId" => "fakeid",
|
503
|
-
"subscription" => "/foo/*",
|
504
|
-
"id" => instance_of(String)
|
505
|
-
}
|
506
|
-
end
|
507
|
-
|
508
|
-
describe "with no subscriptions" do
|
509
|
-
it "does not send an unsubscribe message to the server" do
|
510
|
-
transport.should_not_receive(:send).with(@unsubscribe_message, 60)
|
511
|
-
@client.unsubscribe("/foo/*")
|
512
|
-
end
|
513
|
-
end
|
514
|
-
|
515
|
-
describe "with a single subscription" do
|
516
|
-
before do
|
517
|
-
@message = nil
|
518
|
-
@listener = lambda { |m| @message = m }
|
519
|
-
subscribe @client, "/foo/*", @listener
|
520
|
-
end
|
521
|
-
|
522
|
-
it "sends an unsubscribe message to the server" do
|
523
|
-
transport.should_receive(:send).with(@unsubscribe_message, 60)
|
524
|
-
@client.unsubscribe("/foo/*")
|
525
|
-
end
|
526
|
-
|
527
|
-
it "removes the listener from the channel" do
|
528
|
-
@client.receive_message("channel" => "/foo/bar", "data" => "first")
|
529
|
-
@client.unsubscribe("/foo/*", &@listener)
|
530
|
-
@client.receive_message("channel" => "/foo/bar", "data" => "second")
|
531
|
-
@message.should == "first"
|
532
|
-
end
|
533
|
-
end
|
534
|
-
|
535
|
-
describe "with multiple subscriptions to the same channel" do
|
536
|
-
before do
|
537
|
-
@messages = []
|
538
|
-
@hey = lambda { |m| @messages << ("hey " + m["text"]) }
|
539
|
-
@bye = lambda { |m| @messages << ("bye " + m["text"]) }
|
540
|
-
subscribe @client, "/foo/*", @hey
|
541
|
-
subscribe @client, "/foo/*", @bye
|
542
|
-
end
|
543
|
-
|
544
|
-
it "removes one of the listeners from the channel" do
|
545
|
-
@client.receive_message("channel" => "/foo/bar", "data" => {"text" => "you"})
|
546
|
-
@client.unsubscribe("/foo/*", &@hey)
|
547
|
-
@client.receive_message("channel" => "/foo/bar", "data" => {"text" => "you"})
|
548
|
-
@messages.should == ["hey you", "bye you", "bye you"]
|
549
|
-
end
|
550
|
-
|
551
|
-
it "does not send an unsubscribe message if one listener is removed" do
|
552
|
-
transport.should_not_receive(:send).with(@unsubscribe_message, 60)
|
553
|
-
@client.unsubscribe("/foo/*", &@bye)
|
554
|
-
end
|
555
|
-
|
556
|
-
it "sends an unsubscribe message if each listener is removed" do
|
557
|
-
transport.should_receive(:send).with(@unsubscribe_message, 60)
|
558
|
-
@client.unsubscribe("/foo/*", &@bye)
|
559
|
-
@client.unsubscribe("/foo/*", &@hey)
|
560
|
-
end
|
561
|
-
|
562
|
-
it "sends an unsubscribe message if all listeners are removed" do
|
563
|
-
transport.should_receive(:send).with(@unsubscribe_message, 60)
|
564
|
-
@client.unsubscribe("/foo/*")
|
565
|
-
end
|
566
|
-
end
|
567
|
-
|
568
|
-
describe "with multiple subscriptions to different channels" do
|
569
|
-
before do
|
570
|
-
subscribe @client, "/foo"
|
571
|
-
subscribe @client, "/bar"
|
572
|
-
end
|
573
|
-
|
574
|
-
it "sends multiple unsubscribe messages if given an array" do
|
575
|
-
transport.should_receive(:send).with({
|
576
|
-
"channel" => "/meta/unsubscribe",
|
577
|
-
"clientId" => "fakeid",
|
578
|
-
"subscription" => "/foo",
|
579
|
-
"id" => instance_of(String)
|
580
|
-
}, 60)
|
581
|
-
transport.should_receive(:send).with({
|
582
|
-
"channel" => "/meta/unsubscribe",
|
583
|
-
"clientId" => "fakeid",
|
584
|
-
"subscription" => "/bar",
|
585
|
-
"id" => instance_of(String)
|
586
|
-
}, 60)
|
587
|
-
@client.unsubscribe(["/foo", "/bar"])
|
588
|
-
end
|
589
|
-
end
|
590
|
-
end
|
591
|
-
|
592
|
-
describe :publish do
|
593
|
-
before { create_connected_client }
|
594
|
-
|
595
|
-
it "sends the message to the server with an ID" do
|
596
|
-
transport.should_receive(:send).with({
|
597
|
-
"channel" => "/messages/foo",
|
598
|
-
"clientId" => "fakeid",
|
599
|
-
"data" => {"hello" => "world"},
|
600
|
-
"id" => instance_of(String)
|
601
|
-
}, 60)
|
602
|
-
@client.publish("/messages/foo", "hello" => "world")
|
603
|
-
end
|
604
|
-
|
605
|
-
it "throws an error when publishing to an invalid channel" do
|
606
|
-
transport.should_not_receive(:send).with(hash_including("channel" => "/messages/*"), 60)
|
607
|
-
lambda { @client.publish("/messages/*", "hello" => "world") }.should raise_error
|
608
|
-
end
|
609
|
-
|
610
|
-
describe "on publish failure" do
|
611
|
-
before do
|
612
|
-
stub_response "channel" => "/messages/foo",
|
613
|
-
"error" => "407:/messages/foo:Failed to publish",
|
614
|
-
"successful" => false,
|
615
|
-
"clientId" => "fakeid"
|
616
|
-
end
|
617
|
-
|
618
|
-
it "should not be published" do
|
619
|
-
published = false
|
620
|
-
@client.publish("/messages/foo", "text" => "hi").callback { published = true }
|
621
|
-
published.should be_false
|
622
|
-
end
|
623
|
-
|
624
|
-
it "reports the error through an errback" do
|
625
|
-
error = nil
|
626
|
-
@client.publish("/messages/foo", "text" => "hi").errback { |e| error = e }
|
627
|
-
error.code.should == 407
|
628
|
-
error.params.should == ["/messages/foo"]
|
629
|
-
error.message.should == "Failed to publish"
|
630
|
-
end
|
631
|
-
end
|
632
|
-
|
633
|
-
describe "on receipt of the published message" do
|
634
|
-
before do
|
635
|
-
stub_response "channel" => "/messages/foo",
|
636
|
-
"data" => {"text" => "hi"},
|
637
|
-
"clientId" => "fakeid"
|
638
|
-
end
|
639
|
-
|
640
|
-
it "does not trigger the callbacks" do
|
641
|
-
published = false
|
642
|
-
publication = @client.publish("/messages/foo", "text" => "hi")
|
643
|
-
publication.callback { published = true }
|
644
|
-
publication.errback { published = true }
|
645
|
-
published.should be_false
|
646
|
-
end
|
647
|
-
end
|
648
|
-
|
649
|
-
describe "with an outgoing extension installed" do
|
650
|
-
before do
|
651
|
-
extension = Class.new do
|
652
|
-
def outgoing(message, callback)
|
653
|
-
message["ext"] = {"auth" => "password"}
|
654
|
-
callback.call(message)
|
655
|
-
end
|
656
|
-
end
|
657
|
-
@client.add_extension(extension.new)
|
658
|
-
end
|
659
|
-
|
660
|
-
it "passes messages through the extension" do
|
661
|
-
transport.should_receive(:send).with({
|
662
|
-
"channel" => "/messages/foo",
|
663
|
-
"clientId" => "fakeid",
|
664
|
-
"data" => {"hello" => "world"},
|
665
|
-
"id" => instance_of(String),
|
666
|
-
"ext" => {"auth" => "password"}
|
667
|
-
}, 60)
|
668
|
-
@client.publish("/messages/foo", "hello" => "world")
|
669
|
-
end
|
670
|
-
end
|
671
|
-
|
672
|
-
describe "with an incoming extension installed" do
|
673
|
-
before do
|
674
|
-
extension = Class.new do
|
675
|
-
def incoming(message, callback)
|
676
|
-
message["ext"] = {"auth" => "password"}
|
677
|
-
callback.call(message)
|
678
|
-
end
|
679
|
-
end
|
680
|
-
@client.add_extension(extension.new)
|
681
|
-
end
|
682
|
-
|
683
|
-
it "leaves the message unchanged" do
|
684
|
-
transport.should_receive(:send).with({
|
685
|
-
"channel" => "/messages/foo",
|
686
|
-
"clientId" => "fakeid",
|
687
|
-
"data" => {"hello" => "world"},
|
688
|
-
"id" => instance_of(String)
|
689
|
-
}, 60)
|
690
|
-
@client.publish("/messages/foo", "hello" => "world")
|
691
|
-
end
|
692
|
-
end
|
693
|
-
end
|
694
|
-
|
695
|
-
describe "network notifications" do
|
696
|
-
before {
|
697
|
-
create_client
|
698
|
-
@client.handshake
|
699
|
-
}
|
700
|
-
|
701
|
-
describe "in the default state" do
|
702
|
-
it "broadcasts a down notification" do
|
703
|
-
@client.should_receive(:trigger).with("transport:down")
|
704
|
-
transport.trigger(:down)
|
705
|
-
end
|
706
|
-
|
707
|
-
it "broadcasts an up notification" do
|
708
|
-
@client.should_receive(:trigger).with("transport:up")
|
709
|
-
transport.trigger(:up)
|
710
|
-
end
|
711
|
-
end
|
712
|
-
|
713
|
-
describe "when the transport is up" do
|
714
|
-
before { transport.trigger(:up) }
|
715
|
-
|
716
|
-
it "broadcasts a down notification" do
|
717
|
-
@client.should_receive(:trigger).with("transport:down")
|
718
|
-
transport.trigger(:down)
|
719
|
-
end
|
720
|
-
|
721
|
-
it "does not broadcast an up notification" do
|
722
|
-
@client.should_not_receive(:trigger)
|
723
|
-
transport.trigger(:up)
|
724
|
-
end
|
725
|
-
end
|
726
|
-
|
727
|
-
describe "when the transport is down" do
|
728
|
-
before { transport.trigger(:down) }
|
729
|
-
|
730
|
-
it "does not broadcast a down notification" do
|
731
|
-
@client.should_not_receive(:trigger)
|
732
|
-
transport.trigger(:down)
|
733
|
-
end
|
734
|
-
|
735
|
-
it "broadcasts an up notification" do
|
736
|
-
@client.should_receive(:trigger).with("transport:up")
|
737
|
-
transport.trigger(:up)
|
738
|
-
end
|
739
|
-
end
|
740
|
-
end
|
741
|
-
end
|