X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=installcheck%2FAmanda_Config.pl;h=fece651687c31076a8fcc33d4b850f461dd5c365;hb=d5853102f67d85d8e169f9dbe973ad573306c215;hp=5a0bb2254fb879bbd3a544f7d9aeff144253efe5;hpb=6ba576375c19b829b2a13dbe6562eedd2716b9ea;p=debian%2Famanda diff --git a/installcheck/Amanda_Config.pl b/installcheck/Amanda_Config.pl index 5a0bb22..fece651 100644 --- a/installcheck/Amanda_Config.pl +++ b/installcheck/Amanda_Config.pl @@ -1,4 +1,4 @@ -# Copyright (c) 2006 Zmanda Inc. All Rights Reserved. +# Copyright (c) 2007, 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 @@ -13,51 +13,141 @@ # 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, 505 N Mathlida Ave, Suite 120 -# Sunnyvale, CA 94085, USA, or: http://www.zmanda.com +# Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300 +# Sunnyvale, CA 94086, USA, or: http://www.zmanda.com -use Test::More qw(no_plan); -use Amconfig; +use Test::More tests => 176; use strict; use lib "@amperldir@"; +use Installcheck::Config; use Amanda::Paths; -use Amanda::Config qw( :init :getconf ); +use Amanda::Tests; +use Amanda::Config qw( :init :getconf string_to_boolean ); +use Amanda::Debug; my $testconf; +my $config_overrides; + +Amanda::Debug::dbopen("installcheck"); +Installcheck::log_test_output(); + +# utility function + +sub diag_config_errors { + my ($level, @errors) = Amanda::Config::config_errors(); + for my $errmsg (@errors) { + diag $errmsg; + } +} ## # Try starting with no configuration at all -ok(config_init(0, ''), "Initialize with no configuration"); + +is(config_init(0, ''), $CFGERR_OK, + "Initialize with no configuration") + or diag_config_errors(); + +config_uninit(); +$config_overrides = new_config_overrides(1); +add_config_override($config_overrides, "tapedev", "null:TEST"); +set_config_overrides($config_overrides); + +is(config_init(0, undef), $CFGERR_OK, + "Initialize with no configuration, passing a NULL config name") + or diag_config_errors(); + +is(getconf($CNF_TAPEDEV), "null:TEST", + "config overwrites work with null config"); + +## +# Check out error handling + +$testconf = Installcheck::Config->new(); +$testconf->add_param('tapebufs', '13'); # a deprecated keyword -> warning +$testconf->write(); + +{ + is(config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"), $CFGERR_WARNINGS, + "Deprecated keyword generates a warning"); + my ($error_level, @errors) = Amanda::Config::config_errors(); + like($errors[0], qr/is deprecated/, + "config_get_errors returns the warning string"); + + Amanda::Config::config_clear_errors(); + ($error_level, @errors) = Amanda::Config::config_errors(); + is(scalar(@errors), 0, "config_clear_errors clears error list"); +} + +$testconf = Installcheck::Config->new(); +$testconf->add_param('invalid-param', 'random-value'); # a deprecated keyword -> warning +$testconf->write(); + +is(config_init($CONFIG_INIT_EXPLICIT_NAME, "NO-SUCH-CONFIGURATION"), $CFGERR_ERRORS, + "Non-existent config generates an error"); + +is(config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"), $CFGERR_ERRORS, + "Invalid keyword generates an error"); + +## +# try a client configuration + +# (note use of uppercase letters to test lower-casing of property names) +$testconf = Installcheck::Config->new(); +$testconf->add_client_param('property', '"client-prop" "yep"'); +$testconf->add_client_param('property', 'priority "clIent-prop1" "foo"'); +$testconf->add_client_param('property', 'append "clieNt-prop" "bar"'); +$testconf->write(); + +my $cfg_result = config_init($CONFIG_INIT_CLIENT, undef); +is($cfg_result, $CFGERR_OK, + "Load test client configuration") + or diag_config_errors(); + +is_deeply(getconf($CNF_PROPERTY), { "client-prop1" => { priority => 1, + append => 0, + values => [ "foo" ]}, + "client-prop" => { priority => 0, + append => 1, + values => [ "yep", "bar" ] }}, + "Client PROPERTY parameter parsed correctly"); ## # Parse up a basic configuration -# invent "large" values for CONFTYPE_AM64 and CONFTYPE_SIZE -my $am64_num = '171801575472'; # 0xA000B000C000 / 1024 -my $size_t_num = '2147483647'; # 0x7fffffff +# invent a "large" unsigned number, and make $size_t_num +# depend on the length of size_t +my $int64_num = '171801575472'; # 0xA000B000C000 / 1024 +my $size_t_num; +if (Amanda::Tests::sizeof_size_t() > 4) { + $size_t_num = $int64_num; +} else { + $size_t_num = '2147483647'; # 0x7fffffff +} -$testconf = Amconfig->new(); +$testconf = Installcheck::Config->new(); $testconf->add_param('reserve', '75'); $testconf->add_param('autoflush', 'yes'); +$testconf->add_param('usetimestamps', '0'); $testconf->add_param('tapedev', '"/dev/foo"'); -$testconf->add_param('bumpsize', $am64_num); +$testconf->add_param('bumpsize', $int64_num); $testconf->add_param('bumpmult', '1.4'); -$testconf->add_param('reserved-udp-port', '100,200'); +$testconf->add_param('reserved_udp-port', '100,200'); # note use of '-' and '_' $testconf->add_param('device_output_buffer_size', $size_t_num); $testconf->add_param('taperalgo', 'last'); $testconf->add_param('device_property', '"foo" "bar"'); -$testconf->add_param('device_property', '"blue" "car"'); +$testconf->add_param('device_property', '"blUE" "car" "tar"'); +$testconf->add_param('autolabel', 'non-amanda empty'); $testconf->add_param('displayunit', '"m"'); $testconf->add_param('debug_auth', '1'); $testconf->add_tapetype('mytapetype', [ 'comment' => '"mine"', 'length' => '128 M', ]); -$testconf->add_dumptype('mydumptype', [ +$testconf->add_dumptype('mydump-type', [ # note dash 'comment' => '"mine"', 'priority' => 'high', # == 2 - 'bumpsize' => $am64_num, + 'bumpsize' => $int64_num, 'bumpmult' => 1.75, 'starttime' => 1829, 'holdingdisk' => 'required', @@ -71,12 +161,23 @@ $testconf->add_dumptype('mydumptype', [ 'include list' => '"bing" "ting"', 'include list append' => '"string" "fling"', 'include file optional' => '"rhyme"', + 'property' => '"prop" "erty"', + 'property' => '"DROP" "qwerty" "asdfg"', + 'estimate' => 'server calcsize client' +]); +$testconf->add_dumptype('second_dumptype', [ # note underscore + '' => 'mydump-type', + 'comment' => '"refers to mydump-type with a dash"', +]); +$testconf->add_dumptype('third_dumptype', [ + '' => 'second_dumptype', + 'comment' => '"refers to second_dumptype with an underscore"', ]); -$testconf->add_interface('inyoface', [ +$testconf->add_interface('ethernet', [ 'comment' => '"mine"', 'use' => '100', ]); -$testconf->add_interface('inherface', [ +$testconf->add_interface('nic', [ 'comment' => '"empty"', ]); $testconf->add_holdingdisk('hd1', [ @@ -88,13 +189,40 @@ $testconf->add_holdingdisk('hd1', [ $testconf->add_holdingdisk('hd2', [ 'comment' => '"empty"', ]); +$testconf->add_application('my_app', [ + 'comment' => '"my_app_comment"', + 'plugin' => '"amgtar"', +]); +$testconf->add_script('my_script', [ + 'comment' => '"my_script_comment"', + 'plugin' => '"script-email"', + 'execute-on' => 'pre-host-backup, post-host-backup', + 'execute-where' => 'client', + 'property' => '"mailto" "amandabackup" "amanda"', +]); +$testconf->add_device('my_device', [ + 'comment' => '"my device is mine, not yours"', + 'tapedev' => '"tape:/dev/nst0"', + 'device_property' => '"BLOCK_SIZE" "128k"', +]); +$testconf->add_changer('my_changer', [ + 'comment' => '"my changer is mine, not yours"', + 'tpchanger' => '"chg-foo"', + 'changerdev' => '"/dev/sg0"', + 'changerfile' => '"chg.state"', + 'property' => '"testprop" "testval"', + 'device_property' => '"testdprop" "testdval"', +]); + $testconf->write(); -my $cfg_ok = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF'); -ok($cfg_ok, "Load test configuration"); +$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF'); +is($cfg_result, $CFGERR_OK, + "Load test configuration") + or diag_config_errors(); SKIP: { - skip "error loading config", unless $cfg_ok; + skip "error loading config", 3 unless $cfg_result == $CFGERR_OK; is(Amanda::Config::get_config_name(), "TESTCONF", "config_name set"); @@ -106,18 +234,20 @@ SKIP: { } SKIP: { # global parameters - skip "error loading config", unless $cfg_ok; + skip "error loading config", 13 unless $cfg_result == $CFGERR_OK; is(getconf($CNF_RESERVE), 75, "integer global confparm"); - is(getconf($CNF_BUMPSIZE), $am64_num+0, - "am64 global confparm"); + is(getconf($CNF_BUMPSIZE), $int64_num+0, + "int64 global confparm"); is(getconf($CNF_TAPEDEV), "/dev/foo", "string global confparm"); is(getconf($CNF_DEVICE_OUTPUT_BUFFER_SIZE), $size_t_num+0, "size global confparm"); ok(getconf($CNF_AUTOFLUSH), "boolean global confparm"); + is(getconf($CNF_USETIMESTAMPS), 0, + "boolean global confparm, passing an integer (0)"); is(getconf($CNF_TAPERALGO), $Amanda::Config::ALGO_LAST, "taperalgo global confparam"); is_deeply([getconf($CNF_RESERVED_UDP_PORT)], [100,200], @@ -125,17 +255,22 @@ SKIP: { # global parameters is(getconf($CNF_DISPLAYUNIT), "M", "displayunit is correctly uppercased"); is_deeply(getconf($CNF_DEVICE_PROPERTY), - { "foo" => "bar", "blue" => "car" }, + { "foo" => { priority => 0, append => 0, values => ["bar"]}, + "blue" => { priority => 0, append => 0, + values => ["car", "tar"]} }, "proplist global confparm"); - + is_deeply(getconf($CNF_AUTOLABEL), + { template => undef, other_config => '', + non_amanda => 1, volume_error => '', empty => 1 }, + "'autolabel non-amanda empty' represented correctly"); ok(getconf_seen($CNF_TAPEDEV), "'tapedev' parm was seen"); - ok(!getconf_seen($CNF_NETUSAGE), - "'netusage' parm was not seen"); + ok(!getconf_seen($CNF_CHANGERFILE), + "'changerfile' parm was not seen"); } SKIP: { # derived values - skip "error loading config", unless $cfg_ok; + skip "error loading config", 3 unless $cfg_result == $CFGERR_OK; is(Amanda::Config::getconf_unit_divisor(), 1024, "correct unit divisor (from displayunit -> KB)"); @@ -146,7 +281,7 @@ SKIP: { # derived values } SKIP: { # tapetypes - skip "error loading config", unless $cfg_ok; + skip "error loading config", 6 unless $cfg_result == $CFGERR_OK; my $ttyp = lookup_tapetype("mytapetype"); ok($ttyp, "found mytapetype"); is(tapetype_getconf($ttyp, $TAPETYPE_COMMENT), 'mine', @@ -165,15 +300,15 @@ SKIP: { # tapetypes } SKIP: { # dumptypes - skip "error loading config", unless $cfg_ok; + skip "error loading config", 18 unless $cfg_result == $CFGERR_OK; - my $dtyp = lookup_dumptype("mydumptype"); - ok($dtyp, "found mydumptype"); + my $dtyp = lookup_dumptype("mydump-type"); + ok($dtyp, "found mydump-type"); is(dumptype_getconf($dtyp, $DUMPTYPE_COMMENT), 'mine', "dumptype string"); is(dumptype_getconf($dtyp, $DUMPTYPE_PRIORITY), 2, "dumptype priority"); - is(dumptype_getconf($dtyp, $DUMPTYPE_BUMPSIZE), $am64_num+0, + is(dumptype_getconf($dtyp, $DUMPTYPE_BUMPSIZE), $int64_num+0, "dumptype size"); is(dumptype_getconf($dtyp, $DUMPTYPE_BUMPMULT), 1.75, "dumptype real"); @@ -199,6 +334,14 @@ SKIP: { # dumptypes 'list' => [ 'foo', 'bar', 'true', 'star' ], 'optional' => 0 }, "dumptype exclude list"); + is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_ESTIMATELIST), + [ $ES_SERVER, $ES_CALCSIZE, $ES_CLIENT ], + "dumptype estimate list"); + is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_PROPERTY), + { "prop" => { priority => 0, append => 0, values => ["erty"]}, + "drop" => { priority => 0, append => 0, + values => ["qwerty", "asdfg"] }}, + "dumptype proplist"); ok(dumptype_seen($dtyp, $DUMPTYPE_EXCLUDE), "'exclude' parm was seen"); @@ -207,39 +350,39 @@ SKIP: { # dumptypes is_deeply([ sort(+getconf_list("dumptype")) ], [ sort(qw( - mydumptype + mydump-type second_dumptype third_dumptype NO-COMPRESS COMPRESS-FAST COMPRESS-BEST COMPRESS-CUST - SRVCOMPRESS BSD-AUTH KRB4-AUTH NO-RECORD NO-HOLD + SRVCOMPRESS BSD-AUTH NO-RECORD NO-HOLD NO-FULL )) ], "getconf_list lists all dumptypes (including defaults)"); } SKIP: { # interfaces - skip "error loading config" unless $cfg_ok; - my $iface = lookup_interface("inyoface"); - ok($iface, "found inyoface"); - is(interface_name($iface), "inyoface", + skip "error loading config", 8 unless $cfg_result == $CFGERR_OK; + my $iface = lookup_interface("ethernet"); + ok($iface, "found ethernet"); + is(interface_name($iface), "ethernet", "interface knows its name"); is(interface_getconf($iface, $INTER_COMMENT), 'mine', "interface comment"); is(interface_getconf($iface, $INTER_MAXUSAGE), 100, "interface maxusage"); - $iface = lookup_interface("inherface"); - ok($iface, "found inherface"); + $iface = lookup_interface("nic"); + ok($iface, "found nic"); ok(interface_seen($iface, $INTER_COMMENT), "seen set for parameters that appeared"); ok(!interface_seen($iface, $INTER_MAXUSAGE), "seen not set for parameters that did not appear"); is_deeply([ sort(+getconf_list("interface")) ], - [ sort('inyoface', 'inherface', 'default') ], + [ sort('ethernet', 'nic', 'default') ], "getconf_list lists all interfaces (in any order)"); } SKIP: { # holdingdisks - skip "error loading config" unless $cfg_ok; + skip "error loading config", 13 unless $cfg_result == $CFGERR_OK; my $hdisk = lookup_holdingdisk("hd1"); ok($hdisk, "found hd1"); is(holdingdisk_name($hdisk), "hd1", @@ -262,13 +405,15 @@ SKIP: { # holdingdisks # only holdingdisks have this linked-list structure # exposed - $hdisk = getconf_holdingdisks(); + my $hdisklist = getconf($CNF_HOLDINGDISK); + my $first_disk = @$hdisklist[0]; + $hdisk = lookup_holdingdisk($first_disk); like(holdingdisk_name($hdisk), qr/hd[12]/, "one disk is first in list of holdingdisks"); - $hdisk = holdingdisk_next($hdisk); + $hdisk = lookup_holdingdisk(@$hdisklist[1]); like(holdingdisk_name($hdisk), qr/hd[12]/, "another is second in list of holdingdisks"); - ok(!holdingdisk_next($hdisk), + ok($#$hdisklist == 1, "no third holding disk"); is_deeply([ sort(+getconf_list("holdingdisk")) ], @@ -276,6 +421,128 @@ SKIP: { # holdingdisks "getconf_list lists all holdingdisks (in any order)"); } +SKIP: { # application + skip "error loading config", 5 unless $cfg_result == $CFGERR_OK; + my $app = lookup_application("my_app"); + ok($app, "found my_app"); + is(application_name($app), "my_app", + "my_app knows its name"); + is(application_getconf($app, $APPLICATION_COMMENT), 'my_app_comment', + "application comment"); + is(application_getconf($app, $APPLICATION_PLUGIN), 'amgtar', + "application plugin (amgtar)"); + + is_deeply([ sort(+getconf_list("application-tool")) ], + [ sort("my_app") ], + "getconf_list lists all applications"); + # test backward compatibility + is_deeply([ sort(+getconf_list("application")) ], + [ sort("my_app") ], + "getconf_list works for 'application-tool', too"); +} + +SKIP: { # script + skip "error loading config", 7 unless $cfg_result == $CFGERR_OK; + my $sc = lookup_pp_script("my_script"); + ok($sc, "found my_script"); + is(pp_script_name($sc), "my_script", + "my_script knows its name"); + is(pp_script_getconf($sc, $PP_SCRIPT_COMMENT), 'my_script_comment', + "script comment"); + is(pp_script_getconf($sc, $PP_SCRIPT_PLUGIN), 'script-email', + "script plugin (script-email)"); + is(pp_script_getconf($sc, $PP_SCRIPT_EXECUTE_WHERE), $ES_CLIENT, + "script execute_where (client)"); + is(pp_script_getconf($sc, $PP_SCRIPT_EXECUTE_ON), + $EXECUTE_ON_PRE_HOST_BACKUP|$EXECUTE_ON_POST_HOST_BACKUP, + "script execute_on"); + + is_deeply([ sort(+getconf_list("script")) ], + [ sort("my_script") ], + "getconf_list lists all script"); + + is_deeply([ sort(+getconf_list("script-tool")) ], + [ sort("my_script") ], + "getconf_list works for 'script-tool', too"); +} + +SKIP: { # device + skip "error loading config", 6 unless $cfg_result == $CFGERR_OK; + my $dc = lookup_device_config("my_device"); + ok($dc, "found my_device"); + is(device_config_name($dc), "my_device", + "my_device knows its name"); + is(device_config_getconf($dc, $DEVICE_CONFIG_COMMENT), 'my device is mine, not yours', + "device comment"); + is(device_config_getconf($dc, $DEVICE_CONFIG_TAPEDEV), 'tape:/dev/nst0', + "device tapedev"); + # TODO do we really need all of this equipment for device properties? + is_deeply(device_config_getconf($dc, $DEVICE_CONFIG_DEVICE_PROPERTY), + { "block_size" => { 'priority' => 0, 'values' => ["128k"], 'append' => 0 }, }, + "device config proplist"); + + is_deeply([ sort(+getconf_list("device")) ], + [ sort("my_device") ], + "getconf_list lists all devices"); +} + +SKIP: { # changer + skip "error loading config", 7 unless $cfg_result == $CFGERR_OK; + my $dc = lookup_changer_config("my_changer"); + ok($dc, "found my_changer"); + is(changer_config_name($dc), "my_changer", + "my_changer knows its name"); + is(changer_config_getconf($dc, $CHANGER_CONFIG_COMMENT), 'my changer is mine, not yours', + "changer comment"); + is(changer_config_getconf($dc, $CHANGER_CONFIG_CHANGERDEV), '/dev/sg0', + "changer tapedev"); + is_deeply(changer_config_getconf($dc, $CHANGER_CONFIG_PROPERTY), + { 'testprop' => { + 'priority' => 0, + 'values' => [ 'testval' ], + 'append' => 0, + } + }, "changer properties represented correctly"); + + is_deeply(changer_config_getconf($dc, $CHANGER_CONFIG_DEVICE_PROPERTY), + { 'testdprop' => { + 'priority' => 0, + 'values' => [ 'testdval' ], + 'append' => 0, + } + }, "changer device properties represented correctly"); + + is_deeply([ sort(+getconf_list("changer")) ], + [ sort("my_changer") ], + "getconf_list lists all changers"); +} + +## +# Test config overwrites (using the config from above) + +config_uninit(); +$config_overrides = new_config_overrides(1); # note estimate is too small +add_config_override($config_overrides, "tapedev", "null:TEST"); +add_config_override($config_overrides, "tpchanger", "chg-test"); +add_config_override_opt($config_overrides, "org=KAOS"); +set_config_overrides($config_overrides); +config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF'); + +is(getconf($CNF_TAPEDEV), "null:TEST", + "config overwrites work with real config"); +is(getconf($CNF_ORG), "KAOS", + "add_config_override_opt parsed correctly"); + +# introduce an error +config_uninit(); +$config_overrides = new_config_overrides(1); +add_config_override($config_overrides, "bogusparam", "foo"); +set_config_overrides($config_overrides); +config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF'); + +my ($error_level, @errors) = Amanda::Config::config_errors(); +is($error_level, $CFGERR_ERRORS, "bogus config overwrite flagged as an error"); + ## # Test configuration dumping @@ -288,11 +555,17 @@ if (!$pid) { Amanda::Config::dump_configuration(); exit 1; } -my $dump = join'', <$kid>; +my $dump_first_line = <$kid>; +my $dump = join'', $dump_first_line, <$kid>; close $kid; +waitpid $pid, 0; my $fn = Amanda::Config::get_config_filename(); -like($dump, qr/AMANDA CONFIGURATION FROM FILE "$fn"/, +my $dump_filename = $dump_first_line; +chomp $dump_filename; +$dump_filename =~ s/^# AMANDA CONFIGURATION FROM FILE "//g; +$dump_filename =~ s/":$//g; +is($dump_filename, $fn, "config filename is included correctly"); like($dump, qr/DEVICE_PROPERTY\s+"foo" "bar"\n/i, @@ -313,49 +586,366 @@ like($dump, qr/INCLUDE\s+LIST OPTIONAL "bing" "ting" "string" "fling"/i, like($dump, qr/INCLUDE\s+FILE OPTIONAL "rhyme"/i, "INCLUDE FILE is in the dump"); +## +# Test nested definitions inside a dumptype + +$testconf = Installcheck::Config->new(); +$testconf->add_dumptype('nested_stuff', [ + 'comment' => '"contains a nested application, pp_script"', + 'application' => '{ + comment "my app" + plugin "amfun" +}', + 'script' => '{ + comment "my script" + plugin "ppfun" +}', +]); + +$testconf->write(); + +$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); +is($cfg_result, $CFGERR_OK, + "parsing nested config loaded") + or diag_config_errors(); +SKIP: { + skip "error loading config", 8 unless $cfg_result == $CFGERR_OK; + + my $dtyp = lookup_dumptype("nested_stuff"); + ok($dtyp, "found nested_stuff"); + + my $appname = dumptype_getconf($dtyp, $DUMPTYPE_APPLICATION); + like($appname, qr/^custom\(/, + "DUMPTYPE_APPLICATION is the generated name of an application subsection"); + + my $app = lookup_application($appname); + ok($app, ".. and that name leads to an application object"); + is(application_getconf($app, $APPLICATION_COMMENT), "my app", + ".. that has the right comment"); + + my $sc = dumptype_getconf($dtyp, $DUMPTYPE_SCRIPTLIST); + ok(ref($sc) eq 'ARRAY' && @$sc == 1, "DUMPTYPE_SCRIPTLIST returns a 1-element list"); + like($sc->[0], qr/^custom\(/, + ".. and the first element is the generated name of a script subsection"); + + $sc = lookup_pp_script($sc->[0]); + ok($sc, ".. and that name leads to a pp_script object"); + is(pp_script_getconf($sc, $PP_SCRIPT_COMMENT), "my script", + ".. that has the right comment"); +} + ## # Explore a quirk of exinclude parsing. Only the last # exclude (or include) directive affects the 'optional' flag. # We may want to change this, but we should do so intentionally. # This is also tested by the 'amgetconf' installcheck. -$testconf = Amconfig->new(); -$testconf->add_dumptype('mydumptype', [ +$testconf = Installcheck::Config->new(); +$testconf->add_dumptype('mydump-type', [ 'exclude list' => '"foo" "bar"', 'exclude list optional append' => '"true" "star"', 'exclude list append' => '"true" "star"', ]); $testconf->write(); -$cfg_ok = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); +$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); +is($cfg_result, $CFGERR_OK, + "first exinclude parsing config loaded") + or diag_config_errors(); SKIP: { - skip "error loading config", unless $cfg_ok; + skip "error loading config", 2 unless $cfg_result == $CFGERR_OK; - my $dtyp = lookup_dumptype("mydumptype"); - ok($dtyp, "found mydumptype"); + my $dtyp = lookup_dumptype("mydump-type"); + ok($dtyp, "found mydump-type"); is(dumptype_getconf($dtyp, $DUMPTYPE_EXCLUDE)->{'optional'}, 0, "'optional' has no effect when not on the last occurrence"); } -$testconf = Amconfig->new(); -$testconf->add_dumptype('mydumptype', [ - 'exclude file' => '"foo" "bar"', - 'exclude file optional append' => '"true" "star"', - 'exclude list append' => '"true" "star"', +## +# Try an autolabel with a template and 'any' + +$testconf = Installcheck::Config->new(); +$testconf->add_param('autolabel', '"FOO%%%BAR" any'); +$testconf->write(); + +$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); +is($cfg_result, $CFGERR_OK, + "first exinclude parsing config loaded") + or diag_config_errors(); +SKIP: { + skip "error loading config", 1 unless $cfg_result == $CFGERR_OK; + is_deeply(getconf($CNF_AUTOLABEL), + { template => "FOO%%%BAR", other_config => 1, + non_amanda => 1, volume_error => 1, empty => 1 }, + "'autolabel \"FOO%%%BAR\" any' represented correctly"); +} + +## +# Check out where quoting is and is not required. + +$testconf = Installcheck::Config->new(); + +# make sure an unquoted tapetype is OK +$testconf->add_param('tapetype', 'TEST-TAPE'); # unquoted (Installcheck::Config uses quoted) + +# strings can optionally be quoted +$testconf->add_param('dumporder', '"STSTST"'); + +# enumerations (e.g., taperalgo) must not be quoted; implicitly tested above + +# definitions +$testconf->add_dumptype('"parent"', [ # note quotes + 'bumpsize' => '10240', +]); +$testconf->add_dumptype('child', [ + '' => '"parent"', # note quotes +]); +$testconf->add_dumptype('child2', [ + '' => 'parent', ]); $testconf->write(); -$cfg_ok = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); +$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); +is($cfg_result, $CFGERR_OK, + "parsed config to test strings vs. identifiers") + or diag_config_errors(); SKIP: { - skip "error loading config", unless $cfg_ok; + skip "error loading config", 3 unless $cfg_result == $CFGERR_OK; + + my $dtyp = lookup_dumptype("parent"); + ok($dtyp, "found parent"); + $dtyp = lookup_dumptype("child"); + ok($dtyp, "found child"); + is(dumptype_getconf($dtyp, $DUMPTYPE_BUMPSIZE), 10240, + "child dumptype correctly inherited bumpsize"); +} - my $dtyp = lookup_dumptype("mydumptype"); - ok($dtyp, "found mydumptype"); - is(dumptype_getconf($dtyp, $DUMPTYPE_EXCLUDE)->{'optional'}, 0, - "'optional' has no effect when not on the last occurrence of 'file'"); +## +# Explore a quirk of read_int_or_str parsing. + +$testconf = Installcheck::Config->new(); +$testconf->add_dumptype('mydump-type1', [ + 'client_port' => '12345', +]); +$testconf->add_dumptype('mydump-type2', [ + 'client_port' => '"newamanda"', +]); +$testconf->add_dumptype('mydump-type3', [ + 'client_port' => '"67890"', +]); +$testconf->write(); + +$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); +is($cfg_result, $CFGERR_OK, + "read_int_or_str parsing config loaded") + or diag_config_errors(); +SKIP: { + skip "error loading config", 6 unless $cfg_result == $CFGERR_OK; + + my $dtyp = lookup_dumptype("mydump-type1"); + ok($dtyp, "found mydump-type1"); + is(dumptype_getconf($dtyp, $DUMPTYPE_CLIENT_PORT), "12345", + "client_port set to 12345"); + + $dtyp = lookup_dumptype("mydump-type2"); + ok($dtyp, "found mydump-type1"); + is(dumptype_getconf($dtyp, $DUMPTYPE_CLIENT_PORT), "newamanda", + "client_port set to \"newamanda\""); + + $dtyp = lookup_dumptype("mydump-type3"); + ok($dtyp, "found mydump-type1"); + is(dumptype_getconf($dtyp, $DUMPTYPE_CLIENT_PORT), "67890", + "client_port set to \"67890\""); } -# TODO: -# overwrites -# inheritance -# more init +## +# Check property inheritance + +$testconf = Installcheck::Config->new(); +$testconf->add_application('app1', [ + 'property' => '"prop1" "val1"' +]); +$testconf->add_application('app2', [ + 'property' => 'append "prop2" "val2"' +]); +$testconf->add_application('app3', [ + 'property' => '"prop3" "val3"' +]); +$testconf->add_application('app1a', [ + 'property' => '"prop4" "val4"', + 'property' => '"prop1" "val1a"', + 'app1' => undef +]); +$testconf->add_application('app2a', [ + 'property' => '"prop5" "val5"', + 'property' => '"prop2" "val2a"', + 'app2' => undef +]); +$testconf->add_application('app3a', [ + 'property' => '"prop6" "val6"', + 'app3' => undef, + 'property' => '"prop7" "val7"' +]); +$testconf->add_application('app1b', [ + 'property' => '"prop4" "val4"', + 'property' => '"prop1" "val1a"', + 'app1' => undef, + 'property' => '"prop1" "val1b"', +]); +$testconf->add_application('app2b', [ + 'property' => '"prop5" "val5"', + 'property' => '"prop2" "val2a"', + 'app2' => undef, + 'property' => 'append "prop2" "val2b"', +]); +$testconf->write(); + +$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); +is($cfg_result, $CFGERR_OK, + "application properties inheritance") + or diag_config_errors(); +SKIP: { + skip "error loading config", 15 unless $cfg_result == $CFGERR_OK; + + my $app = lookup_application("app1a"); + ok($app, "found app1a"); + is(application_name($app), "app1a", + "app1a knows its name"); + my $prop = application_getconf($app, $APPLICATION_PROPERTY); + is_deeply($prop, { "prop4" => { priority => 0, + append => 0, + values => [ "val4" ]}, + "prop1" => { priority => 0, + append => 0, + values => [ "val1" ] }}, + "PROPERTY parameter of app1a parsed correctly"); + + $app = lookup_application("app2a"); + ok($app, "found app2a"); + is(application_name($app), "app2a", + "app2a knows its name"); + $prop = application_getconf($app, $APPLICATION_PROPERTY); + is_deeply($prop, { "prop5" => { priority => 0, + append => 0, + values => [ "val5" ]}, + "prop2" => { priority => 0, + append => 0, + values => [ "val2a", "val2" ] }}, + "PROPERTY parameter of app2a parsed correctly"); + + $app = lookup_application("app3a"); + ok($app, "found app3a"); + is(application_name($app), "app3a", + "app3a knows its name"); + $prop = application_getconf($app, $APPLICATION_PROPERTY); + is_deeply($prop, { "prop3" => { priority => 0, + append => 0, + values => [ "val3" ]}, + "prop6" => { priority => 0, + append => 0, + values => [ "val6" ] }, + "prop7" => { priority => 0, + append => 0, + values => [ "val7" ] }}, + "PROPERTY parameter of app3a parsed correctly"); + + $app = lookup_application("app1b"); + ok($app, "found app1b"); + is(application_name($app), "app1b", + "app1b knows its name"); + $prop = application_getconf($app, $APPLICATION_PROPERTY); + is_deeply($prop, { "prop4" => { priority => 0, + append => 0, + values => [ "val4" ]}, + "prop1" => { priority => 0, + append => 0, + values => [ "val1b" ] }}, + "PROPERTY parameter of app1b parsed correctly"); + + $app = lookup_application("app2b"); + ok($app, "found app2b"); + is(application_name($app), "app2b", + "app2b knows its name"); + $prop = application_getconf($app, $APPLICATION_PROPERTY); + is_deeply($prop, { "prop5" => { priority => 0, + append => 0, + values => [ "val5" ]}, + "prop2" => { priority => 0, + append => 1, + values => [ "val2a", "val2", "val2b" ] }}, + "PROPERTY parameter of app2b parsed correctly"); +} + + +## +# Check getconf_byname and getconf_byname_strs + +$testconf = Installcheck::Config->new(); +$testconf->add_param('tapedev', '"thats a funny name"'); +$testconf->add_application('app1', [ + 'comment' => '"one"', +]); +$testconf->add_script('scr1', [ + 'comment' => '"one"', +]); +# check old names, too +$testconf->add_text(<add_text(<write(); + +$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); +is($cfg_result, $CFGERR_OK, + "getconf_byname") + or diag_config_errors(); +SKIP: { + skip "error loading config", 7 unless $cfg_result == $CFGERR_OK; + + is(getconf_byname("Tapedev"), "thats a funny name", + "getconf_byname for global param"); + is_deeply([ getconf_byname_strs("Tapedev", 1) ], + [ "\"thats a funny name\"" ], + "getconf_byname_strs for global param with quotes"); + is_deeply([ getconf_byname_strs("Tapedev", 0) ], + [ "thats a funny name" ], + "getconf_byname_strs for global param without quotes"); + + # test * and *-tool (the old name) + is(getconf_byname("application-tool:app1:comment"), "one", + "getconf_byname for appplication-tool param"); + is(getconf_byname("application:app2:comment"), "two", + "getconf_byname for application param"); + is(getconf_byname("script-tool:scr1:comment"), "one", + "getconf_byname for appplication-tool param"); + is(getconf_byname("script:scr2:comment"), "two", + "getconf_byname for script param"); +} + +my @boolean_vals = ( + {'val' => '1', 'expected' => 1}, + {'val' => '0', 'expected' => 0}, + {'val' => 't', 'expected' => 1}, + {'val' => 'true', 'expected' => 1}, + {'val' => 'f', 'expected' => 0}, + {'val' => 'false', 'expected' => 0}, + {'val' => 'y', 'expected' => 1}, + {'val' => 'yes', 'expected' => 1}, + {'val' => 'n', 'expected' => 0}, + {'val' => 'no', 'expected' => 0}, + {'val' => 'on', 'expected' => 1}, + {'val' => 'off', 'expected' => 0}, + {'val' => 'oFf', 'expected' => 0}, + {'val' => 'foo', 'expected' => undef}, + ); + +for my $bv (@boolean_vals) { + is(string_to_boolean($bv->{'val'}), $bv->{'expected'}, + "string_to_boolean('$bv->{'val'}') is right"); +}