Imported Upstream version 3.1.0
[debian/amanda] / installcheck / Amanda_Util.pl
index 44f08daaed345316ecc0b3907e43e0c8c567d10e..3551927563b0356d6f69d0f147baaac7ce032e98 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2005-2008 Zmanda Inc.  All Rights Reserved.
+# Copyright (c) 2008, 2009, 2010 Zmanda, Inc.  All Rights Reserved.
 #
 # This program is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License version 2 as published
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 #
-# Contact information: Zmanda Inc, 465 S Mathlida Ave, Suite 300
+# Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
 
-use Test::More tests => 28;
+use Test::More tests => 114;
 
 use lib "@amperldir@";
+use warnings;
+use strict;
 use Data::Dumper;
-use Amanda::Util;
+use Amanda::Util qw(slurp burp safe_overwrite_file);
+use Installcheck;
+use POSIX;
 
 # Data::Dumper is used to output strings with control characters
 # in them, below
@@ -30,6 +34,12 @@ $Data::Dumper::Indent = 0; # no newlines
 
 # most of Amanda::Util is tested via running applications that use it
 
+# Test hexencode/hexdecode lightly (they have a "make check" test)
+is(Amanda::Util::hexencode("hi"), "hi", "no encoding needed");
+is(Amanda::Util::hexencode("hi!"), "hi%21", "encoding");
+is(Amanda::Util::hexdecode("hi%21"), "hi!", "decoding");
+ok(!eval {Amanda::Util::hexdecode("%"); 1}, "decoding error throws exception");
+
 # Tests for quote_string and unquote string.  First, some fuzzing of the
 # quote + unquote round-trip.
 my @fuzzstrs = (
@@ -76,3 +86,248 @@ while (my ($qstr, $uqstr) = each %unquote_checks) {
     is(Amanda::Util::unquote_string($qstr), $uqstr,
        "unquote " . Dumper($qstr));
 }
+
+for my $a (keys %unquote_checks) {
+    for my $b ("unquoted", "\"quoted str\"") {
+       my ($a_out, $b_out) = Amanda::Util::skip_quoted_string("$a $b");
+       is_deeply([$a_out, $b_out], [$a, $b],
+           "skip_quoted string over " . Dumper("$a $b"));
+    }
+}
+
+{
+    my ($a, $b) = Amanda::Util::skip_quoted_string("foobar");
+    is($a, "foobar",
+       "skip_quoted_string with one quoted string (first argument)");
+    is($b, undef,
+       "skip_quoted_string with one quoted string (second argument)");
+}
+
+my @try_bracing = (
+    [ 'abc' ],
+    [ 'abc', 'def' ],
+    [ 'abc', 'def', 'ghi' ],
+    [ 'a,b', 'c' ],
+    [ 'a', 'b,c' ],
+    [ 'a', 'b,c', 'd' ],
+    [ 'a{b', 'c' ],
+    [ 'a', 'b{c' ],
+    [ 'a', 'b{c', 'd' ],
+    [ 'a}b', 'c' ],
+    [ 'a', 'b}c' ],
+    [ 'a', 'b}c', 'd' ],
+    [ 'a\\,b', 'c\\{d', 'e\\}f' ],
+);
+
+for my $strs (@try_bracing) {
+    my $rt = [ Amanda::Util::expand_braced_alternates(
+                   Amanda::Util::collapse_braced_alternates($strs)) ];
+    is_deeply($rt, $strs,
+             "round-trip of " . Dumper($strs));
+}
+
+my @try_sanitise = (
+    [ '', '' ],
+    [ 'foo', 'foo' ],
+    [ '/', '_' ],
+    [ ':', '_' ],
+    [ '\\', '_' ],
+    [ 'foo/bar:baz', 'foo_bar_baz' ],
+);
+
+for my $strs (@try_sanitise) {
+    my ($in, $exp) = @{$strs};
+    is(Amanda::Util::sanitise_filename($in), $exp, "sanitise " . $in);
+}
+
+## test full_read and full_write
+
+my $testfile = "$Installcheck::TMP/Amanda_Util";
+my $fd;
+my $buf;
+
+# set up a 1K test file
+{
+    open (my $fh, ">", $testfile) or die("Opening $testfile: $!");
+    print $fh 'abcd' x 256;
+    close($fh);
+}
+
+$! = 0;
+my $rv = Amanda::Util::full_read(-1, 13);
+isnt($!, '', "bad full_read gives a nonzero errno ($!)");
+
+$! = 0;
+$rv = Amanda::Util::full_write(-1, "hello", 5);
+isnt($!, '', "bad full_write gives a nonzero errno ($!)");
+
+$fd = POSIX::open($testfile, POSIX::O_RDONLY);
+die "Could not open '$testfile'" unless defined $fd;
+
+$! = 0;
+$buf = Amanda::Util::full_read($fd, 1000);
+is(length($buf), 1000, "a valid read gets the right number of bytes");
+is(substr($buf, 0, 8), "abcdabcd", "..and what looks like the right data");
+is($!, '', "..and no error");
+
+$! = 0;
+$buf = Amanda::Util::full_read($fd, 1000);
+is(length($buf), 24, "a second read, to EOF, gets the right number of bytes");
+is(substr($buf, 0, 8), "abcdabcd", "..and what looks like the right data");
+is($!, '', "..and no error");
+
+POSIX::close($fd);
+
+$fd = POSIX::open($testfile, POSIX::O_WRONLY);
+die "Could not open '$testfile'" unless defined $fd;
+
+$! = 0;
+$rv = Amanda::Util::full_write($fd, "swank!", 6);
+is($rv, 6, "full_write returns number of bytes written");
+is($!, '', "..and no error");
+
+POSIX::close($fd);
+
+unlink($testfile);
+
+# just a quick check for split_quoted_strings - thorough checks are done in
+# common-src/quoting-test.c.
+is_deeply([ Amanda::Util::split_quoted_strings('one "T W O" thr\ ee'), ],
+          [ "one", "T W O", "thr ee" ],
+          "split_quoted_strings seems to work");
+
+## tests for slurp and burp
+
+my $corpus = <<EOF;
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean id
+neque interdum ligula euismod cursus at vel tortor. Praesent interdum
+molestie felis, nec vehicula lorem luctus quis. Suspendisse in laoreet
+diam. Maecenas fringilla lectus vel libero vehicula
+condimentum. Aenean ac luctus nulla. Nullam sagittis lacinia orci, et
+consectetur nunc malesuada sed. Nulla eu felis ipsum. Duis feugiat
+risus a lectus blandit lobortis. Fusce quis neque neque. Class aptent
+taciti sociosqu ad litora torquent per conubia nostra, per inceptos
+himenaeos.
+
+Nulla at auctor mi. Mauris vestibulum ante vel metus auctor at iaculis
+neque semper. Nullam ipsum lorem, convallis ullamcorper ornare in,
+lacinia eu magna. Vivamus vulputate fermentum quam, quis pulvinar eros
+varius at. Phasellus ac diam nec erat elementum facilisis et ac
+est. Nunc nec nulla nec quam tristique dignissim at ut arcu. Integer
+accumsan tincidunt nisi non consectetur. Donec nec massa sed dui
+auctor sodales eget ac elit. Aliquam luctus sollicitudin nibh, eu
+volutpat augue tempor sed. Mauris ac est et neque mollis iaculis vel
+in libero. Duis molestie felis ultrices elit fringilla varius. In eget
+turpis dignissim sem varius sagittis eget vel neque.
+
+EOF
+
+my $burp_corpus_fname = "$Installcheck::TMP/burp_corpus";
+
+ok( burp( $burp_corpus_fname, $corpus ), "burp round-trip test" );
+is( slurp($burp_corpus_fname), $corpus, "slurp round-trip test" );
+
+# test safe_overwrite_file
+
+my $sof_data = <<EOF;
+DISK planner somebox /lib
+START planner date 20080111
+START driver date 20080111
+STATS driver hostname somebox
+STATS driver startup time 0.051
+FINISH planner date 20080111 time 82.721
+START taper datestamp 20080111 label Conf-001 tape 1
+SUCCESS dumper somebox /lib 20080111 0 [sec 0.209 kb 1970 kps 9382.2 orig-kb 1970]
+SUCCESS chunker somebox /lib 20080111 0 [sec 0.305 kb 420 kps 1478.7]
+STATS driver estimate somebox /lib 20080111 0 [sec 1 nkb 2002 ckb 480 kps 385]
+PART taper Conf-001 1 somebox /lib 20080111 1/1 0 [sec 4.813543 kb 419 kps 87.133307]
+DONE taper somebox /lib 20080111 1 0 [sec 4.813543 kb 419 kps 87.133307]
+FINISH driver date 20080111 time 2167.581
+EOF
+
+ok(safe_overwrite_file($burp_corpus_fname, $sof_data));
+is(slurp($burp_corpus_fname), $sof_data,
+    "safe_overwrite_file round-trip check");
+
+# check out get_fs_usage
+my $fs_usage = Amanda::Util::get_fs_usage(POSIX::getcwd);
+if ($fs_usage) {
+    ok($fs_usage->{'blocks'}, "get_fs_usage returns something");
+} else {
+    fail("get_fs_usage fails: $!");
+}
+
+# check file_lock -- again, full checks are in common-src/amflock-test.c
+my $filename = "$Installcheck::TMP/testlock";
+unlink($filename);
+my $fl = Amanda::Util::file_lock->new($filename);
+is($fl->data, undef, "data is initially undefined");
+$fl->lock();
+is($fl->data, undef, "data is undefined even after lock");
+$fl->write("THIS IS MY DATA");
+is($fl->data, "THIS IS MY DATA", "data is set correctly after write()");
+$fl->unlock();
+
+# new lock object
+$fl = Amanda::Util::file_lock->new($filename);
+is($fl->data, undef, "data is initially undefined");
+$fl->lock();
+is($fl->data, "THIS IS MY DATA", "data is set correctly after lock");
+
+## check (un)marshal_tapespec
+
+my @tapespecs = (
+    "FOO:1,2;BAR:3" => [ FOO => [ 1, 2 ], BAR => [ 3 ] ],
+    "SE\\;MI:0;COL\\:ON:3" => [ 'SE;MI' => [0], 'COL:ON' => [3] ],
+    "CO\\,MMA:88,99;BACK\\\\SLASH:3" => [ 'CO,MMA' => [88,99], 'BACK\\SLASH' => [3] ],
+    "FUNNY\\;:1;CHARS\\::2;AT\\,:3;END\\\\:4" =>
+       [ 'FUNNY;' => [ 1 ], 'CHARS:' => [ 2 ], 'AT,' => [ 3 ], 'END\\' => [ 4 ], ],
+    "\\;FUNNY:1;\\:CHARS:2;\\,AT:3;\\\\BEG:4" =>
+       [ ';FUNNY' => [ 1 ], ':CHARS' => [ 2 ], ',AT' => [ 3 ], '\\BEG' => [ 4 ], ],
+);
+
+while (@tapespecs) {
+    my $tapespec = shift @tapespecs;
+    my $filelist = shift @tapespecs;
+    is(Amanda::Util::marshal_tapespec($filelist), $tapespec,
+           "marshal '$tapespec'");
+    is_deeply(Amanda::Util::unmarshal_tapespec($tapespec), $filelist,
+           "unmarshal '$tapespec'");
+}
+
+is_deeply(Amanda::Util::unmarshal_tapespec("x:100,99"), [ x => [99,100] ],
+    "filenums are sorted when unmarshalled");
+
+is_deeply(Amanda::Util::marshal_tapespec([ x => [100, 99] ]), "x:100,99",
+    "un-sorted filenums are NOT sorted when marshalled");
+
+is_deeply(Amanda::Util::unmarshal_tapespec("x:34,34"), [ x => [34, 34] ],
+    "duplicate filenums are NOT collapsed when unmarshalled");
+
+is_deeply(Amanda::Util::marshal_tapespec([ x => [34, 34] ]), "x:34,34",
+    "duplicate filenums are NOT collapsed when marshalled");
+
+is_deeply(Amanda::Util::unmarshal_tapespec("sim\\\\ple\\:quoted\\;file\\,name"),
+    [ "sim\\ple:quoted;file,name" => [0] ],
+    "simple non-tapespec string translated like string:0");
+
+is_deeply(Amanda::Util::unmarshal_tapespec("tricky\\,tricky\\:1,2,3"),
+    [ "tricky,tricky:1,2,3" => [0] ],
+    "tricky non-tapespec string also translated to string:0");
+
+is_deeply(Amanda::Util::unmarshal_tapespec("\\:3"), # one slash
+    [ ":3" => [0] ],
+    "one slash escapes the colon");
+
+is_deeply(Amanda::Util::unmarshal_tapespec("\\\\:3"), # two slashes
+    [ "\\" => [3] ],
+    "two slashes escape to one");
+
+is_deeply(Amanda::Util::unmarshal_tapespec("\\\\\\:3"), # three slashes
+    [ "\\:3" => [0] ],
+    "three slashes escape to a slash and a colon");
+
+is_deeply(Amanda::Util::unmarshal_tapespec("\\\\\\\\:3"), # four slashes
+    [ "\\\\" => [3] ],
+    "four slashes escape to two");