t/unit/MGH_Biostat/TravEpi/SimpleRulesBase/Logger/log.t


#!/usr/bin/env perl
use Modern::Perl '2013';
use Test2::V0;
use Test2::Tools::Spec;

use Plack::Test;
use HTTP::Request;
use JSON::Tiny 'encode_json';

use MGH_Biostat::TravEpi::SimpleRulesBase::Logger;

tests 'logger' => sub {
    my $mock_logger = mock { 'lines' => [] } => (
        add => [
            'print' => sub {
                my $self = shift;
                my ($line) = @_;
                push @{ $self->{'lines'} }, $line;
            },
        ]
    );
    my $logger = MGH_Biostat::TravEpi::SimpleRulesBase::Logger->new($mock_logger);

    # override loggers removal of localhost, so that we can have something to test against
    shift @{ $MGH_Biostat::TravEpi::SimpleRulesBase::Logger::filters->{'remove_ips'} };

    my $action = sub {
        my ( $ua, $ip, $hash, $lang, $action, $extra ) = @_;
        my $plack = Plack::Test->create(
            sub {
                my $env = shift;
                if ( defined( $env->{'HTTP_REMOTE_ADDR'} ) ) { $env->{'REMOTE_ADDR'} = $env->{'HTTP_REMOTE_ADDR'}; }
                $logger->log( $env, $hash, $lang, $action, $extra );
                return [ 200, [ 'Content-Type' => 'text/plain' ], [ 'ok' ] ];
            } );
        my $request = HTTP::Request->new( 'GET' => '/' );
        $request->header( 'User-Agent' => $ua );
        if ($ip) {
            if ( defined( $ip->{'REMOTE_ADDR'} ) ) {
                $request->header( 'Remote-Addr' => $ip->{'REMOTE_ADDR'} );
            }
            if ( defined( $ip->{'X_FORWARDED_FOR'} ) ) {
                $request->header( 'X-Forwarded-For' => $ip->{'X_FORWARDED_FOR'} );
            }
        }
        $plack->request($request);
    };

    my $loglines = [
        { 'ua' => 'testua1', 'ip' => '', 'hash' => 'testhash1', 'lang' => 'testlang1', 'action' => 'testaction1', 'extra' => 'testextra1', 'keep' => 1 },
        { 'ua' => 'testua2', 'ip' => { 'REMOTE_ADDR' => '10.0.0.1', 'EXPECTED' => '10.0.0.1' }, 'hash' => 'testhash2', 'lang' => 'testlang2', 'action' => 'testaction2', 'extra' => 'testextra2', 'keep' => 1 },
        { 'ua' => 'UptimeRobot foo', 'ip' => '', 'hash' => 'testhash3', 'lang' => 'testlang3', 'action' => 'testaction3', 'extra' => 'testextra3', 'keep' => 0 },
    ];

    foreach my $logline (@$loglines) {
        $action->( @{$logline}{qw(ua ip hash lang action extra)} );
    }

    my $expectedlines = [];
    foreach my $line (@$loglines) {
        next unless $line->{'keep'};
        my $ips_json = ips_to_json( $line->{'ip'} );
        push @$expectedlines, match qr/^
                    \d{4}-\d{2}-\d{2}\ \d{2}:\d{2}:\d{2}
                    \t
                    \Q$line->{hash}\E
                    \t
                    \Q$ips_json\E
                    \t
                    \Q$line->{lang}\E
                    \t
                    \Q$line->{action}\E
                    \t
                    \Q$line->{ua}\E
                    \t
                    \Q$line->{extra}\E
                $/x;
    }

    is( $mock_logger->{'lines'}, $expectedlines, 'logged lines (text) match expected' );
};

done_testing();

sub ips_to_json {
    my $ip_spec  = shift;
    my $ip_array = [];
    if ( $ip_spec and ( $ip_spec->{'EXPECTED'} ) ) {
        ## if any ip specification is provided, we need to know what is expected
        push @$ip_array, split( ',' => $ip_spec->{'EXPECTED'} );
    }
    elsif ( !$ip_spec ) {
        ## if we don't override anything, then we expect the ip address to be localhost
        push @$ip_array, '127.0.0.1';
    }

    return encode_json($ip_array);
}