require "spec_helper"

describe Faye::Server do
  let(:engine) { mock "engine" }
  let(:server) { Faye::Server.new }
  
  before do
    Faye::Engine.stub(:get).and_return engine
  end
  
  describe :process do
    let(:handshake)   {{"channel" => "/meta/handshake",   "data" => "handshake"  }}
    let(:connect)     {{"channel" => "/meta/connect",     "data" => "connect"    }}
    let(:disconnect)  {{"channel" => "/meta/disconnect",  "data" => "disconnect" }}
    let(:subscribe)   {{"channel" => "/meta/subscribe",   "data" => "subscribe"  }}
    let(:unsubscribe) {{"channel" => "/meta/unsubscribe", "data" => "unsubscribe"}}
    let(:publish)     {{"channel" => "/some/channel",     "data" => "publish"    }}
    
    before do
      engine.stub(:interval).and_return(0)
      engine.stub(:timeout).and_return(60)
    end
    
    it "returns an empty response for no messages" do
      response = nil
      server.process([], false) { |r| response = r }
      response.should == []
    end
    
    it "ignores invalid messages" do
      response = nil
      server.process([{}, {"channel" => "invalid"}], false) { |r| response = r }
      response.should == []
    end
    
    it "routes single messages to appropriate handlers" do
      server.should_receive(:handshake).with(handshake, false)
      engine.should_receive(:publish).with(handshake)
      server.process(handshake, false)
    end
    
    it "routes a list of messages to appropriate handlers" do
      server.should_receive(:handshake).with(handshake, false)
      server.should_receive(:connect).with(connect, false)
      server.should_receive(:disconnect).with(disconnect, false)
      server.should_receive(:subscribe).with(subscribe, false)
      server.should_receive(:unsubscribe).with(unsubscribe, false)
      
      engine.should_receive(:publish).with(handshake)
      engine.should_receive(:publish).with(connect)
      engine.should_receive(:publish).with(disconnect)
      engine.should_receive(:publish).with(subscribe)
      engine.should_receive(:publish).with(unsubscribe)
      engine.should_receive(:publish).with(publish)
      
      server.process([handshake, connect, disconnect, subscribe, unsubscribe, publish], false)
    end
    
    describe "publishing a message" do
      it "tells the engine to publish the message" do
        engine.should_receive(:publish).with(publish)
        server.process(publish, false) {}
      end
      
      it "returns no response" do
        engine.stub(:publish)
        server.process(publish, false) { |r| r.should == [] }
      end
      
      describe "with an error" do
        before { publish["error"] = "invalid" }
        
        it "does not tell the engine to publish the message" do
          engine.should_not_receive(:publish)
          server.process(publish, false) {}
        end
        
        it "returns no response" do
          engine.stub(:publish)
          server.process(publish, false) { |r| r.should == [] }
        end
      end

      describe "to an invalid channel" do
        before { publish["channel"] = "/invalid/*" }

        it "does not tell the engine to publish the message" do
          engine.should_not_receive(:publish)
          server.process(publish, false) {}
        end
      end
    end
    
    describe "handshaking" do
      before do
        engine.should_receive(:publish).with(handshake)
        server.should_receive(:handshake).with(handshake, false).and_yield({"successful" => true})
      end
      
      it "returns the handshake response with advice" do
        server.process(handshake, false) do |response|
          response.should == [
            { "successful" => true,
              "advice" => {"reconnect" => "retry", "interval" => 0, "timeout" => 60000}
            }
          ]
        end
      end
    end
    
    describe "connecting for messages" do
      let(:messages) { [{"channel" => "/a"}, {"channel" => "/b"}] }
      
      before do
        engine.should_receive(:publish).with(connect)
        server.should_receive(:connect).with(connect, false).and_yield(messages)
      end
      
      it "returns the new messages" do
        server.process(connect, false) { |r| r.should == messages }
      end
    end
  end
  
  describe :flush_connection do
    let(:message) {{"clientId" => "fakeclientid"}}
    
    it "flushes the connection when given one message" do
      engine.should_receive(:flush).with("fakeclientid")
      server.flush_connection(message)
    end
    
    it "flushes the connection when given a list of messages" do
      engine.should_receive(:flush).with("fakeclientid")
      server.flush_connection([message])
    end
  end
end