b6c6acd2874bccbcf6702601a53e93b0e1159a3a
[debian/amanda] / installcheck / Amanda_Logfile.pl
1 # Copyright (c) 2006 Zmanda Inc.  All Rights Reserved.
2 #
3 # This program is free software; you can redistribute it and/or modify it
4 # under the terms of the GNU General Public License version 2 as published
5 # by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful, but
8 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
10 # for more details.
11 #
12 # You should have received a copy of the GNU General Public License along
13 # with this program; if not, write to the Free Software Foundation, Inc.,
14 # 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15 #
16 # Contact information: Zmanda Inc, 505 N Mathlida Ave, Suite 120
17 # Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
18
19 use Test::More qw(no_plan);
20 use File::Path;
21 use Amconfig;
22 use strict;
23
24 use lib "@amperldir@";
25 use Amanda::Paths;
26 use Amanda::Tapefile;
27 use Amanda::Logfile qw(:logtype_t :program_t open_logfile get_logline close_logfile);
28 use Amanda::Config qw( :init :getconf config_dir_relative );
29
30 # write a logfile and return the filename
31 sub write_logfile {
32     my ($contents) = @_;
33     my $filename = "$AMANDA_TMPDIR/Amanda_Logfile_test.log";
34
35     if (!-e $AMANDA_TMPDIR) {
36         mkpath($AMANDA_TMPDIR);
37     }
38
39     open my $logfile, ">", $filename or die("Could not create temporary log file");
40     print $logfile $contents;
41     close $logfile;
42
43     return $filename;
44 }
45
46 ####
47 ## RAW LOGFILE ACCESS
48
49 my $logfile;
50 my $logdata;
51
52 ##
53 # Test out the constant functions
54
55 is(logtype_t_to_string($L_MARKER), "L_MARKER", "logtype_t_to_string works");
56 is(program_t_to_string($P_DRIVER), "P_DRIVER", "program_t_to_string works");
57
58 ##
59 # Test a simple logfile
60
61 $logdata = <<END;
62 START planner date 20071026183200
63 END
64
65 $logfile = open_logfile(write_logfile($logdata));
66 ok($logfile, "can open a simple logfile");
67 is_deeply([ get_logline($logfile) ], 
68           [ $L_START, $P_PLANNER, "date 20071026183200" ],
69           "reads START line correctly");
70 ok(!get_logline($logfile), "no second line");
71 close_logfile($logfile);
72
73 ##
74 # Test continuation lines
75
76 $logdata = <<END;
77 INFO chunker line1
78   line2
79 END
80
81 $logfile = open_logfile(write_logfile($logdata));
82 ok($logfile, "can open a logfile containing conitinuation lines");
83 is_deeply([ get_logline($logfile) ],
84           [ $L_INFO, $P_CHUNKER, "line1" ], 
85           "can read INFO line");
86 is_deeply([ get_logline($logfile) ],
87           [ $L_CONT, $P_CHUNKER, "line2" ], 
88           "can read continuation line");
89 ok(!get_logline($logfile), "no third line");
90 close_logfile($logfile);
91
92 ##
93 # Test skipping blank lines
94
95 # (retain the two blank lines in the following:)
96 $logdata = <<END;
97
98 STATS taper foo
99
100 END
101
102 $logfile = open_logfile(write_logfile($logdata));
103 ok($logfile, "can open a logfile containing blank lines");
104 is_deeply([ get_logline($logfile) ], 
105           [ $L_STATS, $P_TAPER, "foo" ],
106           "reads non-blank line correctly");
107 ok(!get_logline($logfile), "no second line");
108 close_logfile($logfile);
109
110 ##
111 # Test BOGUS values and short lines
112
113 $logdata = <<END;
114 SOMETHINGWEIRD somerandomprog bar
115 MARKER amflush
116 MARKER amflush put something in curstr
117 PART
118 END
119
120 $logfile = open_logfile(write_logfile($logdata));
121 ok($logfile, "can open a logfile containing bogus entries");
122 is_deeply([ get_logline($logfile) ], 
123           [ $L_BOGUS, $P_UNKNOWN, "bar" ],
124           "can read line with bogus program and logtype");
125 is_deeply([ get_logline($logfile) ], 
126           [ $L_MARKER, $P_AMFLUSH, "" ],
127           "can read line with an empty string");
128 ok(get_logline($logfile), "can read third line (to fill in curstr with some text)");
129 is_deeply([ get_logline($logfile) ], 
130           [ $L_PART, $P_UNKNOWN, "" ],
131           "can read a one-word line, with P_UNKNOWN");
132 ok(!get_logline($logfile), "no next line");
133 close_logfile($logfile);
134
135 ## HIGHER-LEVEL FUNCTIONS
136
137 # a utility function for is_deeply checks, below.  Converts a hash to
138 # an array, for more succinct comparisons
139 sub res2arr {
140     my ($res) = @_;
141     return [
142         $res->{'timestamp'},
143         $res->{'hostname'},
144         $res->{'diskname'},
145         $res->{'level'},
146         $res->{'label'},
147         $res->{'filenum'},
148         $res->{'status'},
149         $res->{'partnum'}
150     ];
151 }
152
153 # set up a basic config
154 my $testconf = Amconfig->new();
155 $testconf->add_param("tapecycle", "20");
156 $testconf->write();
157
158 # load the config
159 ok(config_init($CONFIG_INIT_EXPLICIT_NAME, "TESTCONF"), "config_init is OK");
160 my $tapelist = config_dir_relative("tapelist");
161
162 # set up and read the tapelist
163 open my $tlf, ">", $tapelist or die("Could not write tapelist");
164 print $tlf "20071111010002 TESTCONF004 reuse\n";
165 print $tlf "20071110010002 TESTCONF003 reuse\n";
166 print $tlf "20071109010002 TESTCONF002 reuse\n";
167 print $tlf "20071108010001 TESTCONF001 reuse\n";
168 close $tlf;
169 Amanda::Tapefile::read_tapelist($tapelist) == 0 or die("Could not read tapelist");
170
171 # set up a number of logfiles in logdir.
172 my $logf;
173 my $logdir = $testconf->{'logdir'};
174
175 # (an old log file that should be ignored)
176 open $logf, ">", "$logdir/log.20071106010002.0" or die("Could not write logfile");
177 print $logf "START taper datestamp 20071107010002 label TESTCONF017 tape 1\n";
178 close $logf;
179
180 # (a logfile with two tapes)
181 open $logf, ">", "$logdir/log.20071106010002.0" or die("Could not write logfile");
182 print $logf "START taper datestamp 20071106010002 label TESTCONF018 tape 1\n";
183 print $logf "START taper datestamp 20071106010002 label TESTCONF019 tape 2\n";
184 close $logf;
185
186 open $logf, ">", "$logdir/log.20071108010001.0" or die("Could not write logfile");
187 print $logf "START taper datestamp 20071108010001 label TESTCONF001 tape 1\n";
188 close $logf;
189
190 # a logfile with some detail, to run search_logfile against
191 open $logf, ">", "$logdir/log.20071109010002.0" or die("Could not write logfile");
192 print $logf <<EOF;
193 START taper datestamp 20071109010002 label TESTCONF002 tape 1
194 PART taper TESTCONF002 1 clihost /usr 20071109010002 1 0 [regular single part PART]
195 DONE taper clihost /usr 20071109010002 1 0 [regular single part DONE]
196 PART taper TESTCONF002 2 clihost "/my documents" 20071109010002 1 0 [diskname quoting]
197 DONE taper clihost "/my documents" 20071109010002 1 0 [diskname quoting]
198 PART taper TESTCONF002 3 thatbox /var 1 [regular 'old style' PART]
199 DONE taper thatbox /var 1 [regular 'old style' DONE]
200 PART taper TESTCONF002 4 clihost /home 20071109010002 1/5 0 [multi-part dump]
201 PART taper TESTCONF002 5 clihost /home 20071109010002 2/5 0 [multi-part dump]
202 PART taper TESTCONF002 6 clihost /home 20071109010002 3/5 0 [multi-part dump]
203 PART taper TESTCONF002 7 clihost /home 20071109010002 4/5 0 [multi-part dump]
204 PART taper TESTCONF002 8 clihost /home 20071109010002 5/5 0 [multi-part dump]
205 DONE taper clihost /home 20071109010002 5 0 [multi-part dump]
206 PART taper TESTCONF002 9 thatbox /u_lose 20071109010002 1/4 2 [multi-part failure]
207 PART taper TESTCONF002 10 thatbox /u_lose 20071109010002 2/4 2 [multi-part failure]
208 PART taper TESTCONF002 11 thatbox /u_lose 20071109010002 3/4 2 [multi-part failure]
209 FAIL taper thatbox /u_lose 20071109010002 2 "Oh no!"
210 DONE taper thatbox /u_lose 20071109010002 4 2 [multi-part failure]
211 EOF
212 close $logf;
213
214 # "old-style amflush log"
215 open $logf, ">", "$logdir/log.20071110010002.amflush" or die("Could not write logfile");
216 print $logf "START taper datestamp 20071110010002 label TESTCONF003 tape 1\n";
217 close $logf;
218
219 # "old-style main log"
220 open $logf, ">", "$logdir/log.20071111010002" or die("Could not write logfile");
221 print $logf "START taper datestamp 20071111010002 label TESTCONF004 tape 1\n";
222 close $logf;
223
224 is_deeply([ Amanda::Logfile::find_log() ],
225           [ "log.20071111010002", "log.20071110010002.amflush",
226             "log.20071109010002.0", "log.20071108010001.0" ],
227           "find_log returns correct logfiles in the correct order");
228
229 my @results;
230 my @results_arr;
231
232 @results = Amanda::Logfile::search_logfile("TESTCONF002", "20071109010002",
233                                            "$logdir/log.20071109010002.0", 1);
234 is($#results+1, 11, "search_logfile returned 11 results");
235
236 # sort by filenum so we can compare each to what it should be
237 @results = sort { $a->{'filenum'} <=> $b->{'filenum'} } @results;
238
239 # and convert the hashes to arrays for easy comparison
240 @results_arr = map { res2arr($_) } @results;
241
242 is_deeply(\@results_arr,
243         [ [ '20071109010002', 'clihost', '/usr',            0, 'TESTCONF002', 1,  'OK', '1'   ],
244           [ '20071109010002', 'clihost', '/my documents',   0, 'TESTCONF002', 2,  'OK', '1'   ],
245           [ '20071109010002', 'thatbox', '/var',            1, 'TESTCONF002', 3,  'OK', '--'  ],
246           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 4,  'OK', '1/5' ],
247           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 5,  'OK', '2/5' ],
248           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 6,  'OK', '3/5' ],
249           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 7,  'OK', '4/5' ],
250           [ '20071109010002', 'clihost', '/home',           0, 'TESTCONF002', 8,  'OK', '5/5' ],
251           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 9,  '"Oh no!"', '1/4' ],
252           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 10, '"Oh no!"', '2/4' ],
253           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 11, '"Oh no!"', '3/4' ] ],
254           "results are correct");
255
256 my @filtered;
257 my @filtered_arr;
258
259 @filtered = Amanda::Logfile::dumps_match([@results], "thatbox", undef, undef, undef, 0);
260 is($#filtered+1, 4, "four results match 'thatbox'");
261 @filtered = sort { $a->{'filenum'} <=> $b->{'filenum'} } @filtered;
262
263 @filtered_arr = map { res2arr($_) } @filtered;
264
265 is_deeply(\@filtered_arr,
266         [ [ '20071109010002', 'thatbox', '/var',      1, 'TESTCONF002', 3,  'OK',       '--' ],
267           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 9,  '"Oh no!"', '1/4' ],
268           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 10, '"Oh no!"', '2/4' ],
269           [ '20071109010002', 'thatbox', '/u_lose',   2, 'TESTCONF002', 11, '"Oh no!"', '3/4' ] ],
270           "results are  correct");
271
272 @filtered = Amanda::Logfile::dumps_match([@results], "thatbox", "/var", undef, undef, 0);
273 is($#filtered+1, 1, "only one result matches 'thatbox:/var'");
274
275 @filtered = Amanda::Logfile::dumps_match([@results], undef, undef, "20071109010002", undef, 0);
276 is($#filtered+1, 11, "all 11 results match '20071109010002'");
277
278 @filtered = Amanda::Logfile::dumps_match([@results], undef, undef, "20071109010002", undef, 1);
279 is($#filtered+1, 8, "of those, 8 results are 'OK'");
280
281 @filtered = Amanda::Logfile::dumps_match([@results], undef, undef, undef, "2", 0);
282 is($#filtered+1, 3, "3 results are at level 2");