392 lines
13 KiB
Ruby
392 lines
13 KiB
Ruby
require 'spec_helper'
|
|
require 'thread'
|
|
|
|
LoginClient = Class.new do
|
|
attr_accessor :onmsgblock, :onopenblock, :encode_json, :channel_id, :client_id, :user_id, :context, :trusted, :subscriptions
|
|
|
|
|
|
def initialize()
|
|
@subscriptions = Set.new
|
|
end
|
|
|
|
def connected?
|
|
true
|
|
end
|
|
|
|
def onopen(&block)
|
|
@onopenblock = block
|
|
end
|
|
|
|
def onmessage(&block)
|
|
@onmsgblock = block
|
|
end
|
|
|
|
def close(&block)
|
|
@oncloseblock = block
|
|
end
|
|
|
|
def close_websocket()
|
|
|
|
end
|
|
|
|
def send(msg)
|
|
puts msg
|
|
end
|
|
|
|
def get_peername
|
|
return "\x00\x02\x93\v\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" # 37643, "localhost"
|
|
end
|
|
|
|
end
|
|
|
|
|
|
# does a login and returns client
|
|
def login(router, user, password, client_id, token, client_type)
|
|
|
|
message_factory = MessageFactory.new
|
|
client = LoginClient.new
|
|
|
|
router.should_receive(:send_to_client) do |*args|
|
|
args.count.should == 2
|
|
args[0].should == client
|
|
args[1].is_a?(Jampb::ClientMessage).should be_true
|
|
end
|
|
router.should_receive(:extract_ip).at_least(:once).with(client, nil).and_return("127.0.0.1")
|
|
client.should_receive(:onclose)
|
|
client.should_receive(:onerror)
|
|
|
|
|
|
#client.should_receive(:get_peername).and_return("\x00\x02\x93\v\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00")
|
|
|
|
@router.new_client(client, false)
|
|
handshake = double("handshake")
|
|
handshake.should_receive(:query).exactly(3).times.and_return({ "pb" => "true", "channel_id" => SecureRandom.uuid, "client_id" => client_id, "token" => token, "client_type" => client_type })
|
|
handshake.should_receive(:headers).at_least(:once).and_return({})
|
|
client.onopenblock.call handshake
|
|
|
|
client
|
|
end
|
|
|
|
def heartbeat(router, client)
|
|
message_factory = MessageFactory.new
|
|
heartbeat = message_factory.heartbeat()
|
|
|
|
client.onmsgblock.call heartbeat.to_s
|
|
end
|
|
|
|
# does a login and returns client
|
|
def login_latency_tester(router, latency_tester, client_id)
|
|
|
|
client = LoginClient.new
|
|
message_factory = MessageFactory.new
|
|
|
|
router.should_receive(:send_to_client).at_least(1).times do |*args|
|
|
args.count.should == 2
|
|
args[0].should == client
|
|
args[1].is_a?(Jampb::ClientMessage).should be_true
|
|
end
|
|
router.should_receive(:extract_ip).at_least(:once).with(client, nil).and_return("127.0.0.1")
|
|
client.should_receive(:onclose)
|
|
client.should_receive(:onerror)
|
|
|
|
#client.should_receive(:get_peername).and_return("\x00\x02\x93\v\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00")
|
|
|
|
@router.new_client(client, true)
|
|
handshake = double("handshake")
|
|
handshake.should_receive(:query).exactly(3).times.and_return({ "pb" => "true", "channel_id" => SecureRandom.uuid, "client_type" => "latency_tester", "client_id" => client_id })
|
|
handshake.should_receive(:headers).at_least(:once).and_return({})
|
|
client.onopenblock.call handshake
|
|
|
|
client
|
|
end
|
|
|
|
|
|
describe Router do
|
|
include EventedSpec::EMSpec
|
|
|
|
message_factory = MessageFactory.new
|
|
|
|
em_before do
|
|
@router = Router.new()
|
|
@router.connect_time_expire_client = 60
|
|
@router.connect_time_stale_client = 40
|
|
@router.heartbeat_interval_client = @router.connect_time_stale_client / 2
|
|
@router.connect_time_expire_browser = 60
|
|
@router.connect_time_stale_browser = 40
|
|
@router.max_connections_per_user = 10
|
|
@router.heartbeat_interval_browser = @router.connect_time_stale_browser / 2
|
|
@router.amqp_connection_manager = AmqpConnectionManager.new(true, 4, host: 'localhost', port: 5672)
|
|
@router.gateway_name = 'gateway1'
|
|
end
|
|
|
|
subject { @router }
|
|
|
|
em_after do
|
|
|
|
end
|
|
|
|
describe "periodical_check_clients" do
|
|
let(:user) { FactoryGirl.create(:user) }
|
|
it "with no data" do
|
|
@router.client_lookup.length.should == 0
|
|
@router.periodical_check_clients
|
|
done
|
|
end
|
|
|
|
it "with one OK client" do
|
|
client = double("client")
|
|
client.should_receive(:context=).any_number_of_times
|
|
conn1 = FactoryGirl.create(:connection, :user => user, :client_id => "pc1")
|
|
@router.add_tracker(user, client, 'client', conn1.client_id)
|
|
@router.client_lookup[conn1.client_id].should_not be_nil
|
|
@router.periodical_check_clients
|
|
@router.client_lookup[conn1.client_id].should_not be_nil
|
|
done
|
|
end
|
|
|
|
it "with one missing client" do
|
|
client = double("client")
|
|
client.should_receive(:context=).any_number_of_times
|
|
context = ClientContext.new(user, client, "client")
|
|
client.should_receive(:context).any_number_of_times.and_return(context)
|
|
client.should_receive(:close)
|
|
client.should_receive(:subscriptions).and_return(Set.new)
|
|
conn1 = FactoryGirl.create(:connection, :user => user, :client_id => "pc1")
|
|
client.should_receive(:client_id).and_return(conn1.client_id)
|
|
@router.add_tracker(user, client, 'client', conn1.client_id)
|
|
conn1.delete
|
|
@router.client_lookup[conn1.client_id].should_not be_nil
|
|
@router.periodical_check_clients
|
|
@router.client_lookup[conn1.client_id].should be_nil
|
|
done
|
|
end
|
|
end
|
|
|
|
describe "serviceability" do
|
|
it "should start and stop", :mq => true do
|
|
#em do
|
|
done
|
|
#end
|
|
end
|
|
|
|
it "should register for client events", :mq => true do
|
|
#em do
|
|
client = double("client")
|
|
client.should_receive(:onopen)
|
|
client.should_receive(:onclose)
|
|
client.should_receive(:onerror)
|
|
client.should_receive(:onmessage)
|
|
client.should_receive(:encode_json=)
|
|
client.should_receive(:trusted=)
|
|
|
|
@router.new_client(client, false)
|
|
done
|
|
#end
|
|
end
|
|
end
|
|
|
|
describe "topic routing helpers" do
|
|
it "create and delete user lookup set" do
|
|
#em do
|
|
user = double(User)
|
|
user.should_receive(:id).any_number_of_times.and_return("1")
|
|
client = double("client")
|
|
client.should_receive(:context=).any_number_of_times
|
|
context = ClientContext.new(user, client, "client")
|
|
|
|
@router.user_context_lookup.length.should == 0
|
|
|
|
@router.add_user(context)
|
|
|
|
@router.user_context_lookup.length.should == 1
|
|
|
|
@router.remove_user(context)
|
|
|
|
@router.user_context_lookup.length.should == 0
|
|
done
|
|
#end
|
|
end
|
|
end
|
|
|
|
|
|
describe "login" do
|
|
it "should not allow login of bogus user", :mq => true do
|
|
pending "broken currently due to some"
|
|
#em do
|
|
TestClient = Class.new do
|
|
|
|
attr_accessor :onmsgblock, :onopenblock, :encode_json, :client_id, :subscriptions
|
|
|
|
def initialize()
|
|
@subscriptions = Set.new
|
|
end
|
|
|
|
def onopen(&block)
|
|
@onopenblock = block
|
|
end
|
|
|
|
def onmessage(&block)
|
|
@onmsgblock = block
|
|
end
|
|
|
|
def close_websocket()
|
|
end
|
|
|
|
def close()
|
|
end
|
|
|
|
def get_peername
|
|
return "\x00\x02\x93\v\x7F\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" # 37643, "localhost"
|
|
end
|
|
|
|
end
|
|
|
|
client = TestClient.new
|
|
|
|
error_msg = message_factory.server_rejection_error("invalid login", "invalid_login")
|
|
|
|
@router.should_receive(:send_to_client).with(client, error_msg)
|
|
client.should_receive(:close_websocket)
|
|
client.should_receive(:onclose)
|
|
client.should_receive(:onerror)
|
|
|
|
|
|
@router.new_client(client)
|
|
handshake = double("handshake")
|
|
handshake.should_receive(:query).and_return({"pb" => "true"})
|
|
client.onopenblock.call handshake
|
|
|
|
# create a login message, and pass it into the router via onmsgblock.call
|
|
login = message_factory.login_with_user_pass("baduser@example.com", "foobar")
|
|
|
|
client.onmsgblock.call login.to_s
|
|
done
|
|
#end
|
|
end
|
|
|
|
it "should allow login of valid user", :mq => true do
|
|
@user = FactoryGirl.create(:user,
|
|
:password => "foobar", :password_confirmation => "foobar")
|
|
client1 = login(@router, @user, "foobar", "1", @user.remember_token, "client")
|
|
@user.reload
|
|
|
|
# verify that last_jam_reason, last_jam_addr, and last_jam_updated_at were updated
|
|
@user.last_jam_addr.should == ip_address_to_int('127.0.0.1')
|
|
@user.last_jam_updated_reason.should == User::JAM_REASON_LOGIN
|
|
@user.last_jam_updated_at.should_not be_nil
|
|
puts @user.last_jam_addr
|
|
@user.last_jam_locidispid.should == GeoIpLocations.lookup(@user.last_jam_addr)[:locidispid]
|
|
done
|
|
end
|
|
|
|
it "should not update last_jam info if already set", :mq => true do
|
|
last_jam_addr = ip_address_to_int('10.0.0.1')
|
|
last_jam_updated_reason = User::JAM_REASON_REGISTRATION
|
|
last_jam_updated_at = 5.hours.ago
|
|
last_jam_locidispid = 1
|
|
@user = FactoryGirl.create(:user,
|
|
:password => "foobar", :password_confirmation => "foobar",
|
|
last_jam_addr: last_jam_addr, last_jam_updated_reason: last_jam_updated_reason, last_jam_updated_at: last_jam_updated_at, last_jam_locidispid: last_jam_locidispid)
|
|
client1 = login(@router, @user, "foobar", "1", @user.remember_token, "client")
|
|
@user.reload
|
|
|
|
# verify that last_jam_reason, last_jam_addr, and last_jam_updated_at were updated
|
|
@user.last_jam_addr.should == last_jam_addr
|
|
@user.last_jam_updated_reason.should == last_jam_updated_reason
|
|
@user.last_jam_updated_at.round.should == last_jam_updated_at.round
|
|
@user.last_jam_locidispid.should == last_jam_locidispid
|
|
done
|
|
end
|
|
|
|
|
|
it "should allow login of a latency_tester", :mq => true do
|
|
@latency_tester = FactoryGirl.create(:latency_tester)
|
|
client1 = login_latency_tester(@router, @latency_tester, @latency_tester.client_id)
|
|
done
|
|
end
|
|
|
|
it "should allow heartbeat of a latency_tester", :mq => true do
|
|
@latency_tester = FactoryGirl.create(:latency_tester)
|
|
client1 = login_latency_tester(@router, @latency_tester, @latency_tester.client_id)
|
|
heartbeat(@router, client1)
|
|
done
|
|
end
|
|
|
|
it "should allow music_session_join of valid user", :mq => true do
|
|
|
|
user1 = FactoryGirl.create(:user) # in the music session
|
|
user2 = FactoryGirl.create(:user) # in the music session
|
|
user3 = FactoryGirl.create(:user) # not in the music session
|
|
|
|
music_session = FactoryGirl.create(:active_music_session, :creator => user1)
|
|
|
|
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :client_id => "4")
|
|
music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :client_id => "5")
|
|
|
|
# make a music_session and define two members
|
|
|
|
# create client 1, log him in, and log him in to music session
|
|
client1 = login(@router, user1, "foobar", "1", user1.remember_token, "client")
|
|
done
|
|
end
|
|
|
|
it "should allow two valid subscribers to communicate with session-directed messages", :mq => true do
|
|
#em do
|
|
user1 = FactoryGirl.create(:user) # in the music session
|
|
user2 = FactoryGirl.create(:user) # in the music session
|
|
|
|
music_session = FactoryGirl.create(:active_music_session, :creator => user1)
|
|
|
|
|
|
# create client 1, log him in, and log him in to music session
|
|
client1 = login(@router, user1, "foobar", "1", user1.remember_token, "client")
|
|
|
|
client2 = login(@router, user2, "foobar", "2", user2.remember_token, "client")
|
|
|
|
# make a music_session and define two members
|
|
|
|
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :client_id => "6")
|
|
music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :client_id => "7")
|
|
|
|
done
|
|
#end
|
|
end
|
|
|
|
it "should allow two valid subscribers to communicate with p2p messages", :mq => true do
|
|
#em do
|
|
user1 = FactoryGirl.create(:user) # in the music session
|
|
user2 = FactoryGirl.create(:user) # in the music session
|
|
|
|
music_session = FactoryGirl.create(:active_music_session, :creator => user1)
|
|
|
|
# create client 1, log him in, and log him in to music session
|
|
client1 = login(@router, user1, "foobar", "1", user1.remember_token, "client")
|
|
#login_music_session(@router, client1, music_session)
|
|
|
|
client2 = login(@router, user2, "foobar", "2", user2.remember_token, "client")
|
|
#login_music_session(@router, client2, music_session)
|
|
|
|
# by creating
|
|
music_session_member1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session, :client_id => "8")
|
|
|
|
# now attempt to message p2p!
|
|
|
|
# first test: user 2 should be able to send a ping message to user 1, even though he isn't in the same session yet
|
|
|
|
# create a login message, and pass it into the router via onmsgblock.call
|
|
ping = message_factory.ping_request("1", "2")
|
|
|
|
#@router.should_receive(:send_to_client) #.with(client1, ping)
|
|
|
|
## send ping to client 2
|
|
#client2.onmsgblock.call ping.to_s
|
|
|
|
#music_session_member2 = FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :client_id => "2")
|
|
|
|
done
|
|
#end
|
|
end
|
|
end
|
|
end
|
|
|