#!/usr/bin/perl -w
#
# Test suite for wa_keyring.
#
# Written by Russ Allbery <rra@stanford.edu>
# Copyright 2010, 2013
#     The Board of Trustees of the Leland Stanford Junior University
#
# See LICENSE for licensing terms.

use 5.008;
use strict;
use warnings;

use lib "$ENV{SOURCE}/tap/perl";

use Test::More;
use Test::RRA qw(use_prereq);
use Test::RRA::Automake qw(automake_setup);

# Load prerequiste modules.
use_prereq(qw(Date::Parse str2time));
use_prereq(qw(IPC::Run run));

# Declare our plan.
plan tests => 68;

# Set up Automake testing.
automake_setup({ chdir_build => 1 });

# Run wa_keyring with the given arguments and return the exit status, standard
# output, and standard error as a list.
sub wa_keyring {
    my (@args) = @_;
    my ($out, $err);
    run(['tools/wa_keyring', @args], \undef, \$out, \$err);
    my $status = $?;
    return ($status, $out, $err);
}

# Test basic operations.
my ($status, $out, $err) = wa_keyring('-f', 'keyring', 'add', '0s');
is($status, 0,   'wa_keyring add 0s succeeded');
is($out,    q{}, '...with no output');
is($err,    q{}, '...and no errors');
($status, $out, $err) = wa_keyring('-f', 'keyring', 'list');
is($status, 0,   'wa_keyring list succeeded');
is($err,    q{}, '...with no errors');
my @out = split(m{\n}xms, $out);
is($out[0], 'Path: keyring', '...and correct path');
is(scalar(@out), 4, '...and length of output');
my ($id, $created, $valid, $fingerprint) = split(m{ [ ]{2} }xms, $out[3]);
is($id,      q{ 0},  '...and correct key ID');
is($created, $valid, '...and created equals valid after');
diag("fingerprint: $fingerprint");
is(length($fingerprint), 32, '...and correct fingerprint length');
diag('now ', time, ' - ', str2time($created), ', < 10');
ok((time - str2time($created)) < 10, '...and correct created date');
($status, $out, $err) = wa_keyring('-v', '-f', 'keyring', 'list');
is($status, 0,   'wa_keyring list succeeded');
is($err,    q{}, '...with no errors');
@out = split(m{\n}xms, $out);
like($out[0], qr{ \A \s*Path: [ ] keyring \z }xms, '...and correct path');
like($out[1], qr{ \A \s*Num-Keys: [ ] 1 \z }xms,   '...and correct key count');
like($out[3], qr{ \A \s*Key-Id: [ ] 0 \z }xms,     '...and correct key ID');
like(
    $out[4],
    qr{ \A \s*Created: [ ] \Q$created\E \z }xms,
    '...and correct creation date'
);
like(
    $out[5],
    qr{ \A \s*Valid-After: [ ] \Q$valid\E \z }xms,
    '...and correct valid after'
);
like(
    $out[6],
    qr{ \A \s*Key-Type: [ ] 1 [ ] [(]AES[)] \z }xms,
    '...and correct key type'
);
like(
    $out[7],
    qr{ \A \s*Key-Length: [ ] 128 [ ] bits \z }xms,
    '...and correct key length'
);
like(
    $out[8],
    qr{ \A \s*Fingerprint: [ ] \Q$fingerprint\E \z }xms,
    '...and correct fingerprint'
);
is(scalar(@out), 9, '...and correct output length');
($status, $out, $err) = wa_keyring('-f', 'keyring', 'remove', '0');
is($status, 0,   'wa_keyring remove 0 succeeded');
is($out,    q{}, '...with no output');
is($err,    q{}, '...and no errors');
($status, $out, $err) = wa_keyring('-f', 'keyring', 'list');
is($status, 0,   'wa_keyring list succeeded after remove');
is($err,    q{}, '...with no errors');
@out = split(m{\n}xms, $out);
is(scalar(@out), 3, '...and correct output length');

# Test garbage collection.
($status, $out, $err) = wa_keyring('-f', 'keyring', 'add', '-2w');
is($status, 0,   'wa_keyring add -2w succeeded');
is($out,    q{}, '...with no output');
is($err,    q{}, '...and no errors');
($status, $out, $err) = wa_keyring('-f', 'keyring', 'add', '-2d');
is($status, 0,   'wa_keyring add -2d succeeded');
is($out,    q{}, '...with no output');
is($err,    q{}, '...and no errors');
($status, $out, $err) = wa_keyring('-f', 'keyring', 'add', '1h');
is($status, 0,   'wa_keyring add 1h succeeded');
is($out,    q{}, '...with no output');
is($err,    q{}, '...and no errors');
($status, $out, $err) = wa_keyring('-f', 'keyring', 'add', '120m');
is($status, 0,   'wa_keyring add 120m succeeded');
is($out,    q{}, '...with no output');
is($err,    q{}, '...and no errors');
($status, $out, $err) = wa_keyring('-f', 'keyring', 'add', '10800s');
is($status, 0,   'wa_keyring add 10800s succeeded');
is($out,    q{}, '...with no output');
is($err,    q{}, '...and no errors');
($status, $out, $err) = wa_keyring('-f', 'keyring', 'list');
is($status, 0,   'wa_keyring list succeeded after adds');
is($err,    q{}, '...with no errors');
@out = split(m{\n}xms, $out);
is(scalar(@out) - 3, 5, '...and has the correct number of keys');
splice(@out, 0, 3);
my $i = 0;

#<<<
my @offsets = (
    -60 * 60 * 24 * 7 * 2,
    -60 * 60 * 24 * 2,
    60 * 60 * 1,
    60 * 120,
    10800,
);
#>>>
for my $offset (@offsets) {
    ($id, $created, $valid, $fingerprint) = split(m{ [ ]{2} }xms, $out[$i]);
    ok(str2time($created) - time < 10,
        "...and key $i has the correct created time");
    ok(
        str2time($valid) - $offset - time < 10,
        "...and key $i has the correct valid time"
    );
    $i++;
}
($status, $out, $err) = wa_keyring('-f', 'keyring', 'gc', '-1w');
is($status, 0,   'wa_keyring gc -1w succeeded');
is($out,    q{}, '...with no output');
is($err,    q{}, '...and no errors');
($status, $out, $err) = wa_keyring('-f', 'keyring', 'list');
is($status, 0,   'wa_keyring list succeeded after gc');
is($err,    q{}, '...with no errors');
@out = split(m{\n}xms, $out);
is(scalar(@out) - 3, 4, '...and has the correct number of keys');
($status, $out, $err) = wa_keyring('-f', 'keyring', 'gc', '0s');
is($status, 0,   'wa_keyring gc 0s succeeded');
is($out,    q{}, '...with no output');
is($err,    q{}, '...and no errors');
($status, $out, $err) = wa_keyring('-f', 'keyring', 'list');
is($status, 0,   'wa_keyring list succeeded after gc');
is($err,    q{}, '...with no errors');
@out = split(m{\n}xms, $out);
is(scalar(@out) - 3, 3, '...and has the correct number of keys');

# Clean up.
unlink 'keyring';
