304 lines
7.3 KiB
Ruby
304 lines
7.3 KiB
Ruby
require 'spec_helper'
|
|
require 'thread'
|
|
|
|
def time_it(cat, &blk)
|
|
start = Time.now
|
|
|
|
blk.call
|
|
|
|
time = Time.now - start
|
|
|
|
puts("TIME: #{cat}: #{time}")
|
|
end
|
|
def safety_net(&blk)
|
|
begin
|
|
blk.call
|
|
rescue => e
|
|
#Bugsnag.notify(e)
|
|
@log.error("unhandled exception in EM Timer #{e}")
|
|
puts "Error during processing: #{$!}"
|
|
puts "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
|
|
|
|
end
|
|
end
|
|
|
|
LoginClient = Class.new do
|
|
attr_accessor :onmsgblock, :onopenblock, :oncloseblock, :onerrorblock, :encode_json, :channel_id, :client_id, :user_id, :context, :trusted, :subscriptions
|
|
|
|
|
|
def initialize(user)
|
|
@subscriptions = Set.new
|
|
@channel_id = user.id
|
|
@encode_json = true
|
|
end
|
|
|
|
def connected?
|
|
true
|
|
end
|
|
|
|
def onopen(&block)
|
|
@onopenblock = Proc.new { |handshake| block }
|
|
end
|
|
|
|
def onmessage(&block)
|
|
@onmsgblock= Proc.new { |data| block.call data }
|
|
end
|
|
|
|
def onclose(&block)
|
|
@oncloseblock = Proc.new { || block.call }
|
|
end
|
|
|
|
def onerror(&block)
|
|
@onerrorblock = Proc.new { |err| block.call err }
|
|
end
|
|
|
|
def close()
|
|
|
|
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
|
|
|
|
class TestClient
|
|
|
|
def initialize(user, router)
|
|
@user = user
|
|
@client = LoginClient.new(@user)
|
|
@router = router
|
|
end
|
|
|
|
def connect
|
|
@router.new_client(@client, false)
|
|
end
|
|
|
|
def login
|
|
login_message = login_options(@user)
|
|
@router.handle_login(@client, login_message)
|
|
end
|
|
|
|
def heartbeat(notification_id = nil, notification_seen_at = nil)
|
|
heartbeat = Jampb::Heartbeat.new
|
|
if notification_id
|
|
heartbeat.notification_seen = notification_id
|
|
else
|
|
heartbeat.notification_seen = 'junk'
|
|
end
|
|
|
|
if notification_seen_at
|
|
heartbeat.notification_seen_at = notification_seen_at.to_s
|
|
end
|
|
|
|
@router.handle_heartbeat(heartbeat, '1', @client)
|
|
end
|
|
|
|
def disconnect
|
|
@client.oncloseblock.call
|
|
end
|
|
|
|
private
|
|
def login_options(user)
|
|
options = {}
|
|
options["token"] = user.remember_token
|
|
options["client_id"] = user.id
|
|
options["client_type"] = "client"
|
|
options["client_id_int"] = 1
|
|
options
|
|
end
|
|
|
|
end
|
|
|
|
describe Router, :spec_timeout => 15 do
|
|
|
|
def database_env (env)
|
|
singleton = GenericState.new
|
|
singleton.id = 'default'
|
|
singleton.env = env
|
|
singleton.save!
|
|
end
|
|
|
|
def rails_env (env)
|
|
JamRuby::Environment.should_receive(:mode).any_number_of_times.and_return(env)
|
|
end
|
|
|
|
|
|
include EventedSpec::EMSpec
|
|
default_timeout(1000000)
|
|
|
|
em_before do
|
|
puts "EM BEFORE ROUTER NEW"
|
|
|
|
end
|
|
|
|
subject { @router }
|
|
|
|
em_after do
|
|
puts "EM AFTER"
|
|
end
|
|
|
|
def sequence_1(user, special_heartbeat)
|
|
|
|
client1 = TestClient.new(user, @router)
|
|
client1.connect
|
|
client1.login
|
|
@router.client_lookup.count.should be 1
|
|
client1.heartbeat
|
|
update_notification_at = Time.now.utc
|
|
#client1.heartbeat(special_heartbeat.id.to_s, nil)
|
|
client1.heartbeat(nil, update_notification_at)
|
|
|
|
client1.disconnect
|
|
|
|
sleep 6
|
|
|
|
user.reload
|
|
user = User.find(user.id)
|
|
@router.client_lookup.count.should be 0
|
|
last_notification_seen_at = user.notification_seen_at
|
|
last_notification_seen_at.should_not be_nil
|
|
last_notification_seen_at.to_i.should be update_notification_at.to_i
|
|
end
|
|
|
|
def sequence_2(user)
|
|
|
|
before_count = Connection.count
|
|
client1 = TestClient.new(user, @router)
|
|
client1.connect
|
|
client1.login
|
|
@router.client_lookup.count.should be 1
|
|
after_count = Connection.count
|
|
before_count.should be (after_count - 1)
|
|
|
|
sleep 25
|
|
|
|
@router.client_lookup.count.should be 0
|
|
disc_count = Connection.count
|
|
before_count.should be disc_count
|
|
end
|
|
|
|
def sequence_in_session(user)
|
|
before_count = Connection.count
|
|
client1 = TestClient.new(user, @router)
|
|
client1.connect
|
|
client1.login
|
|
@router.client_lookup.count.should be 1
|
|
|
|
music_session = FactoryGirl.create(:active_music_session, :creator => user)
|
|
connection = Connection.find_by_user_id(user.id)
|
|
connection.music_session = music_session
|
|
connection.save!
|
|
|
|
|
|
client1.disconnect
|
|
@router.client_lookup.count.should be 0
|
|
disc_count = Connection.count
|
|
before_count.should be disc_count
|
|
end
|
|
def sequence_in_two_session(user1, user2)
|
|
|
|
# create friendship between the two, to increase notifications
|
|
FactoryGirl.create(:friendship, :user => user1, :friend => user2)
|
|
FactoryGirl.create(:friendship, :user => user2, :friend => user1)
|
|
|
|
before_count = Connection.count
|
|
client1 = TestClient.new(user1, @router)
|
|
client1.connect
|
|
client1.login
|
|
@router.client_lookup.count.should be 1
|
|
|
|
client1 = TestClient.new(user2, @router)
|
|
client1.connect
|
|
client1.login
|
|
@router.client_lookup.count.should be 2
|
|
|
|
music_session = FactoryGirl.create(:active_music_session, :creator => user)
|
|
connection = Connection.find_by_user_id(user1.id)
|
|
connection.music_session = music_session
|
|
connection.save!
|
|
|
|
connection2 = Connection.find_by_user_id(user2.id)
|
|
connection2.music_session = music_session
|
|
connection2.save!
|
|
|
|
|
|
client1.disconnect
|
|
@router.client_lookup.count.should be 1
|
|
disc_count = Connection.count
|
|
before_count.should be (disc_count - 1)
|
|
end
|
|
|
|
def delete_conn_from_under(user)
|
|
|
|
before_count = Connection.count
|
|
client1 = TestClient.new(user, @router)
|
|
client1.connect
|
|
client1.login
|
|
@router.client_lookup.count.should be 1
|
|
after_count = Connection.count
|
|
before_count.should be (after_count - 1)
|
|
|
|
Connection.first.delete
|
|
|
|
@router.periodical_check_clients
|
|
|
|
@router.client_lookup.count.should be 0
|
|
disc_count = Connection.count
|
|
before_count.should be disc_count
|
|
end
|
|
|
|
|
|
describe "stress" do
|
|
before {
|
|
database_env('production')
|
|
rails_env('production')
|
|
stub_const("ENV", {'BUILD_NUMBER' => 1})
|
|
}
|
|
let(:user1) { FactoryGirl.create(:user) }
|
|
let(:user2) { FactoryGirl.create(:user) }
|
|
let(:user3) { FactoryGirl.create(:user) }
|
|
let(:user4) { FactoryGirl.create(:user) }
|
|
let(:user5) { FactoryGirl.create(:user) }
|
|
let!(:other) { FactoryGirl.create(:user, last_jam_locidispid: 1) }
|
|
let!(:msg1) {FactoryGirl.create(:notification_text_message, source_user: other, target_user: user1) }
|
|
|
|
it "the test" do
|
|
|
|
@router = Router.new()
|
|
@router.connect_time_expire_client = 20
|
|
@router.connect_time_stale_client = 14
|
|
@router.heartbeat_interval_client = @router.connect_time_stale_client / 2
|
|
@router.connect_time_expire_browser = 20
|
|
@router.connect_time_stale_browser = 14
|
|
@router.max_connections_per_user = 10
|
|
@router.heartbeat_interval_browser = @router.connect_time_stale_browser / 2
|
|
@router.maximum_minutely_heartbeat_rate_browser = 10
|
|
@router.maximum_minutely_heartbeat_rate_client = 10
|
|
@router.amqp_connection_manager = AmqpConnectionManager.new(true, 4, host: 'localhost', port: 5672)
|
|
@router.gateway_name = 'gateway1'
|
|
|
|
@router.init
|
|
|
|
em do
|
|
EventMachine::PeriodicTimer.new(5) do
|
|
time_it('stats_dump') { safety_net { @router.periodical_stats_dump } }
|
|
end
|
|
|
|
sequence_in_session(user3)
|
|
sequence_in_two_session(user4, user5)
|
|
delete_conn_from_under(user3)
|
|
sequence_1(user1, msg1)
|
|
sequence_1(user1, msg1)
|
|
sequence_2(user2)
|
|
|
|
done
|
|
|
|
end
|
|
end
|
|
end
|
|
end |