require File.expand_path(File.dirname(__FILE__) + '/spec_helper') require 'stringio' PhusionPassenger.require_passenger_lib 'analytics_logger' module PhusionPassenger describe AnalyticsLogger do YESTERDAY = Time.utc(2010, 4, 11, 11, 56, 02) TODAY = Time.utc(2010, 4, 11, 12, 56, 02) TOMORROW = Time.utc(2010, 4, 11, 13, 56, 02) before :each do @username = "logging" @password = "1234" @dump_file = Utils.passenger_tmpdir + "/log.txt" start_agent @logger = AnalyticsLogger.new(@socket_address, @username, @password, "localhost") @logger2 = AnalyticsLogger.new(@socket_address, @username, @password, "localhost") end after :each do @logger.close @logger2.close if @agent_pid Process.kill('KILL', @agent_pid) Process.waitpid(@agent_pid) end end def mock_time(time) AnalyticsLogger.stub(:current_time).and_return(time) end def start_agent @agent_pid, @socket_filename, @socket_address = spawn_logging_agent(@dump_file, @password) end def kill_agent if @agent_pid Process.kill('KILL', @agent_pid) Process.waitpid(@agent_pid) File.unlink(@socket_filename) @agent_pid = nil end end specify "logging with #new_transaction works" do mock_time(TODAY) log = @logger.new_transaction("foobar") log.should_not be_null begin log.message("hello") ensure log.close(true) end File.read(@dump_file).should =~ /hello/ log = @logger.new_transaction("foobar", :processes) log.should_not be_null begin log.message("world") ensure log.close(true) end File.read(@dump_file).should =~ /world/ end specify "#new_transaction reestablishes the connection if disconnected" do mock_time(TODAY) @logger.new_transaction("foobar").close(true) connection = @logger.instance_variable_get(:"@connection") connection.synchronize do connection.channel.close connection.channel = nil end log = @logger.new_transaction("foobar") begin log.message("hello") ensure log.close(true) end File.read(@dump_file).should =~ /hello/ end specify "#new_transaction does not reconnect to the server for a short period of time if connecting failed" do @logger.reconnect_timeout = 60 @logger.max_connect_tries = 1 mock_time(TODAY) kill_agent @logger.new_transaction("foobar").should be_null mock_time(TODAY + 30) start_agent @logger.new_transaction("foobar").should be_null mock_time(TODAY + 61) @logger.new_transaction("foobar").should_not be_null end specify "logging with #continue_transaction works" do mock_time(TODAY) log = @logger.new_transaction("foobar", :processes) begin log.message("hello") log2 = @logger2.continue_transaction(log.txn_id, "foobar", :processes) log2.should_not be_null log2.txn_id.should == log.txn_id begin log2.message("world") ensure log2.close(true) end ensure log.close(true) end File.read(@dump_file).should =~ /#{Regexp.escape log.txn_id} .* hello$/ File.read(@dump_file).should =~ /#{Regexp.escape log.txn_id} .* world$/ end specify "#continue_transaction reestablishes the connection if disconnected" do mock_time(TODAY) log = @logger.new_transaction("foobar") log.close(true) log2 = @logger2.continue_transaction(log.txn_id, "foobar") log2.close(true) connection = @logger2.instance_variable_get(:"@connection") connection.synchronize do connection.channel.close connection.channel = nil end log2 = @logger2.continue_transaction(log.txn_id, "foobar") begin log2.message("hello") ensure log2.close(true) end File.read(@dump_file).should =~ /hello/ end specify "#new_transaction and #continue_transaction eventually reestablish the connection to the logging server if the logging server crashed and was restarted" do mock_time(TODAY) log = @logger.new_transaction("foobar") @logger2.continue_transaction(log.txn_id, "foobar").close kill_agent start_agent log = @logger.new_transaction("foobar") log.should be_null log2 = @logger2.continue_transaction("1234-abcd", "foobar") log2.should be_null mock_time(TODAY + 60) log = @logger.new_transaction("foobar") log2 = @logger2.continue_transaction(log.txn_id, "foobar") begin log2.message("hello") ensure log2.close(true) end log.close(true) File.read(@dump_file).should =~ /hello/ end specify "#continue_transaction does not reconnect to the server for a short period of time if connecting failed" do @logger.reconnect_timeout = 60 @logger.max_connect_tries = 1 @logger2.reconnect_timeout = 60 @logger2.max_connect_tries = 1 mock_time(TODAY) log = @logger.new_transaction("foobar") @logger2.continue_transaction(log.txn_id, "foobar") kill_agent @logger2.continue_transaction(log.txn_id, "foobar").should be_null mock_time(TODAY + 30) start_agent @logger2.continue_transaction(log.txn_id, "foobar").should be_null mock_time(TODAY + 61) @logger2.continue_transaction(log.txn_id, "foobar").should_not be_null end specify "AnalyticsLogger only creates null Log objects if no server address is given" do logger = AnalyticsLogger.new(nil, nil, nil, nil) begin logger.new_transaction("foobar").should be_null ensure logger.close end end specify "#clear_connection closes the connection" do @logger.new_transaction("foobar").close @logger.clear_connection connection = @logger.instance_variable_get(:"@connection") connection.synchronize do connection.channel.should be_nil end end describe "Log objects" do it "becomes null once it is closed" do log = @logger.new_transaction("foobar") log.close log.should be_null end it "does nothing if it's null" do logger = AnalyticsLogger.new(nil, nil, nil, nil) begin log = logger.new_transaction("foobar") log.message("hello") log.close(true) ensure logger.close end File.exist?("#{@log_dir}/1").should be_false end describe "#begin_measure" do it "sends a BEGIN message" do log = @logger.new_transaction("foobar") begin log.should_receive(:message).with(/^BEGIN: hello \(.+?,.+?,.+?\) $/) log.begin_measure("hello") ensure log.close end end it "adds extra information as base64" do log = @logger.new_transaction("foobar") begin log.should_receive(:message).with(/^BEGIN: hello \(.+?,.+?,.+?\) YWJjZA==$/) log.begin_measure("hello", "abcd") ensure log.close end end end describe "#end_measure" do it "sends an END message if error_countered=false" do log = @logger.new_transaction("foobar") begin log.should_receive(:message).with(/^END: hello \(.+?,.+?,.+?\)$/) log.end_measure("hello") ensure log.close end end it "sends a FAIL message if error_countered=true" do log = @logger.new_transaction("foobar") begin log.should_receive(:message).with(/^FAIL: hello \(.+?,.+?,.+?\)$/) log.end_measure("hello", true) ensure log.close end end end end end end # module PhusionPassenger