NAME

DBD::Informix::TestHarness - Test Harness for DBD::Informix

SYNOPSIS

use DBD::Informix::TestHarness;

DESCRIPTION

This document describes DBD::Informix::TestHarness distributed with IBM Informix Database Driver for Perl Version 2003.03.0401 (2003-03-04). This is pure Perl code which exploits DBI and DBD::Informix to make it easier to write tests. Most notably, it provides a simple mechanism to connect to the user's chosen test database and a uniform set of reporting mechanisms.

Loading DBD::Informix::TestHarness

To use the DBD::Informix::TestHarness software, you need to load the DBI software and then install the Informix driver:

use DBD::Informix::TestHarness;

Connecting to test database

$dbh = &connect_to_test_database({ AutoCommit => 0 });

This gives you a reference to the database connection handle, aka the database handle. If the load fails, your program stops immediately. The functionality available from this handle is documented in the DBD::Informix manual page. This function does not report success when it succeeds because the test scripts for blobs, for example, need to know whether they are working with an OnLine system before reporting how many tests will be run.

This code exploits 3 environment variables:

DBD_INFORMIX_DATABASE
DBD_INFORMIX_USERNAME
DBD_INFORMIX_PASSWORD

The database variable can be simply the name of the database, or it can be 'database@server', or it can be one of the SE notations such as '/opt/dbase' or '//hostname/dbase'. If INFORMIXSERVER is not set, then you had better be on a 5.0x system as otherwise the connection will fail. With 6.00 and above, you can optionally specify a user name and password in the environment. This is horribly insecure -- do not use it for production work. The test scripts do not print the password.

Using connect_to_primary

The method connect_to_primary takes a flag (0 implies quietly, 1 implies noisily) and a set of attributes, and connects to the primary database.

$dbh = &connect_to_primary(1, { AutoCommit => 0 });

Using connect_to_secondary

The method connect_to_secondary takes a flag (0 implies quietly, 1 implies noisily) and a set of attributes, and connects to the secondary database.

$dbh = &connect_to_secondary(1, { AutoCommit => 0 });

Using connect_to_tertiary

The method connect_to_tertiary takes a flag (0 implies quietly, 1 implies noisily) and a set of attributes, and connects to the tertiary database.

$dbh = &connect_to_tertiary(1, { AutoCommit => 0 });

Using cleanup_database

If the test needs a clean database to work with, the cleanup_database method removes any tables, views, synonyms (or IUS types) created by the DBD::Informix test suite. These are all identified by the 'dbd_ix_' prefix.

&cleanup_database($dbh);

This is not used in all tests by any stretch of the imagination. In fact, the only test to use it routinely is t/t99clean.t. Whereever possible, tests should use temporary tables.

Using test_for_ius

If the test explicitly requires Informix Universal Server (IUS) or IDS/UDO (Informix Dynamic Server with Universal Data Option -- essentially the product as IUS, but with a longer, more recent, name), then the mechanism to use is:

my ($dbh) = &test_for_ius();

If this returns, then the ESQL/C is capable of handling IUS data types, the database connection worked, and the database server is capable of handling IUS data types.

Using is_shared_memory_connection

You cannot have multiple simultaneous connections if both connections use shared memory connectivity. The multiple connection tests try to determine whether both test databases have shared memory connections. This Unix-centric test provides such a test and allows the tests to report that 'skipping test on this platform'.

if (&is_shared_memory_connection($dbase1)) { ... }

Using stmt_test

Once you have a database connection, you can execute simple statements (those which do not return any data) using &stmt_test():

&stmt_test($dbh, $stmt, $flag, $tag);

The first argument is the database handle. The second is a string containing the statement to be executed. The third is optional and is a boolean. If it is 0, then the statement must execute without causing an error or the test will terminate. If it is set to 1, then the statement may fail and the error will be reported but the test will continue. The fourth argument is an optional string which will be used as a tag before the statement when it is printed. If omitted, it defaults to "Test".

Using stmt_retest

The &stmt_retest() function takes three arguments, which have the same meaning as the first three arguments of &stmt_test():

&stmt_retest($dbh, $stmt, $flag);

It calls:

&stmt_test($dbh, $stmt, 0, "Retest");

Using print_sqlca

The &print_sqlca() function takes a single argument which can be either a statement handle or a database handle and prints out the current values of the SQLCA record.

&print_sqlca($dbh);
&print_sqlca($sth);

