]> git.donarmstrong.com Git - debbugs.git/blobdiff - t/lib/DebbugsTest.pm
add submit_but and run_processall utility routines
[debbugs.git] / t / lib / DebbugsTest.pm
index c299df7768ada303b7c1a8a82e3cb6f7f1e100e4..152bd5801fa3afcb80451422835d86f7a9cf477f 100644 (file)
@@ -24,6 +24,8 @@ use strict;
 use vars qw($VERSION $DEBUG %EXPORT_TAGS @EXPORT_OK @EXPORT);
 use base qw(Exporter);
 
+use v5.10;
+
 use IO::File;
 use File::Temp qw(tempdir);
 use Cwd qw(getcwd);
@@ -31,6 +33,8 @@ use Debbugs::MIME qw(create_mime_message);
 use File::Basename qw(dirname basename);
 use IPC::Open3;
 use IO::Handle;
+use Test::More;
+use Test::PostgreSQL;
 
 use Params::Validate qw(validate_with :types);
 
@@ -39,10 +43,14 @@ BEGIN{
      $DEBUG = 0 unless defined $DEBUG;
 
      @EXPORT = ();
-     %EXPORT_TAGS = (configuration => [qw(dirsize create_debbugs_configuration send_message)],
+     %EXPORT_TAGS = (configuration => [qw(dirsize create_debbugs_configuration send_message),
+                                      qw(submit_bug run_processall)],
+                    mail          => [qw(num_messages_sent)],
+                    control       => [qw(test_control_commands)],
+                    database => [qw(create_postgresql_database update_postgresql_database)]
                    );
      @EXPORT_OK = ();
-     Exporter::export_ok_tags(qw(configuration));
+     Exporter::export_ok_tags(keys %EXPORT_TAGS);
      $EXPORT_TAGS{all} = [@EXPORT_OK];
 }
 
@@ -55,7 +63,8 @@ BEGIN{
 sub create_debbugs_configuration {
      my %param = validate_with(params => \@_,
                               spec   => {debug => {type => BOOLEAN,
-                                                   default => 0,
+                                                   default => exists $ENV{DEBUG}?
+                                                   $ENV{DEBUG}:0,
                                                   },
                                          cleanup => {type => BOOLEAN,
                                                      optional => 1,
@@ -71,6 +80,7 @@ sub create_debbugs_configuration {
      $ENV{DEBBUGS_CONFIG_FILE}  ="$config_dir/debbugs_config";
      $ENV{PERL5LIB} = getcwd();
      $ENV{SENDMAIL_TESTDIR} = $sendmail_dir;
+     eval {
      my $sendmail_tester = getcwd().'/t/sendmail_tester';
      unless (-x $sendmail_tester) {
          die q(t/sendmail_tester doesn't exist or isn't executable. You may be in the wrong directory.);
@@ -79,16 +89,20 @@ sub create_debbugs_configuration {
 \$gSendmail='$sendmail_tester';
 \$gSpoolDir='$spool_dir';
 \$gLibPath='@{[getcwd()]}/scripts';
+\$gTemplateDir='@{[getcwd()]}/templates';
+\$gWebDir='@{[getcwd()]}/html';
 \$gWebHost='localhost';
 1;
 END
                            "$spool_dir/nextnumber" => qq(1\n),
-                           "$config_dir/Maintainers" => qq(foo Blah Bleargh <bar\@baz.com>\n),
+                           "$config_dir/Maintainers" => qq(foo Blah Bleargh <foo\@baz.com>\nbar Bar Bleargh <bar\@baz.com>\n),
                            "$config_dir/Maintainers.override" => qq(),
+                           "$config_dir/Source_maintainers" => qq(foo Blah Bleargh <foo\@baz.com>\nbar Bar Bleargh <bar\@baz.com>\n),
                            "$config_dir/indices/sources" => <<END,
 foo main foo
 END
                            "$config_dir/pseudo-packages.description" => '',
+                           "$config_dir/pseudo-packages.maintainers" => '',
                           );
      while (my ($file,$contents) = each %files_to_create) {
          system('mkdir','-p',dirname($file));
@@ -106,12 +120,27 @@ END
            "$spool_dir/index.archive");
 
      # create the spool files and sub directories
-     map {system('mkdir','-p',"$spool_dir/$_"); }
-         map {('db-h/'.$_,'archive/'.$_)}
-              map { sprintf "%02d",$_ % 100} 0..99;
+     for my $dir (0..99) {
+         for my $archive (qw(db-h archive)) {
+             system('mkdir','-p',"$spool_dir/$archive/".sprintf('%02d',$dir));
+         }
+     }
      system('mkdir','-p',"$spool_dir/incoming");
      system('mkdir','-p',"$spool_dir/lock");
+     # generate the maintainers index files
+     system('scripts/maintainer-indices') == 0
+        or die "Unable to generate maintainer index files";
+     eval '
+END{
+     if ($ENV{DEBUG}) {
+         diag("spool_dir:   $spool_dir\n");
+         diag("config_dir:   $config_dir\n",);
+         diag("sendmail_dir: $sendmail_dir\n");
+     }
+}';
 
+     };
+     BAIL_OUT ($@) if ($@);
      return (spool_dir => $spool_dir,
             sendmail_dir => $sendmail_dir,
             config_dir => $config_dir,
@@ -140,6 +169,9 @@ sub send_message{
                                                     },
                                          body    => {type => SCALAR,
                                                     },
+                                         attachments => {type => ARRAYREF,
+                                                         default => [],
+                                                        },
                                          run_processall =>{type => BOOLEAN,
                                                            default => 1,
                                                           },
@@ -148,18 +180,22 @@ sub send_message{
      $ENV{LOCAL_PART} = $param{to};
      my ($rfd,$wfd);
      my $output='';
-     local $SIG{PIPE} = 'IGNORE';
-     local $SIG{CHLD} = sub {};
-     my $pid = open3($wfd,$rfd,$rfd,'scripts/receive.in')
-         or die "Unable to start receive.in: $!";
+     my $pipe_handler = $SIG{PIPE};
+     $SIG{PIPE} = 'IGNORE';
+     $SIG{CHLD} = 'DEFAULT';
+     my $pid = open3($wfd,$rfd,$rfd,'scripts/receive')
+         or die "Unable to start receive: $!";
      print {$wfd} create_mime_message($param{headers},
-                                        $param{body}) or die "Unable to to print to receive.in";
-     close($wfd) or die "Unable to close receive.in";
+                                     $param{body},
+                                     $param{attachments}) or
+                                         die "Unable to to print to receive";
+     close($wfd) or die "Unable to close receive";
+     $SIG{PIPE} = $pipe_handler;
      my $err = $? >> 8;
      my $childpid = waitpid($pid,0);
      if ($childpid != -1) {
          $err = $? >> 8;
-         print STDERR "receive.in pid: $pid doesn't match childpid: $childpid\n" if $childpid != $pid;
+         print STDERR "receive pid: $pid doesn't match childpid: $childpid\n" if $childpid != $pid;
      }
      if ($err != 0 ) {
          my $rfh =  IO::Handle->new_from_fd($rfd,'r') or die "Unable to create filehandle: $!";
@@ -170,17 +206,139 @@ sub send_message{
               print STDERR "Reading from STDOUT/STDERR would have blocked.";
          }
          print STDERR $output,qq(\n);
-         die "receive.in failed with exit status $err";
+         die "receive failed with exit status $err";
      }
      # now we should run processall to see if the message gets processed
      if ($param{run_processall}) {
-         system('scripts/processall.in') == 0 or die "processall.in failed";
-     }
+        run_processall();
+      }
+     return 1;
 }
 
+sub run_processall {
+    system('scripts/processall') == 0 or die "processall failed";
+}
+
+=item test_control_commands
+
+ test_control_commands(\%config,
+                       forcemerge => {command => 'forcemerge',
+                                      value   => '1 2',
+                                      status_key => 'mergedwith',
+                                      status_value => '2',
+                                      expect_error => 0,
+                                     });
+
+Test a set of control commands to see if they will fail or not. Takes
+SCALAR/HASHREF pairs, where the scalar should be unique, and the HASHREF
+contains the following keys:
+
+=over
+
+=item command -- control command to issue
+
+=item value -- value to pass to control command
+
+=item status_key -- bug status key to check
+
+=item status_value -- value of status key
+
+=item expect_error -- whether to expect the control command to error or not
+
+=back
+
+=cut
+
+sub test_control_commands {
+    my ($config,@commands) = @_;
+
+    # now we need to check to make sure that the control message actually did anything
+    # This is an eval because $ENV{DEBBUGS_CONFIG_FILE} isn't set at BEGIN{} time
+    eval "use Debbugs::Status qw(read_bug writebug);";
+    while (my ($command,$control_command) = splice(@commands,0,2)) {
+       # just check to see that control doesn't explode
+       $control_command->{value} = " $control_command->{value}" if length $control_command->{value}
+           and $control_command->{value} !~ /^\s/;
+       send_message(to => 'control@bugs.something',
+                    headers => [To   => 'control@bugs.something',
+                                From => 'foo@bugs.something',
+                                Subject => "Munging a bug with $command",
+                               ],
+                    body => <<EOF) or fail 'message to control@bugs.something failed';
+debug 10
+$control_command->{command} $control_command->{value}
+thanks
+EOF
+       ;
+       # now we need to check to make sure the control message was processed without errors
+       if (not ($control_command->{expect_error} // 0)) {
+           ok(system('sh','-c','find '.$config->{sendmail_dir}.
+                     q( -type f | xargs grep -q "Subject: Processed: Munging a bug with $command")
+                    ) == 0,
+              'control@bugs.something'. "$command message was parsed without errors");
+       }
+       # now we need to check to make sure that the control message actually did anything
+       my $status;
+       $status = read_bug(exists $control_command->{bug}?(bug => $control_command->{bug}):(bug=>1),
+                          exists $control_command->{location}?(location => $control_command->{location}):(),
+                         );
+       is_deeply($status->{$control_command->{status_key}},
+                 $control_command->{status_value},
+                 "bug " .
+                 (exists $control_command->{bug}?$control_command->{bug}:1).
+                 " $command"
+                )
+           or fail(Data::Dumper->Dump([$status],[qw(status)]));
+    }
+}
+
+sub submit_bug {
+    state $spec =
+       {subject => {type => SCALAR,
+                   default => 'Submitting a bug',
+                  },
+       body => {type => SCALAR,
+                default => 'This is a silly bug',
+               },
+       submitter => {type => SCALAR,
+                     default => 'foo@bugs.something',
+                    },
+       pseudoheaders => {type => HASHREF,
+                         default => sub {{}},
+                        },
+       package => {type => SCALAR,
+                   default => 'foo',
+                  },
+       run_processall => {type => SCALAR,
+                          default => 0,
+                         },
+       };
+    my %param =
+       validate_with(params => \@_,
+                     spec => $spec);
+    my $body = 'Package: '.$param{package}."\n";
+    foreach my $key (keys %{$param{pseudoheaders}}) {
+       for my $val (ref($param{pseudoheaders}{$key}) ?
+                    @{$param{pseudoheaders}{$key}} :
+                    $param{pseudoheaders}{$key}) {
+           $body .= $key. ': '.$val."\n";
+       }
+    }
+    $body .="\n".$param{body};
+    send_message(to => 'submit@bugs.something',
+                headers => [To => 'submit@bugs.something',
+                            From => $param{submitter},
+                            Subject => $param{subject},
+                           ],
+                run_processall => $param{run_processall},
+                body => $body
+               );
+}
+
+
 {
      package DebbugsTest::HTTPServer;
-     use base qw(HTTP::Server::Simple::CGI);
+     use base qw(HTTP::Server::Simple::CGI HTTP::Server::Simple::CGI::Environment);
 
      our $child_pid = undef;
      our $webserver = undef;
@@ -189,8 +347,10 @@ sub send_message{
      END {
          if (defined $child_pid) {
               # stop the child
+              my $temp_exit = $?;
               kill(15,$child_pid);
               waitpid(-1,0);
+              $? = $temp_exit;
          }
      }
 
@@ -227,6 +387,117 @@ sub send_message{
      }
 }
 
+=head2 num_messages_sent
+
+     $SD_SIZE = num_messages_sent($SD_SIZE,2,$sendmail_dir,'2 messages have been sent properly');
+
+Tests to make sure that at least a certain number of messages have
+been sent since the last time this command was run. Usefull to test to
+make sure that mail has been sent.
+
+=cut
+
+sub num_messages_sent {
+    my ($prev_size,$num_messages,$sendmail_dir,$test_name) = @_;
+    my $cur_size = dirsize($sendmail_dir);
+    ## print STDERR "sendmail: $sendmail_dir, want: $num_messages,
+    ## size: $cur_size, prev_size: $prev_size\n";
+    ok($cur_size-$prev_size >= $num_messages, $test_name);
+    return $cur_size;
+}
+
+=head2 create_postgresql_database
+
+C<my $pgsql = create_postgresql_database();>
+
+Create a postgresql database for testing; when the L<Test::PostgreSQL> object it
+returns is destroyed (or goes out of scope) the database will be removed.
+
+=cut
+
+sub create_postgresql_database {
+    my $pgsql = Test::PostgreSQL->new(use_socket => 1) or
+       return undef;
+    my $installsql =
+       File::Spec->rel2abs(dirname(__FILE__).'/../..').
+           '/bin/debbugs-installsql';
+    # create the debversion extension
+    my $dbh = DBI->connect($pgsql->dsn);
+    $dbh->do(<<END) or die "Unable to create extension";
+CREATE EXTENSION IF NOT EXISTS debversion;
+END
+    # create the schema for the bug tracking system
+    my $dep_dir = File::Temp::tempdir(CLEANUP=>1);
+    system($installsql,
+          '--dsn',$pgsql->dsn,
+          '--install',
+          '--deployment-dir',$dep_dir);
+
+    initialize_postgresql_database($pgsql,@_);
+    return $pgsql;
+}
+
+=item iniitalize_postgresql_database
+
+C<initialize_postgresql_database();>
+
+Initialize postgresql database by calling debbugs-loadsql appropriately.
+
+=cut
+
+sub initialize_postgresql_database {
+    my ($pgsql,@options) = @_;
+    my $loadsql =
+       File::Spec->rel2abs(dirname(__FILE__).'/../..').
+           '/bin/debbugs-loadsql';
+
+    my $ftpdists =
+       File::Spec->rel2abs(dirname(__FILE__).'/../debian/dist');
+    my $debinfo_dir =
+       File::Spec->rel2abs(dirname(__FILE__).'/../debian/debinfo');
+    my %loadsql_commands =
+       (configuration => [],
+        suites => ['--ftpdists',$ftpdists],
+        debinfo => ['--debinfo-dir',$debinfo_dir],
+        packages => ['--ftpdists',$ftpdists],
+        maintainers => [],
+       );
+    for my $command (keys %loadsql_commands) {
+       system($loadsql,$command,
+              '--dsn',$pgsql->dsn,
+              @options,
+              @{$loadsql_commands{$command}}) == 0 or
+                  die "Unable to load $command";
+    }
+}
+
+
+=item update_postgresql_database
+
+C<update_postgresql_database();>
+
+Update the postgresql database by calling debbugs-loadsql appropriately.
+
+=cut
+sub update_postgresql_database {
+    my ($pgsql,@options) = @_;
+    my $loadsql =
+       File::Spec->rel2abs(dirname(__FILE__).'/../..').
+           '/bin/debbugs-loadsql';
+
+    my %loadsql_commands =
+       (bugs_and_logs => [],
+       );
+    for my $command (keys %loadsql_commands) {
+       system($loadsql,$command,
+              '--dsn',$pgsql->dsn,
+              @options,
+              @{$loadsql_commands{$command}}) == 0 or
+                  die "Unable to load $command";
+    }
+}
+
+
 
 1;