27f188f2f3eb124deef6c6554e991d23d3b72003
[external/curl.git] / tests / testcurl.pl
1 #!/usr/bin/env perl
2 #***************************************************************************
3 #                                  _   _ ____  _
4 #  Project                     ___| | | |  _ \| |
5 #                             / __| | | | |_) | |
6 #                            | (__| |_| |  _ <| |___
7 #                             \___|\___/|_| \_\_____|
8 #
9 # Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
10 #
11 # This software is licensed as described in the file COPYING, which
12 # you should have received as part of this distribution. The terms
13 # are also available at http://curl.haxx.se/docs/copyright.html.
14 #
15 # You may opt to use, copy, modify, merge, publish, distribute and/or sell
16 # copies of the Software, and permit persons to whom the Software is
17 # furnished to do so, under the terms of the COPYING file.
18 #
19 # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 # KIND, either express or implied.
21 #
22 ###########################################################################
23
24 ###########################
25 #  What is This Script?
26 ###########################
27
28 # testcurl.pl is the master script to use for automatic testing of curl
29 # directly off its source repository.
30 # This is written for the purpose of being run from a crontab job or similar
31 # at a regular interval. The output is suitable to be mailed to
32 # curl-autocompile@haxx.se to be dealt with automatically (make sure the
33 # subject includes the word "autobuild" as the mail gets silently discarded
34 # otherwise).  The most current build status (with a resonable backlog) will
35 # be published on the curl site, at http://curl.haxx.se/auto/
36
37 # USAGE:
38 # testcurl.pl [options] [curl-daily-name] > output
39
40 # Options:
41 #
42 # --configure=[options]    Configure options
43 # --crosscompile           This is a crosscompile
44 # --desc=[desc]            Description of your test system
45 # --email=[email]          Set email address to report as
46 # --extvercmd=[command]    Command to use for displaying version with cross compiles.
47 # --mktarball=[command]    Command to run after completed test
48 # --name=[name]            Set name to report as
49 # --nocvsup                Don't pull from git even though it is a git tree
50 # --nogitpull              Don't pull from git even though it is a git tree
51 # --nobuildconf            Don't run buildconf
52 # --noconfigure            Don't run configure
53 # --runtestopts=[options]  Options to pass to runtests.pl
54 # --setup=[file name]      File name to read setup from (deprecated)
55 # --target=[your os]       Specify your target environment.
56 #
57 # if [curl-daily-name] is omitted, a 'curl' git directory is assumed.
58 #
59
60 use strict;
61
62 use Cwd;
63
64 # Turn on warnings (equivalent to -w, which can't be used with /usr/bin/env)
65 #BEGIN { $^W = 1; }
66
67 use vars qw($version $fixed $infixed $CURLDIR $git $pwd $build $buildlog
68             $buildlogname $configurebuild $targetos $confheader $binext
69             $libext);
70
71 use vars qw($name $email $desc $confopts $runtestopts $setupfile $mktarball
72             $extvercmd $nogitpull $nobuildconf $crosscompile
73             $timestamp);
74
75 # version of this script
76 $version='2010-08-20';
77 $fixed=0;
78
79 # Determine if we're running from git or a canned copy of curl,
80 # or if we got a specific target option or setup file option.
81 $CURLDIR="curl";
82 if (-f ".git/config") {
83   $CURLDIR = "./";
84 }
85
86 $git=1;
87 $setupfile = 'setup';
88 $configurebuild = 1;
89 while ($ARGV[0]) {
90   if ($ARGV[0] =~ /--target=/) {
91     $targetos = (split(/=/, shift @ARGV))[1];
92   }
93   elsif ($ARGV[0] =~ /--setup=/) {
94     $setupfile = (split(/=/, shift @ARGV))[1];
95   }
96   elsif ($ARGV[0] =~ /--extvercmd=/) {
97     $extvercmd = (split(/=/, shift @ARGV))[1];
98   }
99   elsif ($ARGV[0] =~ /--mktarball=/) {
100     $mktarball = (split(/=/, shift @ARGV))[1];
101   }
102   elsif ($ARGV[0] =~ /--name=/) {
103     $name = (split(/=/, shift @ARGV))[1];
104   }
105   elsif ($ARGV[0] =~ /--email=/) {
106     $email = (split(/=/, shift @ARGV))[1];
107   }
108   elsif ($ARGV[0] =~ /--desc=/) {
109     $desc = (split(/=/, shift @ARGV))[1];
110   }
111   elsif ($ARGV[0] =~ /--configure=/) {
112     $confopts = (split(/=/, shift @ARGV))[1];
113   }
114   elsif (($ARGV[0] eq "--nocvsup") || ($ARGV[0] eq "--nogitpull")) {
115     $nogitpull=1;
116     shift @ARGV;
117   }
118   elsif ($ARGV[0] =~ /--nobuildconf/) {
119     $nobuildconf=1;
120     shift @ARGV;
121   }
122   elsif ($ARGV[0] =~ /--noconfigure/) {
123     $configurebuild=0;
124     shift @ARGV;
125   }
126   elsif ($ARGV[0] =~ /--crosscompile/) {
127     $crosscompile=1;
128     shift @ARGV;
129   }
130   elsif ($ARGV[0] =~ /--runtestopts=/) {
131     $runtestopts = (split(/=/, shift @ARGV, 2))[1];
132   }
133   else {
134     $CURLDIR=shift @ARGV;
135     $git=0; # a given dir, assume not using git
136   }
137 }
138
139 # Do the platform-specific stuff here
140 $confheader = 'curl_config.h';
141 $binext = '';
142 $libext = '.la'; # .la since both libcurl and libcares are made with libtool
143 if ($^O eq 'MSWin32' || $targetos) {
144   if (!$targetos) {
145     # If no target defined on Win32 lets assume vc
146     $targetos = 'vc';
147   }
148   if ($targetos =~ /vc/ || $targetos =~ /borland/ || $targetos =~ /watcom/) {
149     $binext = '.exe';
150     $libext = '.lib';
151   }
152   elsif ($targetos =~ /mingw/) {
153     $binext = '.exe';
154     if ($^O eq 'MSWin32') {
155       $libext = '.a';
156     }
157   }
158   elsif ($targetos =~ /netware/) {
159     $configurebuild = 0;
160     $binext = '.nlm';
161     if ($^O eq 'MSWin32') {
162       $libext = '.lib';
163     }
164     else {
165       $libext = '.a';
166     }
167   }
168 }
169
170 if (($^O eq 'MSWin32' || $^O eq 'msys') &&
171     ($targetos =~ /vc/ || $targetos =~ /mingw32/ ||
172      $targetos =~ /borland/ || $targetos =~ /watcom/)) {
173
174   # Set these things only when building ON Windows and for Win32 platform.
175   # FOR Windows since we might be cross-compiling on another system. Non-
176   # Windows builds still default to configure-style builds with curl_config.h.
177
178   $configurebuild = 0;
179   $confheader = 'config-win32.h';
180 }
181
182 $ENV{LC_ALL}="C" if (($ENV{LC_ALL}) && ($ENV{LC_ALL} !~ /^C$/));
183 $ENV{LC_CTYPE}="C" if (($ENV{LC_CTYPE}) && ($ENV{LC_CTYPE} !~ /^C$/));
184 $ENV{LANG}="C";
185
186 sub rmtree($) {
187     my $target = $_[0];
188     if ($^O eq 'MSWin32') {
189       foreach (glob($target)) {
190         s:/:\\:g;
191         system("rd /s /q $_");
192       }
193     } else {
194       system("rm -rf $target");
195     }
196 }
197
198 sub grepfile($$) {
199     my ($target, $fn) = @_;
200     open(F, $fn) or die;
201     while (<F>) {
202       if (/$target/) {
203         close(F);
204         return 1;
205       }
206     }
207     close(F);
208     return 0;
209 }
210
211 sub logit($) {
212     my $text=$_[0];
213     if ($text) {
214       print "testcurl: $text\n";
215     }
216 }
217
218 sub logit_spaced($) {
219     my $text=$_[0];
220     if ($text) {
221       print "\ntestcurl: $text\n\n";
222     }
223 }
224
225 sub mydie($){
226     my $text=$_[0];
227     logit "$text";
228     chdir $pwd; # cd back to the original root dir
229
230     if ($pwd && $build) {
231       # we have a build directory name, remove the dir
232       logit "removing the $build dir";
233       rmtree "$pwd/$build";
234     }
235     if (-r $buildlog) {
236       # we have a build log output file left, remove it
237       logit "removing the $buildlogname file";
238       unlink "$buildlog";
239     }
240     logit "ENDING HERE"; # last line logged!
241     exit 1;
242 }
243
244 sub get_host_triplet {
245   my $triplet;
246   my $configfile = "$pwd/$build/lib/curl_config.h";
247
248   if(-f $configfile && -s $configfile && open(LIBCONFIGH, "<$configfile")) {
249     while(<LIBCONFIGH>) {
250       if($_ =~ /^\#define\s+OS\s+"*([^"][^"]*)"*\s*/) {
251         $triplet = $1;
252         last;
253       }
254     }
255     close(LIBCONFIGH);
256   }
257   return $triplet;
258 }
259
260 if (open(F, "$setupfile")) {
261   while (<F>) {
262     if (/(\w+)=(.*)/) {
263       eval "\$$1=$2;";
264     }
265   }
266   close(F);
267   $infixed=$fixed;
268 } else {
269   $infixed=0;    # so that "additional args to configure" works properly first time...
270 }
271
272 if (!$name) {
273   print "please enter your name\n";
274   $name = <>;
275   chomp $name;
276   $fixed=1;
277 }
278
279 if (!$email) {
280   print "please enter your contact email address\n";
281   $email = <>;
282   chomp $email;
283   $fixed=2;
284 }
285
286 if (!$desc) {
287   print "please enter a one line system description\n";
288   $desc = <>;
289   chomp $desc;
290   $fixed=3;
291 }
292
293 if (!$confopts) {
294   if ($infixed < 4) {
295     print "please enter your additional arguments to configure\n";
296     print "examples: --with-ssl --enable-debug --enable-ipv6 --with-krb4\n";
297     $confopts = <>;
298     chomp $confopts;
299   }
300 }
301
302
303 if ($fixed < 4) {
304     $fixed=4;
305     open(F, ">$setupfile") or die;
306     print F "name='$name'\n";
307     print F "email='$email'\n";
308     print F "desc='$desc'\n";
309     print F "confopts='$confopts'\n";
310     print F "fixed='$fixed'\n";
311     close(F);
312 }
313
314 # Enable picky compiler warnings unless explicitly disabled
315 if (($confopts !~ /--enable-debug/) &&
316     ($confopts !~ /--enable-warnings/) &&
317     ($confopts !~ /--disable-warnings/)) {
318   $confopts .= " --enable-warnings";
319 }
320
321 my $str1066os = 'o' x 1066;
322
323 # Set timestamp to the UTC this script is running. Its value might
324 # be changed later in the script to the value present in curlver.h
325 $timestamp = scalar(gmtime)." UTC";
326
327 logit "STARTING HERE"; # first line logged, for scripts to trigger on
328 logit 'TRANSFER CONTROL ==== 1120 CHAR LINE' . $str1066os . 'LINE_END';
329 logit "NAME = $name";
330 logit "EMAIL = $email";
331 logit "DESC = $desc";
332 logit "CONFOPTS = $confopts";
333 logit "CPPFLAGS = ".$ENV{CPPFLAGS};
334 logit "CFLAGS = ".$ENV{CFLAGS};
335 logit "LDFLAGS = ".$ENV{LDFLAGS};
336 logit "CC = ".$ENV{CC};
337 logit "MAKEFLAGS = ".$ENV{MAKEFLAGS};
338 logit "PKG_CONFIG_PATH = ".$ENV{PKG_CONFIG_PATH};
339 logit "target = ".$targetos;
340 logit "version = $version"; # script version
341 logit "date = $timestamp";  # When the test build starts
342
343 $str1066os = undef;
344
345 # Make $pwd to become the path without newline. We'll use that in order to cut
346 # off that path from all possible logs and error messages etc.
347 $pwd = getcwd();
348
349 if (-d $CURLDIR) {
350   if ($git && -d "$CURLDIR/.git") {
351     logit "$CURLDIR is verified to be a fine git source dir";
352     # remove the generated sources to force them to be re-generated each
353     # time we run this test
354     unlink "$CURLDIR/src/hugehelp.c";
355   } elsif (!$git && -f "$CURLDIR/tests/testcurl.pl") {
356     logit "$CURLDIR is verified to be a fine daily source dir"
357   } else {
358     mydie "$CURLDIR is not a daily source dir or checked out from git!"
359   }
360 }
361 $build="build-$$";
362 $buildlogname="buildlog-$$";
363 $buildlog="$pwd/$buildlogname";
364
365 # remove any previous left-overs
366 rmtree "build-*";
367 rmtree "buildlog-*";
368
369 # this is to remove old build logs that ended up in the wrong dir
370 foreach (glob("$CURLDIR/buildlog-*")) { unlink $_; }
371
372 # create a dir to build in
373 mkdir $build, 0777;
374
375 if (-d $build) {
376   logit "build dir $build was created fine";
377 } else {
378   mydie "failed to create dir $build";
379 }
380
381 # get in the curl source tree root
382 chdir $CURLDIR;
383
384 # Do the git thing, or not...
385 if ($git) {
386   # update quietly to the latest git
387   if($nogitpull) {
388     logit "skipping git pull (--nogitpull)";
389   } else {
390     my $gitstat = 0;
391     my @commits;
392     logit "run git pull in curl";
393     system("git pull 2>&1");
394     $gitstat += $?;
395     logit "failed to update from curl git ($?), continue anyway" if ($?);
396     # get the last 5 commits for show (even if no pull was made)
397     @commits=`git log --pretty=oneline --abbrev-commit -5`;
398     logit "The most recent curl git commits:";
399     for (@commits) {
400       chomp ($_);
401       logit "  $_";
402     }
403     if (-d "ares/.git") {
404       chdir "ares";
405       logit "run git pull in ares";
406       system("git pull 2>&1");
407       $gitstat += $?;
408       logit "failed to update from ares git ($?), continue anyway" if ($?);
409       # get the last 5 commits for show (even if no pull was made)
410       @commits=`git log --pretty=oneline --abbrev-commit -5`;
411       logit "The most recent ares git commits:";
412       for (@commits) {
413         chomp ($_);
414         logit "  $_";
415       }
416       chdir "$pwd/$CURLDIR";
417     }
418     # Set timestamp to the UTC the git update took place.
419     $timestamp = scalar(gmtime)." UTC" if (!$gitstat);
420   }
421
422   if($nobuildconf) {
423     logit "told to not run buildconf";
424   }
425   elsif ($configurebuild) {
426     # remove possible left-overs from the past
427     unlink "configure";
428     unlink "autom4te.cache";
429
430     # generate the build files
431     logit "invoke buildconf, but filter off aclocal underquoted definition warnings";
432     open(F, "./buildconf 2>&1 |") or die;
433     open(LOG, ">$buildlog") or die;
434     while (<F>) {
435       next if /warning: underquoted definition of/;
436       print;
437       print LOG;
438     }
439     close(F);
440     close(LOG);
441
442     if (grepfile("^buildconf: OK", $buildlog)) {
443       logit "buildconf was successful";
444     }
445     else {
446       mydie "buildconf was NOT successful";
447     }
448   }
449   else {
450     logit "buildconf was successful (dummy message)";
451   }
452 }
453
454 # Set timestamp to the one in curlver.h if this isn't a git test build.
455 if ((-f "include/curl/curlver.h") &&
456     (open(F, "<include/curl/curlver.h"))) {
457   while (<F>) {
458     chomp;
459     if ($_ =~ /^\#define\s+LIBCURL_TIMESTAMP\s+\"(.+)\".*$/) {
460       my $stampstring = $1;
461       if ($stampstring !~ /DEV/) {
462           $stampstring =~ s/\s+UTC//;
463           $timestamp = $stampstring." UTC";
464       }
465       last;
466     }
467   }
468   close(F);
469 }
470
471 # Show timestamp we are using for this test build.
472 logit "timestamp = $timestamp";
473
474 if ($configurebuild) {
475   if (-f "configure") {
476     logit "configure created (at least it exists)";
477   } else {
478     mydie "no configure created/found";
479   }
480 } else {
481   logit "configure created (dummy message)"; # dummy message to feign success
482 }
483
484 sub findinpath {
485   my $c;
486   my $e;
487   my $x = ($^O eq 'MSWin32') ? '.exe' : '';
488   my $s = ($^O eq 'MSWin32') ? ';' : ':';
489   my $p=$ENV{'PATH'};
490   my @pa = split($s, $p);
491   for $c (@_) {
492     for $e (@pa) {
493       if( -x "$e/$c$x") {
494         return $c;
495       }
496     }
497   }
498 }
499
500 my $make = findinpath("gmake", "make", "nmake");
501 if(!$make) {
502     mydie "Couldn't find make in the PATH";
503 }
504 # force to 'nmake' for VC builds
505 $make = "nmake" if ($targetos =~ /vc/);
506 # force to 'wmake' for Watcom builds
507 $make = "wmake" if ($targetos =~ /watcom/);
508 logit "going with $make as make";
509
510 # change to build dir
511 chdir "$pwd/$build";
512
513 if ($configurebuild) {
514   # run configure script
515   print `../$CURLDIR/configure $confopts 2>&1`;
516
517   if (-f "lib/Makefile") {
518     logit "configure seems to have finished fine";
519   } else {
520     mydie "configure didn't work";
521   }
522 } else {
523   logit "copying files to build dir ...";
524   if (($^O eq 'MSWin32') && ($targetos !~ /netware/)) {
525     system("xcopy /s /q ..\\$CURLDIR .");
526     system("buildconf.bat");
527   }
528   elsif ($targetos =~ /netware/) {
529     system("cp -afr ../$CURLDIR/* .");
530     system("cp -af ../$CURLDIR/Makefile.dist Makefile");
531     system("$make -i -C lib -f Makefile.netware prebuild");
532     system("$make -i -C src -f Makefile.netware prebuild");
533     if (-d "../$CURLDIR/ares") {
534       system("$make -i -C ares -f Makefile.netware prebuild");
535     }
536   }
537   elsif ($^O eq 'linux') {
538     system("cp -afr ../$CURLDIR/* .");
539     system("cp -af ../$CURLDIR/Makefile.dist Makefile");
540     system("cp -af ../$CURLDIR/include/curl/curlbuild.h.dist ./include/curl/curlbuild.h");
541     system("$make -i -C lib -f Makefile.$targetos prebuild");
542     system("$make -i -C src -f Makefile.$targetos prebuild");
543     if (-d "../$CURLDIR/ares") {
544       system("cp -af ../$CURLDIR/ares/ares_build.h.dist ./ares/ares_build.h");
545       system("$make -i -C ares -f Makefile.$targetos prebuild");
546     }
547   }
548 }
549
550 if(-f "./libcurl.pc") {
551   logit_spaced "display libcurl.pc";
552   if(open(F, "<./libcurl.pc")) {
553     while(<F>) {
554       my $ll = $_;
555       print $ll if(($ll !~ /^ *#/) && ($ll !~ /^ *$/));
556     }
557     close(F);
558   }
559 }
560
561 if(-f "./include/curl/curlbuild.h") {
562   logit_spaced "display include/curl/curlbuild.h";
563   if(open(F, "<./include/curl/curlbuild.h")) {
564     while(<F>) {
565       my $ll = $_;
566       print $ll if(($ll =~ /^ *# *define *CURL_/) && ($ll !~ /__CURL_CURLBUILD_H/));
567     }
568     close(F);
569   }
570 }
571 else {
572   mydie "no curlbuild.h created/found";
573 }
574
575 logit_spaced "display lib/$confheader";
576 open(F, "lib/$confheader") or die "lib/$confheader: $!";
577 while (<F>) {
578   print if /^ *#/;
579 }
580 close(F);
581
582 if (grepfile("^#define USE_ARES", "lib/$confheader")) {
583   print "\n";
584   logit "setup to build ares";
585
586   if(-f "./ares/libcares.pc") {
587     logit_spaced  "display ares/libcares.pc";
588     if(open(F, "<./ares/libcares.pc")) {
589       while(<F>) {
590         my $ll = $_;
591         print $ll if(($ll !~ /^ *#/) && ($ll !~ /^ *$/));
592       }
593       close(F);
594     }
595   }
596
597   if(-f "./ares/ares_build.h") {
598     logit_spaced "display ares/ares_build.h";
599     if(open(F, "<./ares/ares_build.h")) {
600       while(<F>) {
601         my $ll = $_;
602         print $ll if(($ll =~ /^ *# *define *CARES_/) && ($ll !~ /__CARES_BUILD_H/));
603       }
604       close(F);
605     }
606   }
607   else {
608     mydie "no ares_build.h created/found";
609   }
610
611   $confheader =~ s/curl/ares/;
612   logit_spaced "display ares/$confheader";
613   if(open(F, "ares/$confheader")) {
614       while (<F>) {
615           print if /^ *#/;
616       }
617       close(F);
618   }
619
620   print "\n";
621   logit "build ares";
622   chdir "ares";
623
624   if ($targetos && !$configurebuild) {
625       logit "$make -f Makefile.$targetos";
626       open(F, "$make -f Makefile.$targetos 2>&1 |") or die;
627   }
628   else {
629       logit "$make";
630       open(F, "$make 2>&1 |") or die;
631   }
632   while (<F>) {
633     s/$pwd//g;
634     print;
635   }
636   close(F);
637
638   if (-f "libcares$libext") {
639     logit "ares is now built successfully (libcares$libext)";
640   } else {
641     mydie "ares build failed (libcares$libext)";
642   }
643
644   # cd back to the curl build dir
645   chdir "$pwd/$build";
646 }
647
648 my $mkcmd = "$make -i" . ($targetos && !$configurebuild ? " $targetos" : "");
649 logit "$mkcmd";
650 open(F, "$mkcmd 2>&1 |") or die;
651 while (<F>) {
652   s/$pwd//g;
653   print;
654 }
655 close(F);
656
657 if (-f "lib/libcurl$libext") {
658   logit "libcurl was created fine (libcurl$libext)";
659 }
660 else {
661   mydie "libcurl was not created (libcurl$libext)";
662 }
663
664 if (-f "src/curl$binext") {
665   logit "curl was created fine (curl$binext)";
666 }
667 else {
668   mydie "curl was not created (curl$binext)";
669 }
670
671 if (!$crosscompile || (($extvercmd ne '') && (-x $extvercmd))) {
672   logit "display curl${binext} --version output";
673   my $cmd = ($extvercmd ne '' ? $extvercmd.' ' : '')."./src/curl${binext} --version|";
674   open(F, $cmd);
675   while(<F>) {
676     # strip CR from output on non-win32 platforms (wine on Linux)
677     s/\r// if ($^O ne 'MSWin32');
678     print;
679   }
680   close(F);
681 }
682
683 if ($configurebuild && !$crosscompile) {
684   my $o;
685   if($runtestopts) {
686       $o = "TEST_F=\"$runtestopts\" ";
687   }
688   logit "$make -k ${o}test-full";
689   open(F, "$make -k ${o}test-full 2>&1 |") or die;
690   open(LOG, ">$buildlog") or die;
691   while (<F>) {
692     s/$pwd//g;
693     print;
694     print LOG;
695   }
696   close(F);
697   close(LOG);
698
699   if (grepfile("^TEST", $buildlog)) {
700     logit "tests were run";
701   } else {
702     mydie "test suite failure";
703   }
704
705   if (grepfile("^TESTFAIL:", $buildlog)) {
706     logit "the tests were not successful";
707   } else {
708     logit "the tests were successful!";
709   }
710 }
711 else {
712   if($crosscompile) {
713     # build test harness programs for selected cross-compiles
714     my $host_triplet = get_host_triplet();
715     if($host_triplet =~ /([^-]+)-([^-]+)-mingw(.*)/) {
716       chdir "$pwd/$build/tests";
717       logit_spaced "build test harness";
718       open(F, "$make -i 2>&1 |") or die;
719       open(LOG, ">$buildlog") or die;
720       while (<F>) {
721         s/$pwd//g;
722         print;
723         print LOG;
724       }
725       close(F);
726       close(LOG);
727       chdir "$pwd/$build";
728     }
729     logit_spaced "cross-compiling, can't run tests";
730   }
731   # dummy message to feign success
732   print "TESTDONE: 1 tests out of 0 (dummy message)\n";
733 }
734
735 # create a tarball if we got that option.
736 if (($mktarball ne '') && (-x $mktarball)) {
737   system($mktarball);
738 }
739
740 # mydie to cleanup
741 mydie "ending nicely";