# $Id: TestHarness.pm,v 1.7 2005/04/20 00:34:39 cmungall Exp $
#
# This GO module is maintained by Chris Mungall <cjm@fruitfly.org>
#
# see also - http://www.geneontology.org
#          - http://www.godatabase.org/dev
#
# You may distribute this module under the same terms as perl itself

#   @(#)$Id: TestHarness.pm,v 1.7 2005/04/20 00:34:39 cmungall Exp $
#
#   Test Harness for Gene Ontology modules
#
#   You may distribute under the terms of either the GNU General Public
#   License or the Artistic License, as specified in the Perl README file.

# Exploit this by saying "use GO::TestHarness;"

package GO::TestHarness;
use GO::Admin;

our $CONF = "t/go-test.conf";
our $admin = GO::Admin->new;
$admin->loadp($CONF);


require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(
             dd
             autopass
	     memory_leak_test
	     stmt_err
	     stmt_fail
	     stmt_note
	     stmt_check
	     stmt_ok
	     n_tests
	     set_n_tests
	     get_readonly_apph
	     getapph
	     create_test_database
	     destroy_test_database
		);

use Config;


sub dd {
    use Data::Dumper;
    print Dumper(shift);
}

sub autopass {
    my $n = shift;

    if (!$n) {
        $n = $n_tests - ($ok_counter || 0);
    }
    print "AUTOMATICALLY passing $n remaining subtests (total $n_tests)\n";
#    for (my $i=0; $i<$n; $i++) {
    for (my $i=0; $i<$n_tests; $i++) {
        &stmt_ok;
    }
    exit 0;
}

sub create_test_database {
#    my $name = shift || $ENV{GO_TEST_DATABASE_NAME};
    my $name = $admin->tmpdbname;
    autopass if $ENV{GO_NODBWRITE};
    autopass unless $name;
    eval {
        require "DBIx/DBStag.pm";
    };
    if ($@) {
        print "DBIx::DBStag not installed - skipping db loading tests\n";
        autopass();
    }
    if (system("which xsltproc > /dev/null")) {
        print "xsltproc not installed - skipping db loading tests\n";
        autopass();
    }

    $admin->dbname($name);
    $admin->newdb;
    $admin->load_schema;
    $ENV{GO_TEST_CONNECT_PARAMS} =
      sprintf("%s %s %s",
              ($dbms ? "-dbms $dbms" : ""),
              ($server ? "-dbhost $server" : ""),
              "-dbname $name");
}

sub destroy_test_database {
    $admin->dbname($admin->tmpdbname);
    $admin->dropdb;
}

sub get_readonly_apph {
    $admin->loadp($CONF);
    my @params = (-dbname=>$admin->dbname,
		  -dbhost=>$admin->dbhost,
		 );
    
    require GO::AppHandle;
    my $apph = GO::AppHandle->connect(@params) || die;
    return $apph;
  }

sub getapph {
    $admin->loadp($CONF);
    $admin->dbname($admin->tmpdbname);
    my @params = (-dbname=>$admin->dbname,
		  -dbhost=>$admin->dbhost,
		 );
    require GO::AppHandle;
    my $apph;
    eval {
          $apph = GO::AppHandle->connect(@params);
      };
    if ($@) {
	print "Can't connect using @params - see $@";
	print "will skip this test\n\n";
	autopass;
    }
    return $apph;
  }

our $n_tests = 0;
my $ok_counter = 0;
sub stmt_err
  {
      my ($str) = @_;
      my ($err, $state);
      $str = "Error Message" unless ($str);
      &stmt_note($str);
  }

sub stmt_ok
  {
      my ($warn) = @_;
      $ok_counter++;
      &stmt_note("ok $ok_counter\n");
      &stmt_err("Warning Message") if ($warn);
  }

sub stmt_fail
  {
      my ($warn) = @_;
      &stmt_note($warn) if ($warn);
      $ok_counter++;
      &stmt_note("not ok $ok_counter\n");
      &stmt_err("Error Message");
      die "!! Terminating Test !!\n";
  }

sub all_ok
  {
      &stmt_note("# *** Testing of GO::* complete ***\n");
      &stmt_note("# ***     You appear to be normal!      ***\n");
      exit(0);
  }

sub stmt_note
  {
      print STDOUT @_;
      print STDOUT "\n";
  }

sub n_tests
  {
      my $n = shift;
      $n_tests = $n;
      #print "n tests = $n_tests\n";
      print STDOUT "1..$n\n";
  }
sub set_n_tests
  {
      my $n = shift;
      $n_tests = $n;
  }

sub stmt_check
  {
      my $true;
      if (@_ >1) {
          $true = $_[0] eq $_[1];
          if (!$true) {
              print STDERR "Expected:$_[0], got $_[1]\n";
          }
      }
      else {
          $true = shift;
      }
      if ($true) {
	  stmt_ok;
      }
      else {
	  stmt_fail;
      }
  }

# Run a memory leak test.
# The main program will normally read:
#		use strict;
#		use DBD::Informix::TestHarness;
#		&memory_leak_test(\&test_subroutine);
#		exit;
# The remaining code in the test file will implement a test
# which shows the memory leak.  You should not connect to the
# test database before invoking memory_leak_test.
sub memory_leak_test
  {
      my($sub, $nap, $pscmd) = @_;
      use vars qw($ppid $cpid $nap);
      
      $|=1;
      print "					      # Bug is fixed if size of process stabilizes (fairly quickly!)\n";
      $ppid = $$;
      $nap  = 5 unless defined $nap;
      $pscmd = "ps -lp" unless defined $pscmd;
      $pscmd .= " $ppid";
      
      $cpid = fork();
      die "failed to fork\n" unless (defined $cpid);
      if ($cpid)
	{
	    # Parent
	    print "				      # Parent: $ppid, Child: $cpid\n";
	    # Invoke the subroutine given by reference to do the real database work.
	    &$sub();
	    # Try to ensure that the child gets a chance to report at least once more...
	    sleep ($nap * 2);
	    kill 15, $cpid;
	    exit(0);
	}
      else
	{
	    # Child -- monitor size of parent, while parent exists!
	    system "$pscmd | sed 's/^/		      # /'";
	    sleep $nap;
	    while (kill 0, $ppid)
	      {
		  system "$pscmd | sed -e 1d -e 's/^/ # /'";
		  sleep $nap;
	      }
	}
  }


1;
