#!perl -T

use 5.006;
use strict;
use warnings FATAL => 'all';
use autodie ':all';

use File::Basename;
use File::Temp;
use FindBin;

use Systemd::Daemon;

use Test::More tests => 9;

#
#   Helper function: run systemctl program, check its status and grab its output.
#

sub systemctl(@) {
    my $allowed = ( @_ > 0 and ref( $_[ 0 ] ) ) ? shift( @_ ) : [ 0 ];
    my $cmd = '/usr/bin/systemctl --user ' . join( ' ', @_ );
    diag( "\$ $cmd\n" );
    local $ENV{ PATH } = '';
    my $bulk = qx{ $cmd };
    my $signal = $? & 127;
    my $status = ( $? >> 8 ) & 0xFF;
    defined( $bulk ) and $bulk ne "" and diag( $bulk );
    $signal == 0 or die "systemctl terminated by signal $signal\n";
    grep( $status == $_, @$allowed ) or die "systemctl exited with status $status\n";
    return $bulk;
}; # sub systemctl

#
#   Check XDG_RUNTIME_DIR environment variable.
#

defined( $ENV{ XDG_RUNTIME_DIR } ) or die "XDG_RUNTIME_DIR is not defined\n";
$ENV{ XDG_RUNTIME_DIR } ne ""      or die "XDG_RUNTIME_DIR is empty\n";
-e $ENV{ XDG_RUNTIME_DIR }         or die "XDG_RUNTIME_DIR='$ENV{ XDG_RUNTIME_DIR }' directory does not exist\n";
-d $ENV{ XDG_RUNTIME_DIR }         or die "XDG_RUNTIME_DIR='$ENV{ XDG_RUNTIME_DIR }' is not a directory\n";

#
#   Create directory for test unit.
#

$ENV{ XDG_RUNTIME_DIR } =~ m{\A(/.*)\z} or die;     # Make -T happy.
my $systemd = "$1/systemd";
-e $systemd or die "Directory '$systemd' does not exist\n";
-d $systemd or die "'$systemd' is not a directory\n";
if ( not -d "$systemd/user" ) {
    mkdir( "$systemd/user" );
}; # if

#
#   Create file for test unit.
#

my $unit = File::Temp->new(
    "systemd-notify-XXXXXX",
    SUFFIX  => '.service',
    DIR     => "$ENV{ XDG_RUNTIME_DIR }/systemd/user",
);
my $service = basename( $unit->filename );

sub test(@) {
    my ( $args, @expected ) = @_;
    diag( "===== Test: $args =====" );
    $unit->truncate( 0 ) or die;
    $unit->seek( 0, 0 ) or die;
    $unit->print(
        "[Unit]\n" .
        "Description  = Systemd-Daemon test service\n" .
        "[Service]\n" .
        "Type         = simple\n" .
        "NotifyAccess = main\n" .
        "ExecStart    = $^X -T $FindBin::Bin/notify.pl $args\n"
    ) or die;
    $unit->flush() or die;
    systemctl( 'cat', $service );
    systemctl( 'daemon-reload' );
    systemctl( 'start', $service );
    sleep( 1 );     # Let daemon start and notify systemd.
    my $status = systemctl( [ 0, 3 ], 'status', $service );
        # If service failed, "systemctl status" returns 3. Accept it.
    foreach my $expected ( @expected ) {
        like( $status, $expected );
    }; # foreach $expected
    #   In case of "STOPPING=1", systemd will not stop service immediately but will wait noticeable
    #   time. To avoid long delay, let us kill service first, then stop it.
    systemctl( 'kill', $service );
    systemctl( 'stop', $service );
}; # sub test

#
#   Now we are ready for actual tests.
#

test(
    "--sleep 1000000 RELOADING 10",             # Any true value is suitable, not just "1".
    qr{^\s*Active:\s*reloading \(reload\)}m,
);

test(
    "--sleep 1000000 READY true",               # Any true value is suitable, not only "1".
    qr{^\s*Active:\s*active \(running\)}m,
);

test(
    "--sleep 1000000 STOPPING yes",             # Any true value is suitable, not only "1".
    qr{^\s*Active:\s*deactivating\b}m,
);

test(
    "--sleep 1000000 STATUS Foo",
    qr{^\s*Active:\s*active \(running\)}m,
    qr{^\s*Status:\s*"Foo"\s*$}m,
);

test(
    "--sleep 1000000 STATUS 47%%",
    qr{^\s*Status:\s*"47%"\s*$}m,
);
    #   "STATUS 47%" will be written to systemd unit file. In unit files, `%` has a special meaning,
    #   so we have to double it.

test(
    "--exit 55 ERRNO 2 STATUS Oops",
    qr{^\s*Active:\s*failed\b}m,
    qr{^\s*Status:\s*"Oops"\s*}m,
    qr{^\s*Error:\s*2\b}m,
);

# end of file #
