From c18bdc2d1f1a01de444fad23b46aee830b32c87e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sat, 14 Jan 2012 09:02:24 +0100 Subject: [PATCH] Dirty SQL test system * Added a system that allows "dirty" tests to be written. These tests actually need to change the database, so a temporary test database must be created to run them. --- build/post-build.sh | 7 ++- .../000-dirty-tests-self-check/prepare.sql | 23 +++++++++ .../000-dirty-tests-self-check/run-test.sql | 17 +++++++ .../tests/dirty/run-dirty-tests.sh | 37 +++++++++++++++ legacyworlds/doc/database.txt | 47 +++++++++++++------ 5 files changed, 114 insertions(+), 17 deletions(-) create mode 100644 legacyworlds-server-data/db-structure/tests/dirty/000-dirty-tests-self-check/prepare.sql create mode 100644 legacyworlds-server-data/db-structure/tests/dirty/000-dirty-tests-self-check/run-test.sql create mode 100755 legacyworlds-server-data/db-structure/tests/dirty/run-dirty-tests.sh diff --git a/build/post-build.sh b/build/post-build.sh index 3fb786e..1f9c8fb 100755 --- a/build/post-build.sh +++ b/build/post-build.sh @@ -9,8 +9,8 @@ user=tests password=tests EOF fi -TEST_DATABASE="`grep ^db= db-config.txt | sed -e s/.*=//`" -TEST_USER="`grep ^user= db-config.txt | sed -e s/.*=//`" +export TEST_DATABASE="`grep ^db= db-config.txt | sed -e s/.*=//`" +export TEST_USER="`grep ^user= db-config.txt | sed -e s/.*=//`" echo echo @@ -53,3 +53,6 @@ fi if [ -d user ]; then pg_prove -U $TEST_USER -d $TEST_DATABASE `find user/ -type f -name '*.sql'` || exit 1 fi +if [ -x dirty/run-dirty-tests.sql ]; then + ( cd dirty; exec ./run-dirty-tests.sql ) || exit 1 +fi diff --git a/legacyworlds-server-data/db-structure/tests/dirty/000-dirty-tests-self-check/prepare.sql b/legacyworlds-server-data/db-structure/tests/dirty/000-dirty-tests-self-check/prepare.sql new file mode 100644 index 0000000..d7d0d76 --- /dev/null +++ b/legacyworlds-server-data/db-structure/tests/dirty/000-dirty-tests-self-check/prepare.sql @@ -0,0 +1,23 @@ +/* + * Dirty test system self-check + * + * Insert an address, it should exist during the main test. Also create a + * function and a table which are used to synchronise execution. + */ +BEGIN; + INSERT INTO users.addresses ( address ) + VALUES ( 'prepare@example.org' ); + + CREATE TABLE _barriers( _barrier BIGINT ); + + CREATE FUNCTION _synchronise_tests( _lock BIGINT ) + RETURNS VOID + AS $$ + BEGIN + WHILE pg_try_advisory_lock( _lock ) + LOOP + PERFORM pg_advisory_unlock( _lock ); + END LOOP; + END; + $$ LANGUAGE PLPGSQL; +COMMIT; diff --git a/legacyworlds-server-data/db-structure/tests/dirty/000-dirty-tests-self-check/run-test.sql b/legacyworlds-server-data/db-structure/tests/dirty/000-dirty-tests-self-check/run-test.sql new file mode 100644 index 0000000..6786ab2 --- /dev/null +++ b/legacyworlds-server-data/db-structure/tests/dirty/000-dirty-tests-self-check/run-test.sql @@ -0,0 +1,17 @@ +/* + * Dirty test system self-check + * + * Insert an address, it should exist during the main test. + */ +BEGIN; + SELECT no_plan( ); + + SELECT pg_advisory_lock( 1 ); + + SELECT diag_test_name( 'Dirty test system self-check - prepare.sql was executed' ); + SELECT is( COUNT(*)::INT , 1 ) + FROM users.addresses + WHERE address = 'prepare@example.org'; + + SELECT * FROM finish( ); +ROLLBACK; diff --git a/legacyworlds-server-data/db-structure/tests/dirty/run-dirty-tests.sh b/legacyworlds-server-data/db-structure/tests/dirty/run-dirty-tests.sh new file mode 100755 index 0000000..07f1cf4 --- /dev/null +++ b/legacyworlds-server-data/db-structure/tests/dirty/run-dirty-tests.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +if [ -z "$TEST_DATABASE" ]; then + echo "Missing TEST_DATABASE environment variable" + exit 1; +fi + +echo +echo 'Running "dirty" database tests' +echo + +find -mindepth 1 -maxdepth 1 -type d | sort | while read testdir; do + + [ -f "$testdir/run-test.sql" ] || continue + + echo "Dirty test $testdir" + echo "--------------------------------------------" + echo + + echo "Creating temporary database ..." + echo "DROP DATABASE IF EXISTS dirty_tests; CREATE DATABASE dirty_tests TEMPLATE $TEST_DATABASE;" \ + | psql -vQUIET=1 -vON_ERROR_STOP=1 $TEST_DATABASE || exit 1 + + if [ -f "$testdir/prepare.sql" ]; then + echo "Preparing database ..." + ( cd .. && exec psql -vQUIET=1 -vON_ERROR_STOP=1 --file "dirty/$testdir/prepare.sql" dirty_tests ) || exit 1 + fi + + echo "Running main test ..." + ( cd .. && pg_prove -d dirty_tests dirty/$testdir/run-test.sql ) || exit 1 + + echo "Dropping temporary database ..." + echo -e "DROP DATABASE IF EXISTS dirty_tests;" \ + | psql -vQUIET=1 -vON_ERROR_STOP=1 $TEST_DATABASE || exit 1 + + echo +done diff --git a/legacyworlds/doc/database.txt b/legacyworlds/doc/database.txt index 4d035a4..15ae48e 100644 --- a/legacyworlds/doc/database.txt +++ b/legacyworlds/doc/database.txt @@ -60,22 +60,33 @@ The tests/ sub-directory contains the SQL source code for the pgTAP testing framework as well as the tests themselves. See below for more information. - Unit tests - ---------- +Unit tests +---------- -There are three sub-directories in the tests/ directory. The admin/ directory +There are four sub-directories in the tests/ directory. The admin/ directory contains tests that require administrative permissions on the database (therefore most functionality checks can be found there), while the user/ sub-directory contains unit tests that must be executed as the standard -user (for example privileges checks). Finally, the utils/ sub-directory -contains scripts used by tests from the admin/ directory to create test -data. +user (for example privileges checks). + +The dirty/ sub-directory contains tests which require actual changes to +be committed to the database; while unit tests are not supposed to be executed +on a loaded database anyway, these specific tests could cause problems with +other tests, and therefore run on copies of the database. + +Finally, the utils/ sub-directory contains scripts used by tests from both the +admin/ and dirty/ sub-directories to create test data. -In both directories, files are organised in a manner that is parallel to the -contents of the database creation scripts. For each actual SQL file, a -sub-directory with the same name (minus the ".sql" extension) can be created, -each sub-directory containing the test suites for the definitions and -functions from the corresponding file. +In both the admin/ and user/ directories, files are organised in a manner that +is parallel to the contents of the database creation scripts. For each actual +SQL file, a sub-directory with the same name (minus the ".sql" extension) can +be created, each sub-directory containing the test suites for the definitions +and functions from the corresponding file. + +The dirty/ sub-directory contains a script which can be used to run the +"dirty" test suites, as well as one directory per test suite. Each test suite +directory may contain a "prepare.sql" script, to be executed before the actual +tests, as well as a "run-test.sql" which runs the actual tests. In order to run the database unit tests, the following steps must be taken: @@ -93,14 +104,20 @@ In order to run the database unit tests, the following steps must be taken: 4) The tests/pgtap.sql script must be loaded into the database as the administrative user. -At this point, it becomes possible to launch the test suites by issuing a +At this point, it becomes possible to launch the basic test suites by issuing a command similar to: pg_prove -d $DATABASE -U $USER \ `find $DIR/ -type f -name '*.sql' | sort` where $DATABASE is the name of the database, $USER the name of the user that -will execute the tests and $DIR being either admin or user. +will execute the tests and $DIR being either admin or user. The "dirty" test +suite can be launched by running: + + TEST_DATABASE=$DATABASE ./run-dirty-tests.sh + +Note that the dirty tests will fail unless all existing connections to the +main database are closed. Build system @@ -109,5 +126,5 @@ Build system The build system will attempt to create the database using the scripts. It will stop at the first unsuccessful command. On success, it will proceed to loading pgTAP, then run all available unit tests: first it will execute tests from the -admin/ sub-directory, then tests from the user/ sub-directory. A failure will -cause the build to be aborted. \ No newline at end of file +admin/ sub-directory, then tests from the user/ sub-directory, and finally the +dirty tests. A failure will cause the build to be aborted.