1# Copyright (c) 2007-2013 Zmanda, Inc. All Rights Reserved. 2# 3# This program is free software; you can redistribute it and/or 4# modify it under the terms of the GNU General Public License 5# as published by the Free Software Foundation; either version 2 6# of the License, or (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, but 9# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 10# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11# for more details. 12# 13# You should have received a copy of the GNU General Public License along 14# with this program; if not, write to the Free Software Foundation, Inc., 15# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16# 17# Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300 18# Sunnyvale, CA 94086, USA, or: http://www.zmanda.com 19 20use Test::More tests => 224; 21use strict; 22use warnings; 23use Data::Dumper; 24 25use lib "@amperldir@"; 26use Installcheck::Config; 27use Amanda::Paths; 28use Amanda::Tests; 29use Amanda::Config qw( :init :getconf string_to_boolean amandaify_property_name ); 30use Amanda::Debug; 31 32my $testconf; 33my $config_overrides; 34 35Amanda::Debug::dbopen("installcheck"); 36Installcheck::log_test_output(); 37 38# utility function 39 40sub diag_config_errors { 41 my ($level, @errors) = Amanda::Config::config_errors(); 42 for my $errmsg (@errors) { 43 diag $errmsg; 44 } 45} 46 47## 48# Try starting with no configuration at all 49 50is(config_init(0, ''), $CFGERR_OK, 51 "Initialize with no configuration") 52 or diag_config_errors(); 53 54config_uninit(); 55$config_overrides = new_config_overrides(1); 56add_config_override($config_overrides, "tapedev", "null:TEST"); 57set_config_overrides($config_overrides); 58 59is(config_init(0, undef), $CFGERR_OK, 60 "Initialize with no configuration, passing a NULL config name") 61 or diag_config_errors(); 62 63is(getconf($CNF_TAPEDEV), "null:TEST", 64 "config overwrites work with null config"); 65 66## 67# Check out error handling 68 69$testconf = Installcheck::Config->new(); 70$testconf->add_param('label_new_tapes', '"xx"'); # a deprecated keyword -> warning 71$testconf->write(); 72 73{ 74 is(config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"), $CFGERR_WARNINGS, 75 "Deprecated keyword generates a warning"); 76 my ($error_level, @errors) = Amanda::Config::config_errors(); 77 like($errors[0], qr/is deprecated/, 78 "config_get_errors returns the warning string"); 79 80 Amanda::Config::config_clear_errors(); 81 ($error_level, @errors) = Amanda::Config::config_errors(); 82 is(scalar(@errors), 0, "config_clear_errors clears error list"); 83} 84 85$testconf = Installcheck::Config->new(); 86$testconf->add_param('invalid-param', 'random-value'); # a deprecated keyword -> warning 87$testconf->write(); 88 89is(config_init($CONFIG_INIT_EXPLICIT_NAME, "NO-SUCH-CONFIGURATION"), $CFGERR_ERRORS, 90 "Non-existent config generates an error"); 91 92is(config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"), $CFGERR_ERRORS, 93 "Invalid keyword generates an error"); 94 95## 96# try a client configuration 97 98# (note use of uppercase letters to test lower-casing of property names) 99$testconf = Installcheck::Config->new(); 100$testconf->add_client_param('property', '"client-prop" "yep"'); 101$testconf->add_client_param('property', 'priority "clIent-prop1" "foo"'); 102$testconf->add_client_param('property', 'append "clieNt-prop" "bar"'); 103$testconf->add_client_param('property', '"ANotHer_prOp" "baz"'); 104$testconf->add_client_param('property', 'append "ANOTHER-prop" "boo"'); 105$testconf->write(); 106 107my $cfg_result = config_init($CONFIG_INIT_CLIENT, undef); 108is($cfg_result, $CFGERR_OK, 109 "Load test client configuration") 110 or diag_config_errors(); 111 112is_deeply(getconf($CNF_PROPERTY), { "client-prop1" => { priority => 1, 113 append => 0, 114 values => [ "foo" ]}, 115 "client-prop" => { priority => 0, 116 append => 1, 117 values => [ "yep", "bar" ] }, 118 "another-prop" => { priority => 0, 119 append => 1, 120 values => [ "baz", "boo" ] }}, 121 "Client PROPERTY parameter parsed correctly"); 122 123## 124# Parse up a basic configuration 125 126# invent a "large" unsigned number, and make $size_t_num 127# depend on the length of size_t 128my $int64_num = '171801575472'; # 0xA000B000C000 / 1024 129my $size_t_num; 130if (Amanda::Tests::sizeof_size_t() > 4) { 131 $size_t_num = $int64_num; 132} else { 133 $size_t_num = '2147483647'; # 0x7fffffff 134} 135 136$testconf = Installcheck::Config->new(); 137$testconf->add_param('reserve', '75'); 138$testconf->add_param('autoflush', 'yes'); 139$testconf->add_param('usetimestamps', '0'); 140$testconf->add_param('tapedev', '"/dev/foo"'); 141$testconf->add_param('bumpsize', $int64_num); 142$testconf->add_param('bumpmult', '1.4'); 143$testconf->add_param('reserved_udp-port', '100,200'); # note use of '-' and '_' 144$testconf->add_param('device_output_buffer_size', $size_t_num); 145$testconf->add_param('taperalgo', 'last'); 146$testconf->add_param('device_property', '"foo" "bar"'); 147$testconf->add_param('device_property', '"blUE" "car" "tar"'); 148$testconf->add_param('autolabel', 'non-amanda empty'); 149$testconf->add_param('displayunit', '"m"'); 150$testconf->add_param('debug_auth', '1'); 151$testconf->add_tapetype('mytapetype', [ 152 'comment' => '"mine"', 153 'length' => '128 M', 154 'part_size' => '100M', 155 'part_cache_type' => 'disk', 156 'part_cache_dir' => '"/usr/bin"', 157 'part_cache_max_size' => '50M', 158]); 159$testconf->add_dumptype('mydump-type', [ # note dash 160 'comment' => '"mine"', 161 'priority' => 'high', # == 2 162 'bumpsize' => $int64_num, 163 'bumpmult' => 1.75, 164 'starttime' => 1829, 165 'holdingdisk' => 'required', 166 'compress' => 'client best', 167 'encrypt' => 'server', 168 'strategy' => 'incronly', 169 'comprate' => '0.25,0.75', 170 'exclude list' => '"foo" "bar"', 171 'exclude list append' => '"true" "star"', 172 'exclude file' => '"foolist"', 173 'include list' => '"bing" "ting"', 174 'include list append' => '"string" "fling"', 175 'include file optional' => '"rhyme"', 176 'property' => '"prop" "erty"', 177 'property' => '"DROP" "qwerty" "asdfg"', 178 'estimate' => 'server calcsize client', 179 'allow_split' => 'no', 180 'allow_split' => 'no', 181]); 182$testconf->add_dumptype('second_dumptype', [ # note underscore 183 '' => 'mydump-type', 184 'comment' => '"refers to mydump-type with a dash"', 185]); 186$testconf->add_dumptype('third_dumptype', [ 187 '' => 'second_dumptype', 188 'comment' => '"refers to second_dumptype with an underscore"', 189 'recovery-limit' => '"left" same-host "right"', 190]); 191$testconf->add_interface('ethernet', [ 192 'comment' => '"mine"', 193 'use' => '100', 194]); 195$testconf->add_interface('nic', [ 196 'comment' => '"empty"', 197]); 198$testconf->add_holdingdisk('hd1', [ 199 'comment' => '"mine"', 200 'directory' => '"/mnt/hd1"', 201 'use' => '100M', 202 'chunksize' => '1024k', 203]); 204$testconf->add_holdingdisk('hd2', [ 205 'comment' => '"empty"', 206]); 207$testconf->add_application('my_app', [ 208 'comment' => '"my_app_comment"', 209 'plugin' => '"amgtar"', 210]); 211$testconf->add_script('my_script', [ 212 'comment' => '"my_script_comment"', 213 'plugin' => '"script-email"', 214 'execute-on' => 'pre-host-backup, post-host-backup', 215 'execute-where' => 'client', 216 'property' => '"mailto" "amandabackup" "amanda"', 217]); 218$testconf->add_device('my_device', [ 219 'comment' => '"my device is mine, not yours"', 220 'tapedev' => '"tape:/dev/nst0"', 221 'device_property' => '"BLOCK_SIZE" "128k"', 222 'device_property' => '"CoMmENT" "what up?"', 223]); 224$testconf->add_changer('my_changer', [ 225 'comment' => '"my changer is mine, not yours"', 226 'tpchanger' => '"chg-foo"', 227 'changerdev' => '"/dev/sg0"', 228 'changerfile' => '"chg.state"', 229 'property' => '"testprop" "testval"', 230 'device_property' => '"testdprop" "testdval"', 231]); 232$testconf->add_interactivity('my_interactivity', [ 233 'comment' => '"my interactivity is mine, not yours"', 234 'plugin' => '"MY-interactivity"', 235 'property' => '"testprop" "testval"', 236]); 237 238$testconf->add_taperscan('my_taperscan', [ 239 'comment' => '"my taperscan is mine, not yours"', 240 'plugin' => '"MY-taperscan"', 241 'property' => '"testprop" "testval"', 242]); 243 244$testconf->write(); 245 246$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF'); 247if (!is($cfg_result, $CFGERR_OK, 248 "Load test configuration")) { 249 diag_config_errors(); 250 die "aborting after config errors"; 251} 252 253is(Amanda::Config::get_config_name(), "TESTCONF", 254 "config_name set"); 255is(Amanda::Config::get_config_dir(), "$CONFIG_DIR/TESTCONF", 256 "config_dir set"); 257is(Amanda::Config::get_config_filename(), 258 "$CONFIG_DIR/TESTCONF/amanda.conf", 259 "config_filename set"); 260 261is(getconf($CNF_RESERVE), 75, 262 "integer global confparm"); 263is(getconf($CNF_BUMPSIZE), $int64_num+0, 264 "int64 global confparm"); 265is(getconf($CNF_TAPEDEV), "/dev/foo", 266 "string global confparm"); 267is(getconf($CNF_DEVICE_OUTPUT_BUFFER_SIZE), $size_t_num+0, 268 "size global confparm"); 269ok(getconf($CNF_AUTOFLUSH), 270 "boolean global confparm"); 271is(getconf($CNF_USETIMESTAMPS), 0, 272 "boolean global confparm, passing an integer (0)"); 273is(getconf($CNF_TAPERALGO), $Amanda::Config::ALGO_LAST, 274 "taperalgo global confparam"); 275is_deeply([getconf($CNF_RESERVED_UDP_PORT)], [100,200], 276 "intrange global confparm"); 277is(getconf($CNF_DISPLAYUNIT), "M", 278 "displayunit is correctly uppercased"); 279is_deeply(getconf($CNF_DEVICE_PROPERTY), 280 { "foo" => { priority => 0, append => 0, values => ["bar"]}, 281 "blue" => { priority => 0, append => 0, 282 values => ["car", "tar"]} }, 283 "proplist global confparm"); 284is_deeply(getconf($CNF_AUTOLABEL), 285 { template => undef, other_config => '', 286 non_amanda => 1, volume_error => '', empty => 1 }, 287 "'autolabel non-amanda empty' represented correctly"); 288ok(getconf_seen($CNF_TAPEDEV), 289 "'tapedev' parm was seen"); 290ok(!getconf_seen($CNF_CHANGERFILE), 291 "'changerfile' parm was not seen"); 292 293is(Amanda::Config::getconf_unit_divisor(), 1024, 294 "correct unit divisor (from displayunit -> KB)"); 295ok($Amanda::Config::debug_auth, 296 "debug_auth setting reflected in global variable"); 297ok(!$Amanda::Config::debug_amandad, 298 "debug_amandad defaults to false"); 299 300my $ttyp = lookup_tapetype("mytapetype"); 301ok($ttyp, "found mytapetype"); 302is(tapetype_getconf($ttyp, $TAPETYPE_COMMENT), 'mine', 303 "tapetype comment"); 304is(tapetype_getconf($ttyp, $TAPETYPE_LENGTH), 128 * 1024, 305 "tapetype comment"); 306 307ok(tapetype_seen($ttyp, $TAPETYPE_COMMENT), 308 "tapetype comment was seen"); 309ok(!tapetype_seen($ttyp, $TAPETYPE_LBL_TEMPL), 310 "tapetype lbl_templ was not seen"); 311 312is(tapetype_getconf($ttyp, $TAPETYPE_PART_SIZE), 100*1024, 313 "tapetype part_size"); 314is(tapetype_getconf($ttyp, $TAPETYPE_PART_CACHE_TYPE), $PART_CACHE_TYPE_DISK, 315 "tapetype part_cache_type"); 316is(tapetype_getconf($ttyp, $TAPETYPE_PART_CACHE_DIR), "/usr/bin", 317 "tapetype part_cache_dir"); 318is(tapetype_getconf($ttyp, $TAPETYPE_PART_CACHE_MAX_SIZE), 50*1024, 319 "tapetype part_cache_max_size"); 320 321is_deeply([ sort(+getconf_list("tapetype")) ], 322 [ sort("mytapetype", "TEST-TAPE") ], 323 "getconf_list lists all tapetypes"); 324 325my $dtyp = lookup_dumptype("mydump-type"); 326ok($dtyp, "found mydump-type"); 327is(dumptype_getconf($dtyp, $DUMPTYPE_COMMENT), 'mine', 328 "dumptype string"); 329is(dumptype_getconf($dtyp, $DUMPTYPE_PRIORITY), 2, 330 "dumptype priority"); 331is(dumptype_getconf($dtyp, $DUMPTYPE_BUMPSIZE), $int64_num+0, 332 "dumptype size"); 333is(dumptype_getconf($dtyp, $DUMPTYPE_BUMPMULT), 1.75, 334 "dumptype real"); 335is(dumptype_getconf($dtyp, $DUMPTYPE_STARTTIME), 1829, 336 "dumptype time"); 337is(dumptype_getconf($dtyp, $DUMPTYPE_HOLDINGDISK), $HOLD_REQUIRED, 338 "dumptype holdingdisk"); 339is(dumptype_getconf($dtyp, $DUMPTYPE_COMPRESS), $COMP_BEST, 340 "dumptype compress"); 341is(dumptype_getconf($dtyp, $DUMPTYPE_ENCRYPT), $ENCRYPT_SERV_CUST, 342 "dumptype encrypt"); 343is(dumptype_getconf($dtyp, $DUMPTYPE_STRATEGY), $DS_INCRONLY, 344 "dumptype strategy"); 345is_deeply([dumptype_getconf($dtyp, $DUMPTYPE_COMPRATE)], [0.25, 0.75], 346 "dumptype comprate"); 347is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_INCLUDE), 348 { 'file' => [ 'rhyme' ], 349 'list' => [ 'bing', 'ting', 'string', 'fling' ], 350 'optional' => 1 }, 351 "dumptype include list"); 352is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_EXCLUDE), 353 { 'file' => [ 'foolist' ], 354 'list' => [ 'foo', 'bar', 'true', 'star' ], 355 'optional' => 0 }, 356 "dumptype exclude list"); 357is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_ESTIMATELIST), 358 [ $ES_SERVER, $ES_CALCSIZE, $ES_CLIENT ], 359 "dumptype estimate list"); 360is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_PROPERTY), 361 { "prop" => { priority => 0, append => 0, values => ["erty"]}, 362 "drop" => { priority => 0, append => 0, 363 values => ["qwerty", "asdfg"] }}, 364 "dumptype proplist"); 365is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_RECOVERY_LIMIT), 366 [], 367 "dumptype recovery limit with no limit specified => empty"); 368 369ok(dumptype_seen($dtyp, $DUMPTYPE_EXCLUDE), 370 "'exclude' parm was seen"); 371ok(!dumptype_seen($dtyp, $DUMPTYPE_RECORD), 372 "'record' parm was not seen"); 373 374is_deeply([ sort(+getconf_list("dumptype")) ], 375 [ sort(qw( 376 mydump-type second_dumptype third_dumptype 377 NO-COMPRESS COMPRESS-FAST COMPRESS-BEST COMPRESS-CUST 378 SRVCOMPRESS BSD-AUTH BSDTCP-AUTH NO-RECORD NO-HOLD 379 NO-FULL 380 )) ], 381 "getconf_list lists all dumptypes (including defaults)"); 382is(dumptype_getconf($dtyp, $DUMPTYPE_ALLOW_SPLIT), 0, 383 "dumptype allow_split"); 384 385my $iface = lookup_interface("ethernet"); 386ok($iface, "found ethernet"); 387is(interface_name($iface), "ethernet", 388 "interface knows its name"); 389is(interface_getconf($iface, $INTER_COMMENT), 'mine', 390 "interface comment"); 391is(interface_getconf($iface, $INTER_MAXUSAGE), 100, 392 "interface maxusage"); 393 394$iface = lookup_interface("nic"); 395ok($iface, "found nic"); 396ok(interface_seen($iface, $INTER_COMMENT), 397 "seen set for parameters that appeared"); 398ok(!interface_seen($iface, $INTER_MAXUSAGE), 399 "seen not set for parameters that did not appear"); 400 401is_deeply([ sort(+getconf_list("interface")) ], 402 [ sort('ethernet', 'nic', 'default') ], 403 "getconf_list lists all interfaces (in any order)"); 404 405skip "error loading config", 13 unless $cfg_result == $CFGERR_OK; 406my $hdisk = lookup_holdingdisk("hd1"); 407ok($hdisk, "found hd1"); 408is(holdingdisk_name($hdisk), "hd1", 409 "hd1 knows its name"); 410is(holdingdisk_getconf($hdisk, $HOLDING_COMMENT), 'mine', 411 "holdingdisk comment"); 412is(holdingdisk_getconf($hdisk, $HOLDING_DISKDIR), '/mnt/hd1', 413 "holdingdisk diskdir (directory)"); 414is(holdingdisk_getconf($hdisk, $HOLDING_DISKSIZE), 100*1024, 415 "holdingdisk disksize (use)"); 416is(holdingdisk_getconf($hdisk, $HOLDING_CHUNKSIZE), 1024, 417 "holdingdisk chunksize"); 418 419$hdisk = lookup_holdingdisk("hd2"); 420ok($hdisk, "found hd2"); 421ok(holdingdisk_seen($hdisk, $HOLDING_COMMENT), 422 "seen set for parameters that appeared"); 423ok(!holdingdisk_seen($hdisk, $HOLDING_CHUNKSIZE), 424 "seen not set for parameters that did not appear"); 425 426# only holdingdisks have this linked-list structure 427# exposed 428my $hdisklist = getconf($CNF_HOLDINGDISK); 429my $first_disk = @$hdisklist[0]; 430$hdisk = lookup_holdingdisk($first_disk); 431like(holdingdisk_name($hdisk), qr/hd[12]/, 432 "one disk is first in list of holdingdisks"); 433$hdisk = lookup_holdingdisk(@$hdisklist[1]); 434like(holdingdisk_name($hdisk), qr/hd[12]/, 435 "another is second in list of holdingdisks"); 436ok($#$hdisklist == 1, 437 "no third holding disk"); 438 439is_deeply([ sort(+getconf_list("holdingdisk")) ], 440 [ sort('hd1', 'hd2') ], 441 "getconf_list lists all holdingdisks (in any order)"); 442 443skip "error loading config", 5 unless $cfg_result == $CFGERR_OK; 444my $app = lookup_application("my_app"); 445ok($app, "found my_app"); 446is(application_name($app), "my_app", 447 "my_app knows its name"); 448is(application_getconf($app, $APPLICATION_COMMENT), 'my_app_comment', 449 "application comment"); 450is(application_getconf($app, $APPLICATION_PLUGIN), 'amgtar', 451 "application plugin (amgtar)"); 452 453is_deeply([ sort(+getconf_list("application-tool")) ], 454 [ sort("my_app") ], 455 "getconf_list lists all applications"); 456# test backward compatibility 457is_deeply([ sort(+getconf_list("application")) ], 458 [ sort("my_app") ], 459 "getconf_list works for 'application-tool', too"); 460 461my $sc = lookup_pp_script("my_script"); 462ok($sc, "found my_script"); 463is(pp_script_name($sc), "my_script", 464 "my_script knows its name"); 465is(pp_script_getconf($sc, $PP_SCRIPT_COMMENT), 'my_script_comment', 466 "script comment"); 467is(pp_script_getconf($sc, $PP_SCRIPT_PLUGIN), 'script-email', 468 "script plugin (script-email)"); 469is(pp_script_getconf($sc, $PP_SCRIPT_EXECUTE_WHERE), $ES_CLIENT, 470 "script execute_where (client)"); 471is(pp_script_getconf($sc, $PP_SCRIPT_EXECUTE_ON), 472 $EXECUTE_ON_PRE_HOST_BACKUP|$EXECUTE_ON_POST_HOST_BACKUP, 473 "script execute_on"); 474 475is_deeply([ sort(+getconf_list("script")) ], 476 [ sort("my_script") ], 477 "getconf_list lists all script"); 478 479is_deeply([ sort(+getconf_list("script-tool")) ], 480 [ sort("my_script") ], 481 "getconf_list works for 'script-tool', too"); 482 483my $dc = lookup_device_config("my_device"); 484ok($dc, "found my_device"); 485is(device_config_name($dc), "my_device", 486 "my_device knows its name"); 487is(device_config_getconf($dc, $DEVICE_CONFIG_COMMENT), 'my device is mine, not yours', 488 "device comment"); 489is(device_config_getconf($dc, $DEVICE_CONFIG_TAPEDEV), 'tape:/dev/nst0', 490 "device tapedev"); 491# TODO do we really need all of this equipment for device properties? 492is_deeply(device_config_getconf($dc, $DEVICE_CONFIG_DEVICE_PROPERTY), 493 { "block-size" => { 'priority' => 0, 'values' => ["128k"], 'append' => 0 }, 494 "comment" => { 'priority' => 0, 'values' => ["what up?"], 'append' => 0 }, }, 495 "device config proplist"); 496 497is_deeply([ sort(+getconf_list("device")) ], 498 [ sort("my_device") ], 499 "getconf_list lists all devices"); 500 501skip "error loading config", 7 unless $cfg_result == $CFGERR_OK; 502$dc = lookup_changer_config("my_changer"); 503ok($dc, "found my_changer"); 504is(changer_config_name($dc), "my_changer", 505 "my_changer knows its name"); 506is(changer_config_getconf($dc, $CHANGER_CONFIG_COMMENT), 'my changer is mine, not yours', 507 "changer comment"); 508is(changer_config_getconf($dc, $CHANGER_CONFIG_CHANGERDEV), '/dev/sg0', 509 "changer tapedev"); 510is_deeply(changer_config_getconf($dc, $CHANGER_CONFIG_PROPERTY), 511 { 'testprop' => { 512 'priority' => 0, 513 'values' => [ 'testval' ], 514 'append' => 0, 515 } 516 }, "changer properties represented correctly"); 517 518is_deeply(changer_config_getconf($dc, $CHANGER_CONFIG_DEVICE_PROPERTY), 519 { 'testdprop' => { 520 'priority' => 0, 521 'values' => [ 'testdval' ], 522 'append' => 0, 523 } 524 }, "changer device properties represented correctly"); 525 526is_deeply([ sort(+getconf_list("changer")) ], 527 [ sort("my_changer") ], 528 "getconf_list lists all changers"); 529 530$dc = lookup_interactivity("my_interactivity"); 531ok($dc, "found my_interactivity"); 532is(interactivity_name($dc), "my_interactivity", 533 "my_interactivity knows its name"); 534is(interactivity_getconf($dc, $INTERACTIVITY_COMMENT), 'my interactivity is mine, not yours', 535 "interactivity comment"); 536is(interactivity_getconf($dc, $INTERACTIVITY_PLUGIN), 'MY-interactivity', 537 "interactivity plugin"); 538is_deeply(interactivity_getconf($dc, $INTERACTIVITY_PROPERTY), 539 { 'testprop' => { 540 'priority' => 0, 541 'values' => [ 'testval' ], 542 'append' => 0, 543 } 544 }, "interactivity properties represented correctly"); 545 546is_deeply([ sort(+getconf_list("interactivity")) ], 547 [ sort("my_interactivity") ], 548 "getconf_list lists all interactivity"); 549 550$dc = lookup_taperscan("my_taperscan"); 551ok($dc, "found my_taperscan"); 552is(taperscan_name($dc), "my_taperscan", 553 "my_taperscan knows its name"); 554is(taperscan_getconf($dc, $TAPERSCAN_COMMENT), 'my taperscan is mine, not yours', 555 "taperscan comment"); 556is(taperscan_getconf($dc, $TAPERSCAN_PLUGIN), 'MY-taperscan', 557 "taperscan plugin"); 558is_deeply(taperscan_getconf($dc, $TAPERSCAN_PROPERTY), 559 { 'testprop' => { 560 'priority' => 0, 561 'values' => [ 'testval' ], 562 'append' => 0, 563 } 564 }, "taperscan properties represented correctly"); 565 566is_deeply([ sort(+getconf_list("taperscan")) ], 567 [ sort("my_taperscan") ], 568 "getconf_list lists all taperscan"); 569 570 571## 572# Test config overwrites (using the config from above) 573 574config_uninit(); 575$config_overrides = new_config_overrides(1); # note estimate is too small 576add_config_override($config_overrides, "tapedev", "null:TEST"); 577add_config_override($config_overrides, "tpchanger", "chg-test"); 578add_config_override_opt($config_overrides, "org=KAOS"); 579set_config_overrides($config_overrides); 580config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF'); 581 582is(getconf($CNF_TAPEDEV), "null:TEST", 583 "config overwrites work with real config"); 584is(getconf($CNF_ORG), "KAOS", 585 "add_config_override_opt parsed correctly"); 586 587# introduce an error 588config_uninit(); 589$config_overrides = new_config_overrides(1); 590add_config_override($config_overrides, "bogusparam", "foo"); 591set_config_overrides($config_overrides); 592config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF'); 593 594my ($error_level, @errors) = Amanda::Config::config_errors(); 595is($error_level, $CFGERR_ERRORS, "bogus config overwrite flagged as an error"); 596 597## 598# Test configuration dumping 599 600# (uses the config from the previous section) 601 602# fork a child and capture its stdout 603my $pid = open(my $kid, "-|"); 604die "Can't fork: $!" unless defined($pid); 605if (!$pid) { 606 Amanda::Config::dump_configuration(1, 0); 607 exit 1; 608} 609my $dump_first_line = <$kid>; 610my $dump = join'', $dump_first_line, <$kid>; 611close $kid; 612waitpid $pid, 0; 613 614my $fn = Amanda::Config::get_config_filename(); 615my $dump_filename = $dump_first_line; 616chomp $dump_filename; 617$dump_filename =~ s/^# AMANDA CONFIGURATION FROM FILE "//g; 618$dump_filename =~ s/":$//g; 619is($dump_filename, $fn, 620 "config filename is included correctly"); 621 622like($dump, qr/DEVICE-PROPERTY\s+"foo" "bar"\n/i, 623 "DEVICE-PROPERTY appears in dump output"); 624 625like($dump, qr/AMRECOVER-CHECK-LABEL\s+(yes|no)/i, 626 "AMRECOVER-CHECK-LABEL has a trailing space"); 627 628like($dump, qr/AMRECOVER-CHECK-LABEL\s+(yes|no)/i, 629 "AMRECOVER-CHECK-LABEL has a trailing space"); 630 631like($dump, qr/EXCLUDE\s+LIST "foo" "bar" "true" "star"/i, 632 "EXCLUDE LIST is in the dump"); 633like($dump, qr/EXCLUDE\s+FILE "foolist"/i, 634 "EXCLUDE FILE is in the dump"); 635like($dump, qr/INCLUDE\s+LIST OPTIONAL "bing" "ting" "string" "fling"/i, 636 "INCLUDE LIST is in the dump"); 637like($dump, qr/INCLUDE\s+FILE OPTIONAL "rhyme"/i, 638 "INCLUDE FILE is in the dump"); 639like($dump, qr/RECOVERY-LIMIT.*SAME-HOST/i, 640 "RECOVERY-LIST is in the dump"); 641 642## 643# Test nested definitions inside a dumptype 644 645$testconf = Installcheck::Config->new(); 646$testconf->add_dumptype('nested_stuff', [ 647 'comment' => '"contains a nested application, pp_script"', 648 'application' => '{ 649 comment "my app" 650 plugin "amfun" 651}', 652 'script' => '{ 653 comment "my script" 654 plugin "ppfun" 655}', 656]); 657 658$testconf->write(); 659 660$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); 661is($cfg_result, $CFGERR_OK, 662 "parsing nested config loaded") 663 or diag_config_errors(); 664SKIP: { 665 skip "error loading config", 8 unless $cfg_result == $CFGERR_OK; 666 667 my $dtyp = lookup_dumptype("nested_stuff"); 668 ok($dtyp, "found nested_stuff"); 669 670 my $appname = dumptype_getconf($dtyp, $DUMPTYPE_APPLICATION); 671 like($appname, qr/^custom\(/, 672 "DUMPTYPE_APPLICATION is the generated name of an application subsection"); 673 674 my $app = lookup_application($appname); 675 ok($app, ".. and that name leads to an application object"); 676 is(application_getconf($app, $APPLICATION_COMMENT), "my app", 677 ".. that has the right comment"); 678 679 my $sc = dumptype_getconf($dtyp, $DUMPTYPE_SCRIPTLIST); 680 ok(ref($sc) eq 'ARRAY' && @$sc == 1, "DUMPTYPE_SCRIPTLIST returns a 1-element list"); 681 like($sc->[0], qr/^custom\(/, 682 ".. and the first element is the generated name of a script subsection"); 683 684 $sc = lookup_pp_script($sc->[0]); 685 ok($sc, ".. and that name leads to a pp_script object"); 686 is(pp_script_getconf($sc, $PP_SCRIPT_COMMENT), "my script", 687 ".. that has the right comment"); 688} 689 690## 691# Explore a quirk of exinclude parsing. Only the last 692# exclude (or include) directive affects the 'optional' flag. 693# We may want to change this, but we should do so intentionally. 694# This is also tested by the 'amgetconf' installcheck. 695 696$testconf = Installcheck::Config->new(); 697$testconf->add_dumptype('mydump-type', [ 698 'exclude list' => '"foo" "bar"', 699 'exclude list optional append' => '"true" "star"', 700 'exclude list append' => '"true" "star"', 701]); 702$testconf->write(); 703 704$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); 705is($cfg_result, $CFGERR_OK, 706 "first exinclude parsing config loaded") 707 or diag_config_errors(); 708SKIP: { 709 skip "error loading config", 2 unless $cfg_result == $CFGERR_OK; 710 711 my $dtyp = lookup_dumptype("mydump-type"); 712 ok($dtyp, "found mydump-type"); 713 is(dumptype_getconf($dtyp, $DUMPTYPE_EXCLUDE)->{'optional'}, 0, 714 "'optional' has no effect when not on the last occurrence"); 715} 716 717## 718# Check out recovery-limit parsing 719 720$testconf = Installcheck::Config->new(); 721$testconf->add_param('recovery-limit', '"foo" "bar"'); 722$testconf->add_dumptype('rl1', [ 723 'recovery-limit' => 'same-host server', 724]); 725$testconf->add_dumptype('rl2', [ 726 'recovery-limit' => '"somehost"', 727]); 728$testconf->add_dumptype('rl3', [ 729 'recovery-limit' => 'same-host server "somehost"', 730]); 731$testconf->add_dumptype('rl4', [ 732 'recovery-limit' => '"foohost" same-host', 733]); 734$testconf->write(); 735 736$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); 737is($cfg_result, $CFGERR_OK, 738 "recovery-limit config loaded") 739 or diag_config_errors(); 740SKIP: { 741 skip "error loading config", 5 unless $cfg_result == $CFGERR_OK; 742 my $dtyp; 743 744 is_deeply(getconf($CNF_RECOVERY_LIMIT), 745 [ 'foo', 'bar' ], 746 "global recovery-limit parameter"); 747 748 $dtyp = lookup_dumptype("rl1"); 749 is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_RECOVERY_LIMIT), 750 [ "SAMEHOST-SAMEHOST-SAMEHOST", "SERVER-SERVER-SERVER" ], 751 "same-host => undef in list"); 752 753 $dtyp = lookup_dumptype("rl2"); 754 is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_RECOVERY_LIMIT), 755 [ "somehost" ], 756 "hostname => match pattern"); 757 758 $dtyp = lookup_dumptype("rl3"); 759 is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_RECOVERY_LIMIT), 760 [ "SAMEHOST-SAMEHOST-SAMEHOST", "SERVER-SERVER-SERVER", "somehost" ], 761 "hostname and same-host parsed correctly"); 762 763 $dtyp = lookup_dumptype("rl4"); 764 is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_RECOVERY_LIMIT), 765 [ "SAMEHOST-SAMEHOST-SAMEHOST", "foohost" ], # note that the order is an implementation detail 766 ".. even if same-host comes last"); 767} 768 769## 770# Check out dump-limit parsing 771 772$testconf = Installcheck::Config->new(); 773$testconf->add_dumptype('dl1', [ 774 'dump-limit' => 'same-host', 775]); 776$testconf->add_dumptype('dl2', [ 777 'dump-limit' => 'server', 778]); 779$testconf->add_dumptype('dl3', [ 780 'dump-limit' => 'same-host server', 781]); 782$testconf->write(); 783 784$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); 785is($cfg_result, $CFGERR_OK, 786 "dump-limit config loaded") 787 or diag_config_errors(); 788SKIP: { 789 skip "error loading config", 5 unless $cfg_result == $CFGERR_OK; 790 my $dtyp; 791 792 $dtyp = lookup_dumptype("dl1"); 793 is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_DUMP_LIMIT), 794 [ "SAMEHOST-SAMEHOST-SAMEHOST" ], 795 "same-host => \"SAMEHOST-SAMEHOST-SAMEHOST\" in list"); 796 797 $dtyp = lookup_dumptype("dl2"); 798 is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_DUMP_LIMIT), 799 [ "SERVER-SERVER-SERVER" ], 800 "server => \"SERVER-SERVER-SERVER\" in list"); 801 802 $dtyp = lookup_dumptype("dl3"); 803 is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_DUMP_LIMIT), 804 [ "SAMEHOST-SAMEHOST-SAMEHOST", "SERVER-SERVER-SERVER" ], 805 "same-host and server"); 806} 807 808$testconf->add_dumptype('dl4', [ 809 'dump-limit' => 'same-host server "somehost"', 810]); 811$testconf->write(); 812$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); 813isnt($cfg_result, $CFGERR_OK, 814 "dump-limit do not accept hostname"); 815 816## 817# Try an autolabel with a template and 'any' 818 819$testconf = Installcheck::Config->new(); 820$testconf->add_param('autolabel', '"FOO%%%BAR" any'); 821$testconf->write(); 822 823$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); 824is($cfg_result, $CFGERR_OK, 825 "first exinclude parsing config loaded") 826 or diag_config_errors(); 827SKIP: { 828 skip "error loading config", 1 unless $cfg_result == $CFGERR_OK; 829 is_deeply(getconf($CNF_AUTOLABEL), 830 { template => "FOO%%%BAR", other_config => 1, 831 non_amanda => 1, volume_error => 1, empty => 1 }, 832 "'autolabel \"FOO%%%BAR\" any' represented correctly"); 833} 834 835## 836# Check out where quoting is and is not required. 837 838$testconf = Installcheck::Config->new(); 839 840# make sure an unquoted tapetype is OK 841$testconf->add_param('tapetype', 'TEST-TAPE'); # unquoted (Installcheck::Config uses quoted) 842 843# strings can optionally be quoted 844$testconf->add_param('dumporder', '"STSTST"'); 845 846# enumerations (e.g., taperalgo) must not be quoted; implicitly tested above 847 848# definitions 849$testconf->add_dumptype('"parent"', [ # note quotes 850 'bumpsize' => '10240', 851]); 852$testconf->add_dumptype('child', [ 853 '' => '"parent"', # note quotes 854]); 855$testconf->add_dumptype('child2', [ 856 '' => 'parent', 857]); 858$testconf->write(); 859 860$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); 861is($cfg_result, $CFGERR_OK, 862 "parsed config to test strings vs. identifiers") 863 or diag_config_errors(); 864SKIP: { 865 skip "error loading config", 3 unless $cfg_result == $CFGERR_OK; 866 867 my $dtyp = lookup_dumptype("parent"); 868 ok($dtyp, "found parent"); 869 $dtyp = lookup_dumptype("child"); 870 ok($dtyp, "found child"); 871 is(dumptype_getconf($dtyp, $DUMPTYPE_BUMPSIZE), 10240, 872 "child dumptype correctly inherited bumpsize"); 873} 874 875## 876# Explore a quirk of read_int_or_str parsing. 877 878$testconf = Installcheck::Config->new(); 879$testconf->add_dumptype('mydump-type1', [ 880 'client_port' => '12345', 881]); 882$testconf->add_dumptype('mydump-type2', [ 883 'client_port' => '"newamanda"', 884]); 885$testconf->add_dumptype('mydump-type3', [ 886 'client_port' => '"67890"', 887]); 888$testconf->write(); 889 890$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); 891is($cfg_result, $CFGERR_OK, 892 "read_int_or_str parsing config loaded") 893 or diag_config_errors(); 894SKIP: { 895 skip "error loading config", 6 unless $cfg_result == $CFGERR_OK; 896 897 my $dtyp = lookup_dumptype("mydump-type1"); 898 ok($dtyp, "found mydump-type1"); 899 is(dumptype_getconf($dtyp, $DUMPTYPE_CLIENT_PORT), "12345", 900 "client_port set to 12345"); 901 902 $dtyp = lookup_dumptype("mydump-type2"); 903 ok($dtyp, "found mydump-type1"); 904 is(dumptype_getconf($dtyp, $DUMPTYPE_CLIENT_PORT), "newamanda", 905 "client_port set to \"newamanda\""); 906 907 $dtyp = lookup_dumptype("mydump-type3"); 908 ok($dtyp, "found mydump-type1"); 909 is(dumptype_getconf($dtyp, $DUMPTYPE_CLIENT_PORT), "67890", 910 "client_port set to \"67890\""); 911} 912 913## 914# Check property inheritance 915 916$testconf = Installcheck::Config->new(); 917$testconf->add_application('app1', [ 918 'property' => '"prop1" "val1"' 919]); 920$testconf->add_application('app2', [ 921 'property' => 'append "prop2" "val2"' 922]); 923$testconf->add_application('app3', [ 924 'property' => '"prop3" "val3"' 925]); 926$testconf->add_application('app1a', [ 927 'property' => '"prop4" "val4"', 928 'property' => '"prop1" "val1a"', 929 'app1' => undef 930]); 931$testconf->add_application('app2a', [ 932 'property' => '"prop5" "val5"', 933 'property' => '"prop2" "val2a"', 934 'app2' => undef 935]); 936$testconf->add_application('app3a', [ 937 'property' => '"prop6" "val6"', 938 'app3' => undef, 939 'property' => '"prop7" "val7"' 940]); 941$testconf->add_application('app1b', [ 942 'property' => '"prop4" "val4"', 943 'property' => '"prop1" "val1a"', 944 'app1' => undef, 945 'property' => '"prop1" "val1b"', 946]); 947$testconf->add_application('app2b', [ 948 'property' => '"prop5" "val5"', 949 'property' => '"prop2" "val2a"', 950 'app2' => undef, 951 'property' => 'append "prop2" "val2b"', 952]); 953$testconf->write(); 954 955$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); 956is($cfg_result, $CFGERR_OK, 957 "application properties inheritance") 958 or diag_config_errors(); 959SKIP: { 960 skip "error loading config", 15 unless $cfg_result == $CFGERR_OK; 961 962 my $app = lookup_application("app1a"); 963 ok($app, "found app1a"); 964 is(application_name($app), "app1a", 965 "app1a knows its name"); 966 my $prop = application_getconf($app, $APPLICATION_PROPERTY); 967 is_deeply($prop, { "prop4" => { priority => 0, 968 append => 0, 969 values => [ "val4" ]}, 970 "prop1" => { priority => 0, 971 append => 0, 972 values => [ "val1" ] }}, 973 "PROPERTY parameter of app1a parsed correctly"); 974 975 $app = lookup_application("app2a"); 976 ok($app, "found app2a"); 977 is(application_name($app), "app2a", 978 "app2a knows its name"); 979 $prop = application_getconf($app, $APPLICATION_PROPERTY); 980 is_deeply($prop, { "prop5" => { priority => 0, 981 append => 0, 982 values => [ "val5" ]}, 983 "prop2" => { priority => 0, 984 append => 0, 985 values => [ "val2a", "val2" ] }}, 986 "PROPERTY parameter of app2a parsed correctly"); 987 988 $app = lookup_application("app3a"); 989 ok($app, "found app3a"); 990 is(application_name($app), "app3a", 991 "app3a knows its name"); 992 $prop = application_getconf($app, $APPLICATION_PROPERTY); 993 is_deeply($prop, { "prop3" => { priority => 0, 994 append => 0, 995 values => [ "val3" ]}, 996 "prop6" => { priority => 0, 997 append => 0, 998 values => [ "val6" ] }, 999 "prop7" => { priority => 0, 1000 append => 0, 1001 values => [ "val7" ] }}, 1002 "PROPERTY parameter of app3a parsed correctly"); 1003 1004 $app = lookup_application("app1b"); 1005 ok($app, "found app1b"); 1006 is(application_name($app), "app1b", 1007 "app1b knows its name"); 1008 $prop = application_getconf($app, $APPLICATION_PROPERTY); 1009 is_deeply($prop, { "prop4" => { priority => 0, 1010 append => 0, 1011 values => [ "val4" ]}, 1012 "prop1" => { priority => 0, 1013 append => 0, 1014 values => [ "val1b" ] }}, 1015 "PROPERTY parameter of app1b parsed correctly"); 1016 1017 $app = lookup_application("app2b"); 1018 ok($app, "found app2b"); 1019 is(application_name($app), "app2b", 1020 "app2b knows its name"); 1021 $prop = application_getconf($app, $APPLICATION_PROPERTY); 1022 is_deeply($prop, { "prop5" => { priority => 0, 1023 append => 0, 1024 values => [ "val5" ]}, 1025 "prop2" => { priority => 0, 1026 append => 1, 1027 values => [ "val2a", "val2", "val2b" ] }}, 1028 "PROPERTY parameter of app2b parsed correctly"); 1029} 1030 1031 1032## 1033# Check getconf_byname and getconf_byname_strs 1034 1035$testconf = Installcheck::Config->new(); 1036$testconf->add_param('tapedev', '"thats a funny name"'); 1037$testconf->add_application('app1', [ 1038 'comment' => '"one"', 1039]); 1040$testconf->add_script('scr1', [ 1041 'comment' => '"one"', 1042]); 1043# check old names, too 1044$testconf->add_text(<<EOF); 1045define application-tool "app2" { 1046 comment "two" 1047} 1048EOF 1049$testconf->add_text(<<EOF); 1050define script-tool "scr2" { 1051 comment "two" 1052} 1053EOF 1054$testconf->write(); 1055 1056$cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); 1057is($cfg_result, $CFGERR_OK, 1058 "getconf_byname") 1059 or diag_config_errors(); 1060SKIP: { 1061 skip "error loading config", 7 unless $cfg_result == $CFGERR_OK; 1062 1063 is(getconf_byname("Tapedev"), "thats a funny name", 1064 "getconf_byname for global param"); 1065 is_deeply([ getconf_byname_strs("Tapedev", 1) ], 1066 [ "\"thats a funny name\"" ], 1067 "getconf_byname_strs for global param with quotes"); 1068 is_deeply([ getconf_byname_strs("Tapedev", 0) ], 1069 [ "thats a funny name" ], 1070 "getconf_byname_strs for global param without quotes"); 1071 1072 # test * and *-tool (the old name) 1073 is(getconf_byname("application-tool:app1:comment"), "one", 1074 "getconf_byname for appplication-tool param"); 1075 is(getconf_byname("application:app2:comment"), "two", 1076 "getconf_byname for application param"); 1077 is(getconf_byname("script-tool:scr1:comment"), "one", 1078 "getconf_byname for appplication-tool param"); 1079 is(getconf_byname("script:scr2:comment"), "two", 1080 "getconf_byname for script param"); 1081} 1082 1083my @boolean_vals = ( 1084 {'val' => '1', 'expected' => 1}, 1085 {'val' => '0', 'expected' => 0}, 1086 {'val' => 't', 'expected' => 1}, 1087 {'val' => 'true', 'expected' => 1}, 1088 {'val' => 'f', 'expected' => 0}, 1089 {'val' => 'false', 'expected' => 0}, 1090 {'val' => 'y', 'expected' => 1}, 1091 {'val' => 'yes', 'expected' => 1}, 1092 {'val' => 'n', 'expected' => 0}, 1093 {'val' => 'no', 'expected' => 0}, 1094 {'val' => 'on', 'expected' => 1}, 1095 {'val' => 'off', 'expected' => 0}, 1096 {'val' => 'oFf', 'expected' => 0}, 1097 {'val' => 'foo', 'expected' => undef}, 1098 ); 1099 1100for my $bv (@boolean_vals) { 1101 is(string_to_boolean($bv->{'val'}), $bv->{'expected'}, 1102 "string_to_boolean('$bv->{'val'}') is right"); 1103} 1104 1105my @prop_names = ( 1106 {'val' => '', 'expected' => ''}, 1107 {'val' => 'prop-name', 'expected' => 'prop-name'}, 1108 {'val' => 'PRoP-NaME', 'expected' => 'prop-name'}, 1109 {'val' => 'prop_name', 'expected' => 'prop-name'}, 1110 {'val' => 'FaNCy_ProP', 'expected' => 'fancy-prop'}, 1111 {'val' => '_under_', 'expected' => '-under-'}, 1112 {'val' => '-dash-', 'expected' => '-dash-'}, 1113 {'val' => '-', 'expected' => '-'}, 1114 {'val' => '_', 'expected' => '-'}, 1115 ); 1116 1117for my $pn (@prop_names) { 1118 is(amandaify_property_name($pn->{'val'}), $pn->{'expected'}, 1119 "amandaify_property_name('$pn->{'val'}') is right"); 1120} 1121 1122$testconf = Installcheck::Config->new(); 1123$testconf->add_param('property', '"PrOP_nAme" "VALUE"'); 1124$testconf->write(); 1125config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); 1126my $properties = getconf($CNF_PROPERTY); 1127 1128@prop_names = ( 1129 {'val' => 'prop-name'}, 1130 {'val' => 'PRoP-NaME'}, 1131 {'val' => 'prop_name'}, 1132 {'val' => 'PROP_NAME'}, 1133 {'val' => 'PRoP-NaME'}, 1134 {'val' => 'prop_name'}, 1135 ); 1136 1137for my $pn (@prop_names) { 1138 is_deeply($properties->{$pn->{'val'}}->{values}, [ "VALUE" ], "property $pn->{'val'}"); 1139} 1140 1141$testconf = Installcheck::Config->new(); 1142$testconf->add_client_config_param('amdump-server', '"amdump.localhost"'); 1143$testconf->add_client_config_param('index-server', '"index.localhost"'); 1144$testconf->add_client_config_param('tape-server', '"tape.localhost"'); 1145$testconf->write(); 1146config_init($CONFIG_INIT_CLIENT | $CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"); 1147my $amdump_server = getconf($CNF_AMDUMP_SERVER); 1148is ($amdump_server, "amdump.localhost", "amdump-server is \"amdump.localhost\""); 1149my $index_server = getconf($CNF_INDEX_SERVER); 1150is ($index_server, "index.localhost", "index-server is \"index.localhost\""); 1151my $tape_server = getconf($CNF_TAPE_SERVER); 1152is ($tape_server, "tape.localhost", "amdump is \"tape.localhost\""); 1153 1154