Imported Upstream version 3.3.3
[debian/amanda] / installcheck / Amanda_Logfile.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 => 39;
21 use File::Path;
22 use strict;
23 use warnings;
24
25 use lib "@amperldir@";
26 use Installcheck;
27 use Installcheck::Config;
28 use Data::Dumper;
29 use Amanda::Paths;
30 use Amanda::Tapelist;
31 use Amanda::Cmdline;
32 use Amanda::Util;
33 use Amanda::Debug qw( :logging );
34 use Amanda::Logfile qw(:logtype_t :program_t open_logfile get_logline
35                 close_logfile log_add $amanda_log_trace_log );
36 use Amanda::Config qw( :init :getconf config_dir_relative );
37
38 Amanda::Debug::dbopen("installcheck");
39
40 my $log_filename = "$Installcheck::TMP/Amanda_Logfile_test.log";
41
42 # write a logfile and return the filename
43 sub write_logfile {
44     my ($contents) = @_;
45
46     if (!-e $Installcheck::TMP) {
47         mkpath($Installcheck::TMP);
48     }
49
50     open my $logfile, ">", $log_filename or die("Could not create temporary log file '$log_filename': $!");
51     print $logfile $contents;
52     close $logfile;
53
54     return $log_filename;
55 }
56
57 ####
58 ## RAW LOGFILE ACCESS
59
60 my $logfile;
61 my $logdata;
62
63 ##
64 # Test out the constant functions
65
66 is(logtype_t_to_string($L_MARKER), "L_MARKER", "logtype_t_to_string works");
67 is(program_t_to_string($P_DRIVER), "P_DRIVER", "program_t_to_string works");
68
69 ##
70 # Regression test for previously missing program types
71 is( program_t_to_string($P_AMDUMP),
72     "P_AMDUMP", "program type for amdump defined" );
73 is( program_t_to_string($P_AMIDXTAPED),
74     "P_AMIDXTAPED", "program type for amidxtaped defined" );
75 is( program_t_to_string($P_AMFETCHDUMP),
76     "P_AMFETCHDUMP", "program type for amfetchdump defined" );
77 is( program_t_to_string($P_AMCHECKDUMP),
78     "P_AMCHECKDUMP", "program type for amcheckdump defined" );
79
80 ##
81 # Test a simple logfile
82
83 $logdata = <<END;
84 START planner date 20071026183200
85 END
86
87 $logfile = open_logfile(write_logfile($logdata));
88 ok($logfile, "can open a simple logfile");
89 is_deeply([ get_logline($logfile) ],
90           [ $L_START, $P_PLANNER, "date 20071026183200" ],
91           "reads START line correctly");
92 ok(!get_logline($logfile), "no second line");
93 close_logfile($logfile);
94
95 ##
96 # Test continuation lines
97
98 $logdata = <<END;
99 INFO chunker line1
100   line2
101 END
102
103 $logfile = open_logfile(write_logfile($logdata));
104 ok($logfile, "can open a logfile containing continuation lines");
105 is_deeply([ get_logline($logfile) ],
106           [ $L_INFO, $P_CHUNKER, "line1" ],
107           "can read INFO line");
108 is_deeply([ get_logline($logfile) ],
109           [ $L_CONT, $P_CHUNKER, "line2" ],
110           "can read continuation line");
111 ok(!get_logline($logfile), "no third line");
112 close_logfile($logfile);
113
114 ##
115 # Test skipping blank lines
116
117 # (retain the two blank lines in the following:)
118 $logdata = <<END;
119
120 STATS taper foo
121
122 END
123
124 $logfile = open_logfile(write_logfile($logdata));
125 ok($logfile, "can open a logfile containing blank lines");
126 is_deeply([ get_logline($logfile) ],
127           [ $L_STATS, $P_TAPER, "foo" ],
128           "reads non-blank line correctly");
129 ok(!get_logline($logfile), "no second line");
130 close_logfile($logfile);
131
132 ##
133 # Test BOGUS values and short lines
134
135 $logdata = <<END;
136 SOMETHINGWEIRD somerandomprog bar
137 MARKER amflush
138 MARKER amflush put something in curstr
139 PART
140 END
141
142 $logfile = open_logfile(write_logfile($logdata));
143 ok($logfile, "can open a logfile containing bogus entries");
144 is_deeply([ get_logline($logfile) ],
145           [ $L_BOGUS, $P_UNKNOWN, "bar" ],
146           "can read line with bogus program and logtype");
147 is_deeply([ get_logline($logfile) ],
148           [ $L_MARKER, $P_AMFLUSH, "" ],
149           "can read line with an empty string");
150 ok(get_logline($logfile), "can read third line (to fill in curstr with some text)");
151 is_deeply([ get_logline($logfile) ],
152           [ $L_PART, $P_UNKNOWN, "" ],
153           "can read a one-word line, with P_UNKNOWN");
154 ok(!get_logline($logfile), "no next line");
155 close_logfile($logfile);
156
157 ## HIGHER-LEVEL FUNCTIONS
158
159 # a utility function for is_deeply checks, below.  Converts a hash to
160 # an array, for more succinct comparisons
161 sub res2arr {
162     my ($res) = @_;
163     return [
164         $res->{'timestamp'},
165         $res->{'hostname'},
166         $res->{'diskname'},
167         "$res->{'level'}",
168         $res->{'label'},
169         "$res->{'filenum'}",
170         $res->{'status'},
171         $res->{'dump_status'},
172         $res->{'message'},
173         "$res->{'partnum'}",
174         "$res->{'totalparts'}"
175     ];
176 }
177
178 # set up a basic config
179 my $testconf = Installcheck::Config->new();
180 $testconf->add_param("tapecycle", "20");
181 $testconf->write();
182
183 # load the config
184 config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF") == $CFGERR_OK
185     or die("Could not load config");
186 my $tapelist = config_dir_relative("tapelist");
187 my $logdir = $testconf->{'logdir'};
188
189 # test log_add
190 {
191     my $filename = "$logdir/log";
192
193     -f "$filename" and unlink("$filename");
194     log_add($L_INFO, "This is my info");
195     log_add($L_START, "blah blah blah date 20300405060708 blah blah");
196
197     open(my $fh, "<", $filename) or die("open $filename: $!");
198     my $logdata = do { local $/; <$fh> };
199     close($fh);
200
201     like($logdata, qr/^INFO Amanda_Logfile This is my info/, "log_add works");
202
203     is(Amanda::Logfile::get_current_log_timestamp(), "20300405060708",
204         "get_current_log_timestamp finds a timestamp");
205
206     Amanda::Logfile::log_rename("20300405060708");
207
208     ok(! -f $filename, "after log_rename, /log is gone");
209     ok(-f "$filename.20300405060708.0", "..and log.20300405060708.0 exists");
210 }
211
212 # set up and read the tapelist (we don't use Amanda::Tapelist to write this,
213 # in case it's broken)
214 open my $tlf, ">", $tapelist or die("Could not write tapelist");
215 print $tlf "20071111010002 TESTCONF006 reuse\n";
216 print $tlf "20071110010002 TESTCONF005 reuse\n";
217 print $tlf "20071109010002 TESTCONF004 reuse\n";
218 print $tlf "20071109010002 TESTCONF003 reuse\n";
219 print $tlf "20071109010002 TESTCONF002 reuse\n";
220 print $tlf "20071108010001 TESTCONF001 reuse\n";
221 close $tlf;
222 Amanda::Tapelist->new($tapelist);
223
224 # set up a number of logfiles in logdir.
225 my $logf;
226
227 # (an old log file that should be ignored)
228 open $logf, ">", "$logdir/log.20071106010002.0" or die("Could not write logfile");
229 print $logf "START taper datestamp 20071107010002 label TESTCONF017 tape 1\n";
230 close $logf;
231
232 # (a logfile with two tapes)
233 open $logf, ">", "$logdir/log.20071106010002.0" or die("Could not write logfile");
234 print $logf "START taper datestamp 20071106010002 label TESTCONF018 tape 1\n";
235 print $logf "START taper datestamp 20071106010002 label TESTCONF019 tape 2\n";
236 close $logf;
237
238 open $logf, ">", "$logdir/log.20071108010001.0" or die("Could not write logfile");
239 print $logf "START taper datestamp 20071108010001 label TESTCONF001 tape 1\n";
240 close $logf;
241
242 # a logfile with some detail, to run search_logfile against
243 open $logf, ">", "$logdir/log.20071109010002.0" or die("Could not write logfile");
244 print $logf <<EOF;
245 START taper datestamp 20071109010002 label TESTCONF002 tape 1
246 PART taper TESTCONF002 1 clihost /usr 20071109010002 1 0 [regular single part PART]
247 DONE taper clihost /usr 20071109010002 1 0 [regular single part DONE]
248 PART taper TESTCONF002 2 clihost "/my documents" 20071109010002 1 0 [diskname quoting]
249 DONE taper clihost "/my documents" 20071109010002 1 0 [diskname quoting]
250 PART taper TESTCONF002 3 thatbox /var 1 [regular 'old style' PART]
251 DONE taper thatbox /var 1 [regular 'old style' DONE]
252 PART taper TESTCONF002 4 clihost /home 20071109010002 1/5 0 [multi-part dump]
253 PART taper TESTCONF002 5 clihost /home 20071109010002 2/5 0 [multi-part dump]
254 PART taper TESTCONF002 6 clihost /home 20071109010002 3/5 0 [multi-part dump]
255 PART taper TESTCONF002 7 clihost /home 20071109010002 4/5 0 [multi-part dump]
256 PART taper TESTCONF002 8 clihost /home 20071109010002 5/5 0 [multi-part dump]
257 DONE taper clihost /home 20071109010002 5 0 [multi-part dump]
258 PART taper TESTCONF002 9 thatbox /u_lose 20071109010002 1/4 2 [multi-part failure]
259 PART taper TESTCONF002 10 thatbox /u_lose 20071109010002 2/4 2 [multi-part failure]
260 PARTPARTIAL taper TESTCONF002 11 thatbox /u_lose 20071109010002  3/4 2 [multi-part retry]
261 START taper datestamp 20071109010002 label TESTCONF003 tape 1
262 PART taper TESTCONF003 1 thatbox /u_lose 20071109010002 3/4 2 [multi-part failure]
263 FAIL taper thatbox /u_lose 20071109010002 2 error "Oh no!"
264 PART taper TESTCONF003 2 thatbox /u_win 20071109010002 1/4 3 [multi-part retry]
265 PART taper TESTCONF003 3 thatbox /u_win 20071109010002 2/4 3 [multi-part retry]
266 PARTPARTIAL taper TESTCONF003 4 thatbox /u_win 20071109010002  3/4 3 [multi-part retry]
267 START taper datestamp 20071109010002 label TESTCONF004 tape 1
268 PART taper TESTCONF004 1 thatbox /u_win 20071109010002 3/4 3 [multi-part retry]
269 PART taper TESTCONF004 2 thatbox /u_win 20071109010002 4/4 3 [multi-part retry]
270 DONE taper thatbox /u_win 20071109010002 4 3 [multi-part retry]
271 EOF
272 close $logf;
273
274 # "old-style amflush log"
275 open $logf, ">", "$logdir/log.20071110010002.amflush" or die("Could not write logfile");
276 print $logf "START taper datestamp 20071110010002 label TESTCONF005 tape 1\n";
277 close $logf;
278
279 # "old-style main log"
280 open $logf, ">", "$logdir/log.20071111010002" or die("Could not write logfile");
281 print $logf "START taper datestamp 20071111010002 label TESTCONF006 tape 1\n";
282 close $logf;
283
284 is_deeply([ Amanda::Logfile::find_log() ],
285           [ "log.20071111010002", "log.20071110010002.amflush",
286             "log.20071109010002.0", "log.20071108010001.0" ],
287           "find_log returns correct logfiles in the correct order");
288
289 my @results;
290 my @results_arr;
291
292 @results = Amanda::Logfile::search_logfile(undef, "20071109010002",
293                                            "$logdir/log.20071109010002.0", 1);
294 is($#results+1, 17, "search_logfile returned 17 results");
295
296 # sort by filenum so we can compare each to what it should be
297 @results = sort { $a->{'label'} cmp $b->{'label'} ||
298                   $a->{'filenum'} <=> $b->{'filenum'} } @results;
299
300 # and convert the hashes to arrays for easy comparison
301 @results_arr = map { res2arr($_) } @results;
302 is_deeply(\@results_arr,
303         [
304           [ '20071109010002', 'clihost', '/usr',            0, 'TESTCONF002', 1,  'OK',       'OK',   '',         1, 1 ],
305           [ '20071109010002', 'clihost', '/my documents',   0, 'TESTCONF002', 2,  'OK',       'OK',   '',         1, 1 ],
306           [ '20071109010002', 'thatbox', '/var',            1, 'TESTCONF002', 3,  'OK',       'OK',   '',         1, 1 ],
307           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 4,  'OK',       'OK',   '',         1, 5 ],
308           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 5,  'OK',       'OK',   '',         2, 5 ],
309           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 6,  'OK',       'OK',   '',         3, 5 ],
310           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 7,  'OK',       'OK',   '',         4, 5 ],
311           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 8,  'OK',       'OK',   '',         5, 5 ],
312           [ '20071109010002', 'thatbox', '/u_lose',         2, 'TESTCONF002', 9,  'OK',       'FAIL', '"Oh no!"', 1, 4 ],
313           [ '20071109010002', 'thatbox', '/u_lose',         2, 'TESTCONF002', 10, 'OK',       'FAIL', '"Oh no!"', 2, 4 ],
314           [ '20071109010002', 'thatbox', '/u_lose',         2, 'TESTCONF002', 11, 'PARTIAL',  'FAIL', '"Oh no!"', 3, 4 ],
315           [ '20071109010002', 'thatbox', '/u_lose',         2, 'TESTCONF003', 1,  'OK',       'FAIL', '"Oh no!"', 3, 4 ],
316           [ '20071109010002', 'thatbox', '/u_win',          3, 'TESTCONF003', 2,  'OK',       'OK',   '',         1, 4 ],
317           [ '20071109010002', 'thatbox', '/u_win',          3, 'TESTCONF003', 3,  'OK',       'OK',   '',         2, 4 ],
318           [ '20071109010002', 'thatbox', '/u_win',          3, 'TESTCONF003', 4,  'PARTIAL',  'OK',   '',         3, 4 ],
319           [ '20071109010002', 'thatbox', '/u_win',          3, 'TESTCONF004', 1,  'OK',       'OK',   '',         3, 4 ],
320           [ '20071109010002', 'thatbox', '/u_win',          3, 'TESTCONF004', 2,  'OK',       'OK',   '',         4, 4 ],
321         ], "results are correct");
322
323 my @filtered;
324 my @filtered_arr;
325
326 @filtered = Amanda::Logfile::dumps_match([@results], "thatbox", undef, undef, undef, 0);
327 is($#filtered+1, 10, "ten results match 'thatbox'");
328 @filtered = sort { $a->{'label'} cmp $b->{'label'} ||
329                    $a->{'filenum'} <=> $b->{'filenum'} } @filtered;
330
331 @filtered_arr = map { res2arr($_) } @filtered;
332
333 is_deeply(\@filtered_arr,
334         [
335           [ '20071109010002', 'thatbox', '/var',      1, 'TESTCONF002', 3,  'OK',      'OK',   '',         1, 1 ],
336           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 9,  'OK',      'FAIL', '"Oh no!"', 1, 4 ],
337           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 10, 'OK',      'FAIL', '"Oh no!"', 2, 4 ],
338           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 11, 'PARTIAL', 'FAIL', '"Oh no!"', 3, 4 ],
339           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF003', 1,  'OK',      'FAIL', '"Oh no!"', 3, 4 ],
340           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF003', 2,  'OK',      'OK',   '',         1, 4 ],
341           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF003', 3,  'OK',      'OK',   '',         2, 4 ],
342           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF003', 4,  'PARTIAL', 'OK',   '',         3, 4 ],
343           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF004', 1,  'OK',      'OK',   '',         3, 4 ],
344           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF004', 2,  'OK',      'OK',   '',         4, 4 ],
345         ], "results are correct");
346
347 @filtered = Amanda::Logfile::dumps_match([@results], "thatbox", "/var", undef, undef, 0);
348 is($#filtered+1, 1, "only one result matches 'thatbox:/var'");
349
350 @filtered = Amanda::Logfile::dumps_match([@results], undef, undef, "20071109010002", undef, 0);
351 is($#filtered+1, 17, "all 17 results match '20071109010002'");
352
353 @filtered = Amanda::Logfile::dumps_match([@results], undef, undef, "20071109010002", undef, 1);
354 is($#filtered+1, 12, "of those, 12 results are 'OK'");
355
356 @filtered = Amanda::Logfile::dumps_match([@results], undef, undef, undef, "2", 0);
357 is($#filtered+1, 4, "4 results are at level 2");
358
359 # test dumps_match_dumpspecs
360
361 my @dumpspecs;
362
363 @dumpspecs = Amanda::Cmdline::parse_dumpspecs(["thatbox", "/var"], 0);
364 @filtered = Amanda::Logfile::dumps_match_dumpspecs([@results], [@dumpspecs], 0);
365 is_deeply([ map { res2arr($_) } @filtered ],
366         [
367           [ '20071109010002', 'thatbox', '/var',            1, 'TESTCONF002', 3,  'OK', 'OK', '', 1, 1 ],
368         ], "filter with dumpspecs 'thatbox /var'");
369
370 @dumpspecs = Amanda::Cmdline::parse_dumpspecs(["thatbox", "/var", "clihost"], 0);
371 @filtered = Amanda::Logfile::dumps_match_dumpspecs([@results], [@dumpspecs], 0);
372 @filtered = sort { $a->{'label'} cmp $b->{'label'} ||
373                    $a->{'filenum'} <=> $b->{'filenum'} } @filtered;
374 is_deeply([ map { res2arr($_) } @filtered ],
375         [
376           [ '20071109010002', 'clihost', '/usr',            0, 'TESTCONF002', 1,  'OK', 'OK', '', 1, 1 ],
377           [ '20071109010002', 'clihost', '/my documents',   0, 'TESTCONF002', 2,  'OK', 'OK', '', 1, 1 ],
378           [ '20071109010002', 'thatbox', '/var',            1, 'TESTCONF002', 3,  'OK', 'OK', '', 1, 1 ],
379           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 4,  'OK', 'OK', '', 1, 5 ],
380           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 5,  'OK', 'OK', '', 2, 5 ],
381           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 6,  'OK', 'OK', '', 3, 5 ],
382           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 7,  'OK', 'OK', '', 4, 5 ],
383           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 8,  'OK', 'OK', '', 5, 5 ],
384         ], "filter with dumpspecs 'thatbox /var clihost' (union of two disjoint sets)");
385
386 # if multiple dumpspecs specify the same dump, it will be included in the output multiple times
387 @dumpspecs = Amanda::Cmdline::parse_dumpspecs([".*", "/var", "thatbox"], 0);
388 @filtered = Amanda::Logfile::dumps_match_dumpspecs([@results], [@dumpspecs], 0);
389 @filtered = sort { $a->{'label'} cmp $b->{'label'} ||
390                    $a->{'filenum'} <=> $b->{'filenum'} } @filtered;
391 is_deeply([ map { res2arr($_) } @filtered ],
392         [
393           [ '20071109010002', 'thatbox', '/var',      1, 'TESTCONF002', 3,  'OK',      'OK'  , '',         1, 1 ],
394           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 9,  'OK',      'FAIL', '"Oh no!"', 1, 4 ],
395           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 10, 'OK',      'FAIL', '"Oh no!"', 2, 4 ],
396           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 11, 'PARTIAL', 'FAIL', '"Oh no!"', 3, 4 ],
397           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF003', 1,  'OK',      'FAIL', '"Oh no!"', 3, 4 ],
398           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF003', 2,  'OK',      'OK'  , '',         1, 4 ],
399           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF003', 3,  'OK',      'OK'  , '',         2, 4 ],
400           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF003', 4,  'PARTIAL', 'OK'  , '',         3, 4 ],
401           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF004', 1,  'OK',      'OK'  , '',         3, 4 ],
402           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF004', 2,  'OK',      'OK'  , '',         4, 4 ],
403         ], "filter with dumpspecs '.* /var thatbox' (union of two overlapping sets includes dupes)");
404
405 @dumpspecs = Amanda::Cmdline::dumpspec_t->new('thatbox', undef, undef, undef, '20071109010002');
406 @filtered = Amanda::Logfile::dumps_match_dumpspecs([@results], [@dumpspecs], 0);
407 @filtered = sort { $a->{'label'} cmp $b->{'label'} ||
408                    $a->{'filenum'} <=> $b->{'filenum'} } @filtered;
409 is_deeply([ map { res2arr($_) } @filtered ],
410         [
411           [ '20071109010002', 'thatbox', '/var',      1, 'TESTCONF002', 3,  'OK',      'OK'  , '',         1, 1 ],
412           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 9,  'OK',      'FAIL', '"Oh no!"', 1, 4 ],
413           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 10, 'OK',      'FAIL', '"Oh no!"', 2, 4 ],
414           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 11, 'PARTIAL', 'FAIL', '"Oh no!"', 3, 4 ],
415           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF003', 1,  'OK',      'FAIL', '"Oh no!"', 3, 4 ],
416           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF003', 2,  'OK',      'OK'  , '',         1, 4 ],
417           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF003', 3,  'OK',      'OK'  , '',         2, 4 ],
418           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF003', 4,  'PARTIAL', 'OK'  , '',         3, 4 ],
419           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF004', 1,  'OK',      'OK'  , '',         3, 4 ],
420           [ '20071109010002', 'thatbox', '/u_win',    3, 'TESTCONF004', 2,  'OK',      'OK'  , '',         4, 4 ],
421         ], "filter with dumpspecs with host 'thatbox' and a write_timestamp");
422 unlink($log_filename);
423
424 # search_holding_disk and match_* are tested via Amanda::DB::Catalog's installcheck