]> sjero.net Git - wget/blob - tests/Test.pm
[svn] Unset svn:executable property.
[wget] / tests / Test.pm
1 #!/usr/bin/perl -w
2
3 package Test;
4 $VERSION = 0.01;
5
6 use strict;
7
8 use Cwd;
9 use File::Path;
10
11 my @unexpected_downloads = ();
12
13 {
14     my %_attr_data = ( # DEFAULT
15         _cmdline      => "",
16         _workdir      => Cwd::getcwd(),
17         _errcode      => 0,
18         _existing     => {},
19         _input        => {},
20         _name         => "",
21         _output       => {},
22     );
23     
24     sub _default_for
25     {
26         my ($self, $attr) = @_;
27         $_attr_data{$attr};
28     }
29
30     sub _standard_keys 
31     {
32         keys %_attr_data;
33     }
34 }
35
36
37 sub new {
38     my ($caller, %args) = @_;
39     my $caller_is_obj = ref($caller);
40     my $class = $caller_is_obj || $caller;
41     #print STDERR "class = ", $class, "\n";
42     #print STDERR "_attr_data {workdir} = ", $Test::_attr_data{_workdir}, "\n";
43     my $self = bless {}, $class;
44     foreach my $attrname ($self->_standard_keys()) {
45         #print STDERR "attrname = ", $attrname, " value = ";
46         my ($argname) = ($attrname =~ /^_(.*)/);
47         if (exists $args{$argname}) {
48             #printf STDERR "Setting up $attrname\n";
49             $self->{$attrname} = $args{$argname};
50         } elsif ($caller_is_obj) {
51             #printf STDERR "Copying $attrname\n";
52             $self->{$attrname} = $caller->{$attrname};
53         } else {
54             #printf STDERR "Using default for $attrname\n";
55             $self->{$attrname} = $self->_default_for($attrname);
56         }
57         #print STDERR $attrname, '=', $self->{$attrname}, "\n";
58     }
59     #printf STDERR "_workdir default = ", $self->_default_for("_workdir");
60     return $self;
61 }
62
63
64 sub run {
65     my $self = shift;
66     my $result_message = "Test successful.\n";
67    
68     printf "Running test $self->{_name}\n";
69     
70     # Setup 
71     $self->_setup();
72     chdir ("$self->{_workdir}/$self->{_name}/input");
73     
74     # Launch server
75     my $pid = $self->_fork_and_launch_server();
76     
77     # Call wget
78     chdir ("$self->{_workdir}/$self->{_name}/output");
79     # print "Calling $self->{_cmdline}\n";
80     my $errcode = 
81         ($self->{_cmdline} =~ m{^/.*}) 
82             ? system ($self->{_cmdline})
83             : system ("$self->{_workdir}/../src/$self->{_cmdline}");
84
85     # Shutdown server
86     # if we didn't explicitely kill the server, we would have to call 
87     # waitpid ($pid, 0) here in order to wait for the child process to 
88     # terminate
89     kill ('TERM', $pid);
90
91     # Verify download
92     unless ($errcode == $self->{_errcode}) {
93         $result_message = "Test failed: wrong code returned (was: $errcode, expected: $self->{_errcode})\n";
94     }
95     if (my $error_str = $self->_verify_download()) {
96         $result_message = $error_str;
97     }
98
99     # Cleanup
100     $self->_cleanup();
101
102     print $result_message;
103 }
104
105
106 sub _setup {
107     my $self = shift;
108
109     #print $self->{_name}, "\n";
110     chdir ($self->{_workdir});
111
112     # Create temporary directory
113     mkdir ($self->{_name});
114     chdir ($self->{_name});
115     mkdir ("input");
116     mkdir ("output");
117     
118     # Setup existing files
119     chdir ("output");
120     foreach my $filename (keys %{$self->{_existing}}) {
121         open (FILE, ">$filename") 
122             or return "Test failed: cannot open pre-existing file $filename\n";
123         
124         print FILE $self->{_existing}->{$filename}->{content}
125             or return "Test failed: cannot write pre-existing file $filename\n";
126         
127         close (FILE);
128     } 
129     
130     chdir ("../input");
131     $self->_setup_server();
132
133     chdir ($self->{_workdir});
134 }
135
136
137 sub _cleanup {
138     my $self = shift;
139
140     chdir ($self->{_workdir});
141     File::Path::rmtree ($self->{_name});
142 }
143
144
145 sub _verify_download {
146     my $self = shift;
147
148     chdir ("$self->{_workdir}/$self->{_name}/output");
149     
150     # use slurp mode to read file content
151     my $old_input_record_separator = $/;
152     undef $/;
153     
154     while (my ($filename, $filedata) = each %{$self->{_output}}) {
155         open (FILE, $filename) 
156             or return "Test failed: file $filename not downloaded\n";
157         
158         my $content = <FILE>;
159         $content eq $filedata->{'content'} 
160             or return "Test failed: wrong content for file $filename\n";
161
162         if (exists($filedata->{'timestamp'})) {
163             my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
164                 $atime, $mtime, $ctime, $blksize, $blocks) = stat FILE;
165
166             $mtime == $filedata->{'timestamp'} 
167                 or return "Test failed: wrong timestamp for file $filename\n";
168         }
169         
170         close (FILE);
171     } 
172     
173     $/ = $old_input_record_separator;    
174
175     # make sure no unexpected files were downloaded
176     chdir ("$self->{_workdir}/$self->{_name}/output");
177
178     __dir_walk('.', sub { push @unexpected_downloads, $_[0] unless (exists $self->{_output}{$_[0]}) }, sub { shift; return @_ } );
179     if (@unexpected_downloads) { 
180         return "Test failed: unexpected downloaded files [" . join(', ', @unexpected_downloads) . "]\n";
181     }
182
183     return "";
184 }
185
186
187 sub __dir_walk {
188     my ($top, $filefunc, $dirfunc) = @_;
189
190     my $DIR;
191
192     if (-d $top) {
193         my $file;
194         unless (opendir $DIR, $top) {
195             warn "Couldn't open directory $DIR: $!; skipping.\n";
196             return;
197         }
198
199         my @results;
200         while ($file = readdir $DIR) {
201             next if $file eq '.' || $file eq '..';
202             my $nextdir = $top eq '.' ? $file : "$top/$file";
203             push @results, __dir_walk($nextdir, $filefunc, $dirfunc);
204         }
205
206         return $dirfunc ? $dirfunc->($top, @results) : () ;
207     } else {
208         return $filefunc ? $filefunc->($top) : () ;
209     }
210 }
211
212
213 sub _fork_and_launch_server 
214 {
215     my $self = shift;
216
217     pipe(FROM_CHILD, TO_PARENT) or die "Cannot create pipe!";
218     select((select(TO_PARENT), $| = 1)[0]);
219
220     my $pid = fork();
221     if ($pid < 0) {
222         die "Cannot fork";
223     } elsif ($pid == 0) {
224         # child 
225         close FROM_CHILD;
226         $self->_launch_server(sub { print TO_PARENT "SYNC\n"; close TO_PARENT });
227     } else {
228         # father
229         close TO_PARENT;
230         chomp(my $line = <FROM_CHILD>);
231         close FROM_CHILD;
232     }
233
234     return $pid;
235 }
236
237 1;
238
239 # vim: et ts=4 sw=4
240