Using print_dbinfo

The &print_dbinfo() function takes a single argument which should be a database handle and prints out salient information about the database.

&print_dbinfo($dbh);

Using all_ok

The &all_ok() function can be used at the end of a test script to report whether everything was OK. It exits with status 0 if everything was OK, and with status 1 if not.

&all_ok();

Using stmt_counter

This function returns the current test counter (without altering it). It is most frequently used when the number of tests cannot be told in advance.

$n = &stmt_counter;

Using stmt_ok

The stmt_ok function adds 'ok N' to the end of a line. The N increments automatically each time stmt_ok() or stmt_nok() is called. If called with a non-false argument, it prints the contents of DBI::errstr as a warning message too. This routine is used both internally and more generally in the tests.

&stmt_ok(0);

Using stmt_nok

The stmt_nok function adds 'not ok N' to the end of a line. The N is incremented automatically, as with stmt_ok(). This routine is used both internally and more generally in the tests. It takes an optional string as an argument, which is printed as well.

&stmt_nok();
&stmt_nok("Reason why test failed");

Using stmt_fail

This routine calls stmt_nok, reports the error using stmt_err, and confesses where the failure occurs as it dies. This routine is used (too) extensively, both internally and in the main test scripts. It takes an optional string as an argument, which is printed as well.

&stmt_fail();
&stmt_fail("Reason why test failed");

Note that because this terminates the test abrubtly, it means that all subsequent tests after the one that really failed are deemed to fail. This is often sensible because the subsequent tests depend on the current test to succeed and it is not possible to get good results if this test fails. Nevertheless, whereever possible, the test script should continue after a failure.

Using stmt_err

This routines prints a caption (defaulting to 'Error Message') and the contents of DBI::errstr, ensuring that each line is prefixed by "# ". This routine is used internally by the DBD::Informix::TestHarness module, but is also available for your use.

&stmt_err('Warning Message');

Using stmt_note

This routine writes a string (without any newline unless you include it). This routine is used internally by stmt_test() but is also available for your use.

&stmt_note("Some string or other");

Using stmt_comment

This routine writes a string (prepending hash symbols to line and appending a newline if necessary). This routine is used internally by stmt_test() but is also available for your use.

&stmt_comment("Some string or other");

Using date_as_string

This routine takes one to four arguments:

my($date) = &date_as_string($dbh [, $mm [, $dd [, $yyyy]]]);

The first argument is the database handle. The optional second argument is the month number (1..12). The optional third argument is the day number (1..31). The optional fourth argument is the year number (1..9999). If the date values are omitted, then values from 1930-10-20 are substituted. No direct validation is done; if the conversion operations fail, stmt_fail is called. The date value is converted to a string by the database server, and the result returned to the calling function. The string can be enclosed in quotes and will be accepted by the server as a valid date.

Note: the code assumes that the database server supports the '||' string concatenation operator; this is believed to be valid for OnLine 5.00 and above, and DBD::Informix does not support earlier server versions so it is immaterial that it won't work with them.

Using select_zero_data

The select_zero_data function takes a database handle and the text of a SELECT statement and ensures that no data is returned. The test passes unless any data is returned.

&select_zero_data($dbh, $stmt);

Using memory_leak_test

This routine takes a reference to a subroutine, and optionally a nap time in seconds (default 5) and a ps command string (default "ps -lp", suitable for Solaris 2.x and Solaris 7).

Normally, your test script will simply call this routine and 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.

use strict;
use DBD::Informix::TestHarness;
&memory_leak_test(\&test_subroutine);
exit;

When it is called, memory_leak_test forks, and the parent process runs the given subroutine with no arguments. The subroutine will do the sequence of database operations which show that there is a memory leak, or that the memory leak is fixed. The child process checks that the parent is still alive, and runs the ps command to determine the size of the process. The output of ps is not parsed, so you have to run the test in a verbose mode to see whether there is a memory leak or not.

&memory_leak_test(\&test_subroutine);
&memory_leak_test(\&test_subroutine, 10, "ps -l | grep");

The ps command string has a process number appended to the end after a space, and should report the size of the given process. Note that the last example is not as reliable as requesting the process status of a specific process number; it will probably show the grep command and the child Perl process, and maybe random other processes.

Using connect_controllably

The connect_controllably function is primarily used by the explicit connect_to_primary, connect_to_secondary, connect_to_tertiary, functions, but is also used in its own right.

