spec/ruby/client_spec.rb in faye-0.8.8 vs spec/ruby/client_spec.rb in faye-0.8.9
- old
+ new
@@ -6,13 +6,13 @@
transport.stub(:connection_type).and_return "fake"
transport.stub(:send)
transport.extend(Faye::Publisher)
transport
end
-
+
before { EM.stub(:add_timer) }
-
+
def stub_response(response)
transport.stub(:send) do |message, *args|
response["id"] = message["id"]
@client.receive_message(response)
end
@@ -20,51 +20,52 @@
def create_client
Faye::Transport.stub(:get).and_yield(transport)
@client = Faye::Client.new("http://localhost/")
end
-
+
def create_connected_client
create_client
stub_response "channel" => "/meta/handshake",
"successful" => true,
"version" => "1.0",
"supportedConnectionTypes" => ["websocket"],
"clientId" => "fakeid"
-
+
@client.handshake
end
-
+
def subscribe(client, channel, callback = nil)
stub_response "channel" => "/meta/subscribe",
"successful" => true,
"clientId" => "fakeid",
"subscription" => channel
-
+
@subs_called = 0
callback ||= lambda { |m| @subs_called = 1 }
@client.subscribe(channel, &callback)
end
describe :initialize do
- it "creates a transport the server must support" do
- Faye::Transport.should_receive(:get).with(instance_of(Faye::Client),
- ["long-polling", "callback-polling", "in-process"]).
- and_return(transport)
- Faye::Client.new("http://localhost/")
- end
-
it "puts the client in the UNCONNECTED state" do
Faye::Transport.stub(:get)
client = Faye::Client.new("http://localhost/")
client.state.should == :UNCONNECTED
end
end
describe :handshake do
before { create_client }
+ it "creates a transport the server must support" do
+ Faye::Transport.should_receive(:get).with(instance_of(Faye::Client),
+ ["long-polling", "callback-polling", "in-process"],
+ []).
+ and_yield(transport)
+ @client.handshake
+ end
+
it "sends a handshake message to the server" do
transport.should_receive(:send).with({
"channel" => "/meta/handshake",
"version" => "1.0",
"supportedConnectionTypes" => ["fake"],
@@ -87,11 +88,11 @@
callback.call(message)
end
end
@client.add_extension(extension.new)
end
-
+
it "passes the handshake message through the extension" do
transport.should_receive(:send).with({
"channel" => "/meta/handshake",
"version" => "1.0",
"supportedConnectionTypes" => ["fake"],
@@ -118,27 +119,31 @@
it "puts the client in the CONNECTED state" do
@client.handshake
@client.state.should == :CONNECTED
end
-
+
it "registers any pre-existing subscriptions" do
@client.should_receive(:subscribe).with([], true)
@client.handshake
end
-
+
it "selects a new transport based on what the server supports" do
- Faye::Transport.should_receive(:get).with(instance_of(Faye::Client), ["long-polling", "websocket"]).
+ Faye::Transport.should_receive(:get).with(instance_of(Faye::Client),
+ ["long-polling", "websocket"],
+ []).
and_return(transport)
@client.handshake
end
-
+
describe "with websocket disabled" do
before { @client.disable("websocket") }
-
+
it "selects a new transport, excluding websocket" do
- Faye::Transport.should_receive(:get).with(instance_of(Faye::Client), ["long-polling"]).
+ Faye::Transport.should_receive(:get).with(instance_of(Faye::Client),
+ ["long-polling", "websocket"],
+ ["websocket"]).
and_return(transport)
@client.handshake
end
end
end
@@ -160,48 +165,48 @@
EM.stub(:add_timer)
@client.handshake
@client.state.should == :UNCONNECTED
end
end
-
+
describe "with existing subscriptions after a server restart" do
before do
create_connected_client
-
+
@message = nil
subscribe @client, "/messages/foo", lambda { |m| @message = m }
-
+
@client.receive_message "advice" => {"reconnect" => "handshake"}
-
+
stub_response "channel" => "/meta/handshake",
"successful" => true,
"version" => "1.0",
"supportedConnectionTypes" => ["websocket"],
"clientId" => "reconnectid"
end
-
+
it "resends the subscriptions to the server" do
transport.should_receive(:send).with(hash_including("channel" => "/meta/handshake"), 60)
transport.should_receive(:send).with({
"channel" => "/meta/subscribe",
"clientId" => "reconnectid",
"subscription" => "/messages/foo",
"id" => instance_of(String)
}, 60)
@client.handshake
end
-
+
it "retains the listeners for the subscriptions" do
@client.handshake
@client.receive_message("channel" => "/messages/foo", "data" => "ok")
@message.should == "ok"
end
end
-
+
describe "with a connected client" do
before { create_connected_client }
-
+
it "does not send a handshake message to the server" do
transport.should_not_receive(:send).with({
"channel" => "/meta/handshake",
"version" => "1.0",
"supportedConnectionTypes" => ["fake"],
@@ -209,113 +214,113 @@
}, 60)
@client.handshake
end
end
end
-
+
describe :connect do
describe "with an unconnected client" do
before do
stub_response "channel" => "/meta/handshake",
"successful" => true,
"version" => "1.0",
"supportedConnectionTypes" => ["websocket"],
"clientId" => "handshakeid"
-
+
create_client
end
-
+
it "handshakes before connecting" do
transport.should_receive(:send).with({
"channel" => "/meta/connect",
"clientId" => "handshakeid",
"connectionType" => "fake",
"id" => instance_of(String)
}, 60)
@client.connect
end
end
-
+
describe "with a connected client" do
before { create_connected_client }
-
+
it "sends a connect message to the server" do
transport.should_receive(:send).with({
"channel" => "/meta/connect",
"clientId" => "fakeid",
"connectionType" => "fake",
"id" => instance_of(String)
}, 60)
@client.connect
end
-
+
it "only opens one connect request at a time" do
transport.should_receive(:send).with({
"channel" => "/meta/connect",
"clientId" => "fakeid",
"connectionType" => "fake",
"id" => instance_of(String)
}, 60).
exactly(1).
and_return # override stub implementation
-
+
@client.connect
@client.connect
end
end
end
-
+
describe :disconnect do
before { create_connected_client }
-
+
it "sends a disconnect message to the server" do
transport.stub(:close)
transport.should_receive(:send).with({
"channel" => "/meta/disconnect",
"clientId" => "fakeid",
"id" => instance_of(String)
}, 60)
@client.disconnect
end
-
+
it "puts the client in the DISCONNECTED state" do
transport.stub(:close)
@client.disconnect
@client.state.should == :DISCONNECTED
end
-
+
describe "on successful response" do
before do
stub_response "channel" => "/meta/disconnect",
"successful" => true,
"clientId" => "fakeid"
end
-
+
it "closes the transport" do
transport.should_receive(:close)
@client.disconnect
end
end
end
-
+
describe :subscribe do
before do
create_connected_client
@subscribe_message = {
"channel" => "/meta/subscribe",
"clientId" => "fakeid",
"subscription" => "/foo/*",
"id" => instance_of(String)
}
end
-
+
describe "with no prior subscriptions" do
it "sends a subscribe message to the server" do
transport.should_receive(:send).with(@subscribe_message, 60)
@client.subscribe("/foo/*")
end
-
+
# The Bayeux spec says the server should accept a list of subscriptions
# in one message but the cometD server doesn't actually support this
describe "with an array of subscriptions" do
it "sends multiple subscribe messages" do
transport.should_receive(:send).with({
@@ -330,47 +335,47 @@
"subscription" => "/bar",
"id" => instance_of(String)
}, 60)
@client.subscribe(["/foo", "/bar"])
end
-
+
it "returns an array of subscriptions" do
transport.stub(:send)
subs = @client.subscribe(["/foo", "/bar"])
subs.size.should == 2
subs.should be_all { |s| Faye::Subscription === s }
end
end
-
+
describe "on successful response" do
before do
stub_response "channel" => "/meta/subscribe",
"successful" => true,
"clientId" => "fakeid",
"subscription" => "/foo/*"
end
-
+
it "sets up a listener for the subscribed channel" do
@message = nil
@client.subscribe("/foo/*") { |m| @message = m }
@client.receive_message("channel" => "/foo/bar", "data" => "hi")
@message.should == "hi"
end
-
+
it "does not call the listener for non-matching channels" do
@message = nil
@client.subscribe("/foo/*") { |m| @message = m }
@client.receive_message("channel" => "/bar", "data" => "hi")
@message.should be_nil
end
-
+
it "activates the subscription" do
active = false
@client.subscribe("/foo/*").callback { active = true }
active.should be_true
end
-
+
describe "with an incoming extension installed" do
before do
extension = Class.new do
def incoming(message, callback)
message["data"]["changed"] = true if message["data"]
@@ -379,17 +384,17 @@
end
@client.add_extension(extension.new)
@message = nil
@client.subscribe("/foo/*") { |m| @message = m }
end
-
+
it "passes delivered messages through the extension" do
@client.receive_message("channel" => "/foo/bar", "data" => {"hello" => "there"})
@message.should == {"hello" => "there", "changed" => true}
end
end
-
+
describe "with an outgoing extension installed" do
before do
extension = Class.new do
def outgoing(message, callback)
message["data"]["changed"] = true if message["data"]
@@ -398,59 +403,59 @@
end
@client.add_extension(extension.new)
@message = nil
@client.subscribe("/foo/*") { |m| @message = m }
end
-
+
it "leaves messages unchanged" do
@client.receive_message("channel" => "/foo/bar", "data" => {"hello" => "there"})
@message.should == {"hello" => "there"}
end
end
-
+
describe "with an incoming extension that invalidates the response" do
before do
extension = Class.new do
def incoming(message, callback)
message["successful"] = false if message["channel"] == "/meta/subscribe"
callback.call(message)
end
end
@client.add_extension(extension.new)
end
-
+
it "does not set up a listener for the subscribed channel" do
@message = nil
@client.subscribe("/foo/*") { |m| @message = m }
@client.receive_message("channel" => "/foo/bar", "data" => "hi")
@message.should be_nil
end
-
+
it "does not activate the subscription" do
active = false
@client.subscribe("/foo/*").callback { active = true }
active.should be_false
end
end
end
-
+
describe "on unsuccessful response" do
before do
stub_response "channel" => "/meta/subscribe",
"error" => "403:/meta/foo:Forbidden channel",
"successful" => false,
"clientId" => "fakeid",
"subscription" => "/meta/foo"
end
-
+
it "does not set up a listener for the subscribed channel" do
@message = nil
@client.subscribe("/meta/foo") { |m| @message = m }
@client.receive_message("channel" => "/meta/foo", "data" => "hi")
@message.should be_nil
end
-
+
it "does not activate the subscription" do
active = false
@client.subscribe("/meta/foo").callback { active = true }
active.should be_false
end
@@ -462,112 +467,112 @@
error.params.should == ["/meta/foo"]
error.message.should == "Forbidden channel"
end
end
end
-
+
describe "with an existing subscription" do
before do
subscribe @client, "/foo/*"
end
-
+
it "does not send another subscribe message to the server" do
transport.should_not_receive(:send).with(@subscribe_message, 60)
@client.subscribe("/foo/*")
end
-
+
it "sets up another listener on the channel" do
@client.subscribe("/foo/*") { @subs_called += 1 }
@client.receive_message("channel" => "/foo/bar", "data" => "hi")
@subs_called.should == 2
end
-
+
it "activates the subscription" do
active = false
@client.subscribe("/foo/*").callback { active = true }
active.should be_true
end
end
end
-
+
describe :unsubscribe do
before do
create_connected_client
@unsubscribe_message = {
"channel" => "/meta/unsubscribe",
"clientId" => "fakeid",
"subscription" => "/foo/*",
"id" => instance_of(String)
}
end
-
+
describe "with no subscriptions" do
it "does not send an unsubscribe message to the server" do
transport.should_not_receive(:send).with(@unsubscribe_message, 60)
@client.unsubscribe("/foo/*")
end
end
-
+
describe "with a single subscription" do
before do
@message = nil
@listener = lambda { |m| @message = m }
subscribe @client, "/foo/*", @listener
end
-
+
it "sends an unsubscribe message to the server" do
transport.should_receive(:send).with(@unsubscribe_message, 60)
@client.unsubscribe("/foo/*")
end
-
+
it "removes the listener from the channel" do
@client.receive_message("channel" => "/foo/bar", "data" => "first")
@client.unsubscribe("/foo/*", &@listener)
@client.receive_message("channel" => "/foo/bar", "data" => "second")
@message.should == "first"
end
end
-
+
describe "with multiple subscriptions to the same channel" do
before do
@messages = []
@hey = lambda { |m| @messages << ("hey " + m["text"]) }
@bye = lambda { |m| @messages << ("bye " + m["text"]) }
subscribe @client, "/foo/*", @hey
subscribe @client, "/foo/*", @bye
end
-
+
it "removes one of the listeners from the channel" do
@client.receive_message("channel" => "/foo/bar", "data" => {"text" => "you"})
@client.unsubscribe("/foo/*", &@hey)
@client.receive_message("channel" => "/foo/bar", "data" => {"text" => "you"})
@messages.should == ["hey you", "bye you", "bye you"]
end
-
+
it "does not send an unsubscribe message if one listener is removed" do
transport.should_not_receive(:send).with(@unsubscribe_message, 60)
@client.unsubscribe("/foo/*", &@bye)
end
-
+
it "sends an unsubscribe message if each listener is removed" do
transport.should_receive(:send).with(@unsubscribe_message, 60)
@client.unsubscribe("/foo/*", &@bye)
@client.unsubscribe("/foo/*", &@hey)
end
-
+
it "sends an unsubscribe message if all listeners are removed" do
transport.should_receive(:send).with(@unsubscribe_message, 60)
@client.unsubscribe("/foo/*")
end
end
-
+
describe "with multiple subscriptions to different channels" do
before do
subscribe @client, "/foo"
subscribe @client, "/bar"
end
-
+
it "sends multiple unsubscribe messages if given an array" do
transport.should_receive(:send).with({
"channel" => "/meta/unsubscribe",
"clientId" => "fakeid",
"subscription" => "/foo",
@@ -581,29 +586,29 @@
}, 60)
@client.unsubscribe(["/foo", "/bar"])
end
end
end
-
+
describe :publish do
before { create_connected_client }
-
+
it "sends the message to the server with an ID" do
transport.should_receive(:send).with({
"channel" => "/messages/foo",
"clientId" => "fakeid",
"data" => {"hello" => "world"},
"id" => instance_of(String)
}, 60)
@client.publish("/messages/foo", "hello" => "world")
end
-
+
it "throws an error when publishing to an invalid channel" do
transport.should_not_receive(:send).with(hash_including("channel" => "/messages/*"), 60)
lambda { @client.publish("/messages/*", "hello" => "world") }.should raise_error
end
-
+
describe "on publish failure" do
before do
stub_response "channel" => "/messages/foo",
"error" => "407:/messages/foo:Failed to publish",
"successful" => false,
@@ -622,11 +627,11 @@
error.code.should == 407
error.params.should == ["/messages/foo"]
error.message.should == "Failed to publish"
end
end
-
+
describe "on receipt of the published message" do
before do
stub_response "channel" => "/messages/foo",
"data" => {"text" => "hi"},
"clientId" => "fakeid"
@@ -649,11 +654,11 @@
callback.call(message)
end
end
@client.add_extension(extension.new)
end
-
+
it "passes messages through the extension" do
transport.should_receive(:send).with({
"channel" => "/messages/foo",
"clientId" => "fakeid",
"data" => {"hello" => "world"},
@@ -661,22 +666,22 @@
"ext" => {"auth" => "password"}
}, 60)
@client.publish("/messages/foo", "hello" => "world")
end
end
-
+
describe "with an incoming extension installed" do
before do
extension = Class.new do
def incoming(message, callback)
message["ext"] = {"auth" => "password"}
callback.call(message)
end
end
@client.add_extension(extension.new)
end
-
+
it "leaves the message unchanged" do
transport.should_receive(:send).with({
"channel" => "/messages/foo",
"clientId" => "fakeid",
"data" => {"hello" => "world"},
@@ -684,47 +689,50 @@
}, 60)
@client.publish("/messages/foo", "hello" => "world")
end
end
end
-
+
describe "network notifications" do
- before { create_client }
-
+ before {
+ create_client
+ @client.handshake
+ }
+
describe "in the default state" do
it "broadcasts a down notification" do
@client.should_receive(:trigger).with("transport:down")
transport.trigger(:down)
end
-
+
it "broadcasts an up notification" do
@client.should_receive(:trigger).with("transport:up")
transport.trigger(:up)
end
end
-
+
describe "when the transport is up" do
before { transport.trigger(:up) }
-
+
it "broadcasts a down notification" do
@client.should_receive(:trigger).with("transport:down")
transport.trigger(:down)
end
-
+
it "does not broadcast an up notification" do
@client.should_not_receive(:trigger)
transport.trigger(:up)
end
end
-
+
describe "when the transport is down" do
before { transport.trigger(:down) }
-
+
it "does not broadcast a down notification" do
@client.should_not_receive(:trigger)
transport.trigger(:down)
end
-
+
it "broadcasts an up notification" do
@client.should_receive(:trigger).with("transport:up")
transport.trigger(:up)
end
end