Merge tag 'upstream/3.3.3'
[debian/amanda] / installcheck / Amanda_Config.pl
1 # Copyright (c) 2007-2012 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
20 use Test::More tests => 224;
21 use strict;
22 use warnings;
23 use Data::Dumper;
24
25 use lib "@amperldir@";
26 use Installcheck::Config;
27 use Amanda::Paths;
28 use Amanda::Tests;
29 use Amanda::Config qw( :init :getconf string_to_boolean amandaify_property_name );
30 use Amanda::Debug;
31
32 my $testconf;
33 my $config_overrides;
34
35 Amanda::Debug::dbopen("installcheck");
36 Installcheck::log_test_output();
37
38 # utility function
39
40 sub 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
50 is(config_init(0, ''), $CFGERR_OK,
51     "Initialize with no configuration")
52     or diag_config_errors();
53
54 config_uninit();
55 $config_overrides = new_config_overrides(1);
56 add_config_override($config_overrides, "tapedev", "null:TEST");
57 set_config_overrides($config_overrides);
58
59 is(config_init(0, undef), $CFGERR_OK,
60     "Initialize with no configuration, passing a NULL config name")
61     or diag_config_errors();
62
63 is(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
89 is(config_init($CONFIG_INIT_EXPLICIT_NAME, "NO-SUCH-CONFIGURATION"), $CFGERR_ERRORS,
90     "Non-existent config generates an error");
91
92 is(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
107 my $cfg_result = config_init($CONFIG_INIT_CLIENT, undef);
108 is($cfg_result, $CFGERR_OK,
109     "Load test client configuration")
110     or diag_config_errors();
111
112 is_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
128 my $int64_num = '171801575472'; # 0xA000B000C000 / 1024
129 my $size_t_num;
130 if (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" "backup" "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');
247 if (!is($cfg_result, $CFGERR_OK,
248     "Load test configuration")) {
249     diag_config_errors();
250     die "aborting after config errors";
251 }
252
253 is(Amanda::Config::get_config_name(), "TESTCONF",
254     "config_name set");
255 is(Amanda::Config::get_config_dir(), "$CONFIG_DIR/TESTCONF",
256     "config_dir set");
257 is(Amanda::Config::get_config_filename(),
258     "$CONFIG_DIR/TESTCONF/amanda.conf",
259     "config_filename set");
260
261 is(getconf($CNF_RESERVE), 75,
262     "integer global confparm");
263 is(getconf($CNF_BUMPSIZE), $int64_num+0,
264     "int64 global confparm");
265 is(getconf($CNF_TAPEDEV), "/dev/foo",
266     "string global confparm");
267 is(getconf($CNF_DEVICE_OUTPUT_BUFFER_SIZE), $size_t_num+0,
268     "size global confparm");
269 ok(getconf($CNF_AUTOFLUSH),
270     "boolean global confparm");
271 is(getconf($CNF_USETIMESTAMPS), 0,
272     "boolean global confparm, passing an integer (0)");
273 is(getconf($CNF_TAPERALGO), $Amanda::Config::ALGO_LAST,
274     "taperalgo global confparam");
275 is_deeply([getconf($CNF_RESERVED_UDP_PORT)], [100,200],
276     "intrange global confparm");
277 is(getconf($CNF_DISPLAYUNIT), "M",
278     "displayunit is correctly uppercased");
279 is_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");
284 is_deeply(getconf($CNF_AUTOLABEL),
285         { template => undef, other_config => '',
286           non_amanda => 1, volume_error => '', empty => 1 },
287         "'autolabel non-amanda empty' represented correctly");
288 ok(getconf_seen($CNF_TAPEDEV),
289     "'tapedev' parm was seen");
290 ok(!getconf_seen($CNF_CHANGERFILE),
291     "'changerfile' parm was not seen");
292
293 is(Amanda::Config::getconf_unit_divisor(), 1024,
294     "correct unit divisor (from displayunit -> KB)");
295 ok($Amanda::Config::debug_auth,
296     "debug_auth setting reflected in global variable");
297 ok(!$Amanda::Config::debug_amandad,
298     "debug_amandad defaults to false");
299
300 my $ttyp = lookup_tapetype("mytapetype");
301 ok($ttyp, "found mytapetype");
302 is(tapetype_getconf($ttyp, $TAPETYPE_COMMENT), 'mine',
303     "tapetype comment");
304 is(tapetype_getconf($ttyp, $TAPETYPE_LENGTH), 128 * 1024,
305     "tapetype comment");
306
307 ok(tapetype_seen($ttyp, $TAPETYPE_COMMENT),
308     "tapetype comment was seen");
309 ok(!tapetype_seen($ttyp, $TAPETYPE_LBL_TEMPL),
310     "tapetype lbl_templ was not seen");
311
312 is(tapetype_getconf($ttyp, $TAPETYPE_PART_SIZE), 100*1024,
313     "tapetype part_size");
314 is(tapetype_getconf($ttyp, $TAPETYPE_PART_CACHE_TYPE), $PART_CACHE_TYPE_DISK,
315     "tapetype part_cache_type");
316 is(tapetype_getconf($ttyp, $TAPETYPE_PART_CACHE_DIR), "/usr/bin",
317     "tapetype part_cache_dir");
318 is(tapetype_getconf($ttyp, $TAPETYPE_PART_CACHE_MAX_SIZE), 50*1024,
319     "tapetype part_cache_max_size");
320
321 is_deeply([ sort(+getconf_list("tapetype")) ],
322           [ sort("mytapetype", "TEST-TAPE") ],
323     "getconf_list lists all tapetypes");
324
325 my $dtyp = lookup_dumptype("mydump-type");
326 ok($dtyp, "found mydump-type");
327 is(dumptype_getconf($dtyp, $DUMPTYPE_COMMENT), 'mine',
328     "dumptype string");
329 is(dumptype_getconf($dtyp, $DUMPTYPE_PRIORITY), 2,
330     "dumptype priority");
331 is(dumptype_getconf($dtyp, $DUMPTYPE_BUMPSIZE), $int64_num+0,
332     "dumptype size");
333 is(dumptype_getconf($dtyp, $DUMPTYPE_BUMPMULT), 1.75,
334     "dumptype real");
335 is(dumptype_getconf($dtyp, $DUMPTYPE_STARTTIME), 1829,
336     "dumptype time");
337 is(dumptype_getconf($dtyp, $DUMPTYPE_HOLDINGDISK), $HOLD_REQUIRED,
338     "dumptype holdingdisk");
339 is(dumptype_getconf($dtyp, $DUMPTYPE_COMPRESS), $COMP_BEST,
340     "dumptype compress");
341 is(dumptype_getconf($dtyp, $DUMPTYPE_ENCRYPT), $ENCRYPT_SERV_CUST,
342     "dumptype encrypt");
343 is(dumptype_getconf($dtyp, $DUMPTYPE_STRATEGY), $DS_INCRONLY,
344     "dumptype strategy");
345 is_deeply([dumptype_getconf($dtyp, $DUMPTYPE_COMPRATE)], [0.25, 0.75],
346     "dumptype comprate");
347 is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_INCLUDE),
348     { 'file' => [ 'rhyme' ],
349       'list' => [ 'bing', 'ting', 'string', 'fling' ],
350       'optional' => 1 },
351     "dumptype include list");
352 is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_EXCLUDE),
353     { 'file' => [ 'foolist' ],
354       'list' => [ 'foo', 'bar', 'true', 'star' ],
355       'optional' => 0 },
356     "dumptype exclude list");
357 is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_ESTIMATELIST),
358           [ $ES_SERVER, $ES_CALCSIZE, $ES_CLIENT ],
359     "dumptype estimate list");
360 is_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");
365 is_deeply(dumptype_getconf($dtyp, $DUMPTYPE_RECOVERY_LIMIT),
366     [],
367     "dumptype recovery limit with no limit specified => empty");
368
369 ok(dumptype_seen($dtyp, $DUMPTYPE_EXCLUDE),
370     "'exclude' parm was seen");
371 ok(!dumptype_seen($dtyp, $DUMPTYPE_RECORD),
372     "'record' parm was not seen");
373
374 is_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)");
382 is(dumptype_getconf($dtyp, $DUMPTYPE_ALLOW_SPLIT), 0,
383     "dumptype allow_split");
384
385 my $iface = lookup_interface("ethernet");
386 ok($iface, "found ethernet");
387 is(interface_name($iface), "ethernet",
388     "interface knows its name");
389 is(interface_getconf($iface, $INTER_COMMENT), 'mine',
390     "interface comment");
391 is(interface_getconf($iface, $INTER_MAXUSAGE), 100,
392     "interface maxusage");
393
394 $iface = lookup_interface("nic");
395 ok($iface, "found nic");
396 ok(interface_seen($iface, $INTER_COMMENT),
397     "seen set for parameters that appeared");
398 ok(!interface_seen($iface, $INTER_MAXUSAGE),
399     "seen not set for parameters that did not appear");
400
401 is_deeply([ sort(+getconf_list("interface")) ],
402           [ sort('ethernet', 'nic', 'default') ],
403     "getconf_list lists all interfaces (in any order)");
404
405 skip "error loading config", 13 unless $cfg_result == $CFGERR_OK;
406 my $hdisk = lookup_holdingdisk("hd1");
407 ok($hdisk, "found hd1");
408 is(holdingdisk_name($hdisk), "hd1",
409     "hd1 knows its name");
410 is(holdingdisk_getconf($hdisk, $HOLDING_COMMENT), 'mine',
411     "holdingdisk comment");
412 is(holdingdisk_getconf($hdisk, $HOLDING_DISKDIR), '/mnt/hd1',
413     "holdingdisk diskdir (directory)");
414 is(holdingdisk_getconf($hdisk, $HOLDING_DISKSIZE), 100*1024,
415     "holdingdisk disksize (use)");
416 is(holdingdisk_getconf($hdisk, $HOLDING_CHUNKSIZE), 1024,
417     "holdingdisk chunksize");
418
419 $hdisk = lookup_holdingdisk("hd2");
420 ok($hdisk, "found hd2");
421 ok(holdingdisk_seen($hdisk, $HOLDING_COMMENT),
422     "seen set for parameters that appeared");
423 ok(!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
428 my $hdisklist = getconf($CNF_HOLDINGDISK);
429 my $first_disk = @$hdisklist[0];
430 $hdisk = lookup_holdingdisk($first_disk);
431 like(holdingdisk_name($hdisk), qr/hd[12]/,
432     "one disk is first in list of holdingdisks");
433 $hdisk = lookup_holdingdisk(@$hdisklist[1]);
434 like(holdingdisk_name($hdisk), qr/hd[12]/,
435     "another is second in list of holdingdisks");
436 ok($#$hdisklist == 1,
437     "no third holding disk");
438
439 is_deeply([ sort(+getconf_list("holdingdisk")) ],
440           [ sort('hd1', 'hd2') ],
441     "getconf_list lists all holdingdisks (in any order)");
442
443 skip "error loading config", 5 unless $cfg_result == $CFGERR_OK;
444 my $app = lookup_application("my_app");
445 ok($app, "found my_app");
446 is(application_name($app), "my_app",
447     "my_app knows its name");
448 is(application_getconf($app, $APPLICATION_COMMENT), 'my_app_comment',
449     "application comment");
450 is(application_getconf($app, $APPLICATION_PLUGIN), 'amgtar',
451     "application plugin (amgtar)");
452
453 is_deeply([ sort(+getconf_list("application-tool")) ],
454           [ sort("my_app") ],
455     "getconf_list lists all applications");
456 # test backward compatibility
457 is_deeply([ sort(+getconf_list("application")) ],
458           [ sort("my_app") ],
459     "getconf_list works for 'application-tool', too");
460
461 my $sc = lookup_pp_script("my_script");
462 ok($sc, "found my_script");
463 is(pp_script_name($sc), "my_script",
464     "my_script knows its name");
465 is(pp_script_getconf($sc, $PP_SCRIPT_COMMENT), 'my_script_comment',
466     "script comment");
467 is(pp_script_getconf($sc, $PP_SCRIPT_PLUGIN), 'script-email',
468     "script plugin (script-email)");
469 is(pp_script_getconf($sc, $PP_SCRIPT_EXECUTE_WHERE), $ES_CLIENT,
470     "script execute_where (client)");
471 is(pp_script_getconf($sc, $PP_SCRIPT_EXECUTE_ON),
472     $EXECUTE_ON_PRE_HOST_BACKUP|$EXECUTE_ON_POST_HOST_BACKUP,
473     "script execute_on");
474
475 is_deeply([ sort(+getconf_list("script")) ],
476           [ sort("my_script") ],
477     "getconf_list lists all script");
478
479 is_deeply([ sort(+getconf_list("script-tool")) ],
480           [ sort("my_script") ],
481     "getconf_list works for 'script-tool', too");
482
483 my $dc = lookup_device_config("my_device");
484 ok($dc, "found my_device");
485 is(device_config_name($dc), "my_device",
486     "my_device knows its name");
487 is(device_config_getconf($dc, $DEVICE_CONFIG_COMMENT), 'my device is mine, not yours',
488     "device comment");
489 is(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?
492 is_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
497 is_deeply([ sort(+getconf_list("device")) ],
498           [ sort("my_device") ],
499     "getconf_list lists all devices");
500
501 skip "error loading config", 7 unless $cfg_result == $CFGERR_OK;
502 $dc = lookup_changer_config("my_changer");
503 ok($dc, "found my_changer");
504 is(changer_config_name($dc), "my_changer",
505     "my_changer knows its name");
506 is(changer_config_getconf($dc, $CHANGER_CONFIG_COMMENT), 'my changer is mine, not yours',
507     "changer comment");
508 is(changer_config_getconf($dc, $CHANGER_CONFIG_CHANGERDEV), '/dev/sg0',
509     "changer tapedev");
510 is_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
518 is_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
526 is_deeply([ sort(+getconf_list("changer")) ],
527           [ sort("my_changer") ],
528     "getconf_list lists all changers");
529
530 $dc = lookup_interactivity("my_interactivity");
531 ok($dc, "found my_interactivity");
532 is(interactivity_name($dc), "my_interactivity",
533     "my_interactivity knows its name");
534 is(interactivity_getconf($dc, $INTERACTIVITY_COMMENT), 'my interactivity is mine, not yours',
535     "interactivity comment");
536 is(interactivity_getconf($dc, $INTERACTIVITY_PLUGIN), 'MY-interactivity',
537     "interactivity plugin");
538 is_deeply(interactivity_getconf($dc, $INTERACTIVITY_PROPERTY),
539     { 'testprop' => {
540             'priority' => 0,
541             'values' => [ 'testval' ],
542             'append' => 0,
543         }
544     }, "interactivity properties represented correctly");
545
546 is_deeply([ sort(+getconf_list("interactivity")) ],
547           [ sort("my_interactivity") ],
548     "getconf_list lists all interactivity");
549
550 $dc = lookup_taperscan("my_taperscan");
551 ok($dc, "found my_taperscan");
552 is(taperscan_name($dc), "my_taperscan",
553     "my_taperscan knows its name");
554 is(taperscan_getconf($dc, $TAPERSCAN_COMMENT), 'my taperscan is mine, not yours',
555     "taperscan comment");
556 is(taperscan_getconf($dc, $TAPERSCAN_PLUGIN), 'MY-taperscan',
557     "taperscan plugin");
558 is_deeply(taperscan_getconf($dc, $TAPERSCAN_PROPERTY),
559     { 'testprop' => {
560             'priority' => 0,
561             'values' => [ 'testval' ],
562             'append' => 0,
563         }
564     }, "taperscan properties represented correctly");
565
566 is_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
574 config_uninit();
575 $config_overrides = new_config_overrides(1); # note estimate is too small
576 add_config_override($config_overrides, "tapedev", "null:TEST");
577 add_config_override($config_overrides, "tpchanger", "chg-test");
578 add_config_override_opt($config_overrides, "org=KAOS");
579 set_config_overrides($config_overrides);
580 config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF');
581
582 is(getconf($CNF_TAPEDEV), "null:TEST",
583     "config overwrites work with real config");
584 is(getconf($CNF_ORG), "KAOS",
585     "add_config_override_opt parsed correctly");
586
587 # introduce an error
588 config_uninit();
589 $config_overrides = new_config_overrides(1);
590 add_config_override($config_overrides, "bogusparam", "foo");
591 set_config_overrides($config_overrides);
592 config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF');
593
594 my ($error_level, @errors) = Amanda::Config::config_errors();
595 is($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
603 my $pid = open(my $kid, "-|");
604 die "Can't fork: $!" unless defined($pid);
605 if (!$pid) {
606     Amanda::Config::dump_configuration(1, 0);
607     exit 1;
608 }
609 my $dump_first_line = <$kid>;
610 my $dump = join'', $dump_first_line, <$kid>;
611 close $kid;
612 waitpid $pid, 0;
613
614 my $fn = Amanda::Config::get_config_filename();
615 my $dump_filename = $dump_first_line;
616 chomp $dump_filename;
617 $dump_filename =~ s/^# AMANDA CONFIGURATION FROM FILE "//g;
618 $dump_filename =~ s/":$//g;
619 is($dump_filename, $fn, 
620     "config filename is included correctly");
621
622 like($dump, qr/DEVICE-PROPERTY\s+"foo" "bar"\n/i,
623     "DEVICE-PROPERTY appears in dump output");
624
625 like($dump, qr/AMRECOVER-CHECK-LABEL\s+(yes|no)/i,
626     "AMRECOVER-CHECK-LABEL has a trailing space");
627
628 like($dump, qr/AMRECOVER-CHECK-LABEL\s+(yes|no)/i,
629     "AMRECOVER-CHECK-LABEL has a trailing space");
630
631 like($dump, qr/EXCLUDE\s+LIST "foo" "bar" "true" "star"/i,
632     "EXCLUDE LIST is in the dump");
633 like($dump, qr/EXCLUDE\s+FILE "foolist"/i,
634     "EXCLUDE FILE is in the dump");
635 like($dump, qr/INCLUDE\s+LIST OPTIONAL "bing" "ting" "string" "fling"/i,
636     "INCLUDE LIST is in the dump");
637 like($dump, qr/INCLUDE\s+FILE OPTIONAL "rhyme"/i,
638     "INCLUDE FILE is in the dump");
639 like($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");
661 is($cfg_result, $CFGERR_OK, 
662     "parsing nested config loaded")
663     or diag_config_errors();
664 SKIP: {
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");
705 is($cfg_result, $CFGERR_OK, 
706     "first exinclude parsing config loaded")
707     or diag_config_errors();
708 SKIP: {
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");
737 is($cfg_result, $CFGERR_OK,
738     "recovery-limit config loaded")
739     or diag_config_errors();
740 SKIP: {
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");
785 is($cfg_result, $CFGERR_OK,
786     "dump-limit config loaded")
787     or diag_config_errors();
788 SKIP: {
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");
813 isnt($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");
824 is($cfg_result, $CFGERR_OK, 
825     "first exinclude parsing config loaded")
826     or diag_config_errors();
827 SKIP: {
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");
861 is($cfg_result, $CFGERR_OK,
862     "parsed config to test strings vs. identifiers")
863     or diag_config_errors();
864 SKIP: {
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");
891 is($cfg_result, $CFGERR_OK, 
892     "read_int_or_str parsing config loaded")
893     or diag_config_errors();
894 SKIP: {
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");
956 is($cfg_result, $CFGERR_OK, 
957     "application properties inheritance")
958     or diag_config_errors();
959 SKIP: {
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);
1045 define application-tool "app2" {
1046     comment "two"
1047 }
1048 EOF
1049 $testconf->add_text(<<EOF);
1050 define script-tool "scr2" {
1051     comment "two"
1052 }
1053 EOF
1054 $testconf->write();
1055
1056 $cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF");
1057 is($cfg_result, $CFGERR_OK,
1058     "getconf_byname")
1059     or diag_config_errors();
1060 SKIP: {
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
1083 my @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
1100 for my $bv (@boolean_vals) {
1101     is(string_to_boolean($bv->{'val'}), $bv->{'expected'},
1102         "string_to_boolean('$bv->{'val'}') is right");
1103 }
1104
1105 my @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
1117 for 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();
1125 config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF");
1126 my $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
1137 for 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();
1146 config_init($CONFIG_INIT_CLIENT | $CONFIG_INIT_EXPLICIT_NAME, "TESTCONF");
1147 my $amdump_server = getconf($CNF_AMDUMP_SERVER);
1148 is ($amdump_server, "amdump.localhost", "amdump-server is \"amdump.localhost\"");
1149 my $index_server = getconf($CNF_INDEX_SERVER);
1150 is ($index_server, "index.localhost", "index-server is \"index.localhost\"");
1151 my $tape_server = getconf($CNF_TAPE_SERVER);
1152 is ($tape_server, "tape.localhost", "amdump is \"tape.localhost\"");
1153