$dbh = connect_controllably(1, {PrintError=>1}, \&tertiary_connection);

It takes 3 arguments: a verbose flag (true or false), a reference to the connection attributes, if any, and a reference to a function such as primary_connection which returns a database name, username and password. It uses these to connect to the database, logs the connection as a successful test (or dies completely), and returns the database handle.

Using primary_connection

The primary_connection function returns three values, the database name, the username and the password for the primary test connection. This is used internally by the connect_controllably function, and hence by the connect_to_test_database function.

my ($dbase, $user, $pass) = &primary_connection();
my ($dbh) = DBI->connect("dbi:Informix:$dbase", $user, $pass)
                or die "$DBI::errstr\n";

In looking for the three values, it examines the environment variables DBD_INFORMIX_DATABASE, DBD_INFORMIX_USERNAME and DBD_INFORMIX_PASSWORD. If the database is not determined, it looks at the DBI_DBNAME environment variable (which is essentially obsolete as far as DBI is concerned, but which is documented by the esqltest code -- an alternative was to remove support for DBI_DBNAME from esqltest.ec). If DBI_DBNAME is not set, then the default database name is 'stores' with no version suffix. If the username and password are not set, then empty strings are returned.

Using secondary_connection

The secondary_connection function also returns three values, the database name, the username and the password for the secondary test connection. This is used in the multiple connection tests.

my ($dbase, $user, $pass) = &secondary_connection();
my ($dbh) = DBI->connect("dbi:Informix:$dbase", $user, $pass)
                or die "$DBI::errstr\n";

In looking for the three values, it examines the environment variables DBD_INFORMIX_DATABASE2, DBD_INFORMIX_USERNAME2 and DBD_INFORMIX_PASSWORD2. If the database is not determined, it uses the primary_connection method above to specify the values.

Using tertiary_connection

The tertiary_connection function also returns three values, the database name, the username and the password for the tertiary test connection. This is used in the multiple connection tests.

my ($dbase, $user, $pass) = &tertiary_connection();
my ($dbh) = DBI->connect("dbi:Informix:$dbase", $user, $pass)
                or die "$DBI::errstr\n";

In looking for the three values, it examines the environment variables DBD_INFORMIX_DATABASE3, DBD_INFORMIX_USERNAME3 and DBD_INFORMIX_PASSWORD3. If the database is not determined, it uses the primary_connection method above to specify the values.

Using validate_unordered_unique_data

The validate_unordered_unique_data function is used to ensure that exactly the correct data is returned from a cursor-like statement handle which has already had the $sth->execute method executed on it.

The data in $val is a hash indexed by the key value containing the expected values for each column corresponding to the key value:-

&validate_unordered_unique_data($sth, $keycol, \%expected);

&validate_unordered_unique_data($sth, 'c1',
    {
        'c1-value1' => { 'c1' => 'c1-value1', 'c2' => 'c2-value1', 'c3' => 'c3-value1' },
        'c1-value2' => { 'c1' => 'c1-value1', 'c2' => 'c2-value2', 'c3' => 'c3-value2' },
    });

Note that the key (c1) and expected value (c1-value1) are repeated in the data for each row; this is a consistency check that the function enforces.

This function assumes that each row in result set is supposed to appear exactly once. Any extra result rows are erroneous; any missing result rows are erroneous. Any missing columns are erroneous; any extra columns are erroneous. The results from fetchrow_hashref() must be unambiguous, meaning that each selected column must have a unique name. The key data must be a single column.

This routine (or its hypothetical relatives such as validate_ordered_unique_data, validate_unordered_duplicate_data, and validate_ordered_duplicate_data) should be used to ensure that the correct results are returned. Note that there might not be any need for separate routine for unique and duplicate ordered data.

Using set_verbosity

The set_verbosity function takes a value 0, 1 or 2 and sets the verbosity of the validate_* functions accordingly.

&set_verbosity(0);

Note

All these routines can also be used without parentheses or the &, so that the following is also valid:

select_zero_data $dbh, $stmt;

AUTHOR

At various times:

  • Jonathan Leffler (johnl@informix.com) # obsolete email address

  • Jonathan Leffler (j.leffler@acm.org)

  • Jonathan Leffler (jleffler@informix.com) # obsolete email address

  • Jonathan Leffler (jleffler@us.ibm.com)

SEE ALSO

perl(1), DBD::Informix