From a167ca249128c2b2ed3d6522f43b112268ac6f00 Mon Sep 17 00:00:00 2001 From: Joshua Waihi Date: Tue, 4 Jan 2011 22:57:12 +1300 Subject: [PATCH 1/5] adding tests to DBTNG (indepentant of Drupal) --- settings.php | 157 +++++++++ tests/DBTNG_PHPUnit_Framework_TestCase.php | 10 + tests/schema.test | 386 +++++++++++++++++++++ 3 files changed, 553 insertions(+) create mode 100644 settings.php create mode 100644 tests/DBTNG_PHPUnit_Framework_TestCase.php create mode 100644 tests/schema.test diff --git a/settings.php b/settings.php new file mode 100644 index 0000000..4d6eec1 --- /dev/null +++ b/settings.php @@ -0,0 +1,157 @@ + 'mysql', + * 'database' => 'databasename', + * 'username' => 'username', + * 'password' => 'password', + * 'host' => 'localhost', + * 'port' => 3306, + * 'prefix' => 'myprefix_', + * 'collation' => 'utf8_general_ci', + * ); + * @endcode + * + * The "driver" property indicates what DBTNG driver the connection + * should use. This is usually the same as the name of the database + * type, such as mysql or sqlite, but not always. The other + * properties will vary depending on the driver. For SQLite, you must + * specify a database file name in a directory that is writable by the + * webserver. For most other drivers, you must specify a + * username, password, host, and database name. + * + * Some database engines support transactions. In order to enable + * transaction support for a given database, set the 'transactions' key + * to TRUE. To disable it, set it to FALSE. Note that the default value + * varies by driver. For MySQL, the default is FALSE since MyISAM tables + * do not support transactions. + * + * For each database, you may optionally specify multiple "target" databases. + * A target database allows DBTNG to try to send certain queries to a + * different database if it can but fall back to the default connection if not. + * That is useful for master/slave replication, as DBTNG may try to connect + * to a slave server when appropriate and if one is not available will simply + * fall back to the single master server. + * + * The general format for the $databases array is as follows: + * @code + * $databases['default']['default'] = $info_array; + * $databases['default']['slave'][] = $info_array; + * $databases['default']['slave'][] = $info_array; + * $databases['extra']['default'] = $info_array; + * @endcode + * + * In the above example, $info_array is an array of settings described above. + * The first line sets a "default" database that has one master database + * (the second level default). The second and third lines create an array + * of potential slave databases. DBTNG will select one at random for a given + * request as needed. The fourth line creates a new database with a name of + * "extra". + * + * For a single database configuration, the following is sufficient: + * @code + * $databases['default']['default'] = array( + * 'driver' => 'mysql', + * 'database' => 'databasename', + * 'username' => 'username', + * 'password' => 'password', + * 'host' => 'localhost', + * 'prefix' => 'main_', + * 'collation' => 'utf8_general_ci', + * ); + * @endcode + * + * You can optionally set prefixes for some or all database table names + * by using the 'prefix' setting. If a prefix is specified, the table + * name will be prepended with its value. Be sure to use valid database + * characters only, usually alphanumeric and underscore. If no prefixes + * are desired, leave it as an empty string ''. + * + * To have all database names prefixed, set 'prefix' as a string: + * @code + * 'prefix' => 'main_', + * @endcode + * To provide prefixes for specific tables, set 'prefix' as an array. + * The array's keys are the table names and the values are the prefixes. + * The 'default' element is mandatory and holds the prefix for any tables + * not specified elsewhere in the array. Example: + * @code + * 'prefix' => array( + * 'default' => 'main_', + * 'users' => 'shared_', + * 'sessions' => 'shared_', + * 'role' => 'shared_', + * 'authmap' => 'shared_', + * ), + * @endcode + * You can also use a reference to a schema/database as a prefix. This maybe + * useful if your DBTNG installation exists in a schema that is not the default + * or you want to access several databases from the same code base at the same + * time. + * Example: + * @code + * 'prefix' => array( + * 'default' => 'main.', + * 'users' => 'shared.', + * 'sessions' => 'shared.', + * 'role' => 'shared.', + * 'authmap' => 'shared.', + * ); + * @endcode + * NOTE: MySQL and SQLite's definition of a schema is a database. + * + * Database configuration format: + * @code + * $databases['default']['default'] = array( + * 'driver' => 'mysql', + * 'database' => 'databasename', + * 'username' => 'username', + * 'password' => 'password', + * 'host' => 'localhost', + * 'prefix' => '', + * ); + * $databases['default']['default'] = array( + * 'driver' => 'pgsql', + * 'database' => 'databasename', + * 'username' => 'username', + * 'password' => 'password', + * 'host' => 'localhost', + * 'prefix' => '', + * ); + * $databases['default']['default'] = array( + * 'driver' => 'sqlite', + * 'database' => '/path/to/databasefilename', + * ); + * @endcode + */ + +global $databases; + +$databases['default']['default'] = array( + 'driver' => 'pgsql', + 'database' => 'drupal7', + 'username' => 'drupal', + 'host' => 'localhost', + 'prefix' => '', +); + +if (!function_exists('t')) { + function t($text, $vars = array()) { + return strtr($text, $vars); + } +} + +define('DBTNG_DIR', dirname(__FILE__)); + +include_once DBTNG_DIR . '/database.inc'; diff --git a/tests/DBTNG_PHPUnit_Framework_TestCase.php b/tests/DBTNG_PHPUnit_Framework_TestCase.php new file mode 100644 index 0000000..7b93ce9 --- /dev/null +++ b/tests/DBTNG_PHPUnit_Framework_TestCase.php @@ -0,0 +1,10 @@ + 'Schema API', + 'description' => 'Tests table creation and modification via the schema API.', + 'group' => 'Database', + ); + } + + /** + * + */ + function testSchema() { + // Try creating a table. + $table_specification = array( + 'description' => 'Schema table description.', + 'fields' => array( + 'id' => array( + 'type' => 'int', + 'default' => NULL, + ), + 'test_field' => array( + 'type' => 'int', + 'not null' => TRUE, + 'description' => 'Schema column description.', + ), + ), + ); + db_create_table('test_table', $table_specification); + + // Assert that the table exists. + $this->assertTrue(db_table_exists('test_table'), t('The table exists.')); + + // Assert that the table comment has been set. + $this->checkSchemaComment($table_specification['description'], 'test_table'); + + // Assert that the column comment has been set. + $this->checkSchemaComment($table_specification['fields']['test_field']['description'], 'test_table', 'test_field'); + + // An insert without a value for the column 'test_table' should fail. + $this->assertFalse($this->tryInsert(), t('Insert without a default failed.')); + + // Add a default value to the column. + db_field_set_default('test_table', 'test_field', 0); + // The insert should now succeed. + $this->assertTrue($this->tryInsert(), t('Insert with a default succeeded.')); + + // Remove the default. + db_field_set_no_default('test_table', 'test_field'); + // The insert should fail again. + $this->assertFalse($this->tryInsert(), t('Insert without a default failed.')); + + // Test for fake index and test for the boolean result of indexExists(). + $index_exists = Database::getConnection()->schema()->indexExists('test_table', 'test_field'); + $this->assertIdentical($index_exists, FALSE, t('Fake index does not exists')); + // Add index. + db_add_index('test_table', 'test_field', array('test_field')); + // Test for created index and test for the boolean result of indexExists(). + $index_exists = Database::getConnection()->schema()->indexExists('test_table', 'test_field'); + $this->assertIdentical($index_exists, TRUE, t('Index created.')); + + // Rename the table. + db_rename_table('test_table', 'test_table2'); + + // Index should be renamed. + $index_exists = Database::getConnection()->schema()->indexExists('test_table2', 'test_field'); + $this->assertTrue($index_exists, t('Index was renamed.')); + + // We need the default so that we can insert after the rename. + db_field_set_default('test_table2', 'test_field', 0); + $this->assertFalse($this->tryInsert(), t('Insert into the old table failed.')); + $this->assertTrue($this->tryInsert('test_table2'), t('Insert into the new table succeeded.')); + + // We should have successfully inserted exactly two rows. + $count = db_query('SELECT COUNT(*) FROM {test_table2}')->fetchField(); + $this->assertEqual($count, 2, t('Two fields were successfully inserted.')); + + // Try to drop the table. + db_drop_table('test_table2'); + $this->assertFalse(db_table_exists('test_table2'), t('The dropped table does not exist.')); + + // Recreate the table. + db_create_table('test_table', $table_specification); + db_field_set_default('test_table', 'test_field', 0); + db_add_field('test_table', 'test_serial', array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'description' => 'Added column description.')); + + // Assert that the column comment has been set. + $this->checkSchemaComment('Added column description.', 'test_table', 'test_serial'); + + // Change the new field to a serial column. + db_change_field('test_table', 'test_serial', 'test_serial', array('type' => 'serial', 'not null' => TRUE, 'description' => 'Changed column description.'), array('primary key' => array('test_serial'))); + + // Assert that the column comment has been set. + $this->checkSchemaComment('Changed column description.', 'test_table', 'test_serial'); + + $this->assertTrue($this->tryInsert(), t('Insert with a serial succeeded.')); + $max1 = db_query('SELECT MAX(test_serial) FROM {test_table}')->fetchField(); + $this->assertTrue($this->tryInsert(), t('Insert with a serial succeeded.')); + $max2 = db_query('SELECT MAX(test_serial) FROM {test_table}')->fetchField(); + $this->assertTrue($max2 > $max1, t('The serial is monotone.')); + + $count = db_query('SELECT COUNT(*) FROM {test_table}')->fetchField(); + $this->assertEqual($count, 2, t('There were two rows.')); + + // Use database specific data type and ensure that table is created. + $table_specification = array( + 'description' => 'Schema table description.', + 'fields' => array( + 'timestamp' => array( + 'mysql_type' => 'timestamp', + 'pgsql_type' => 'timestamp', + 'sqlite_type' => 'datetime', + 'not null' => FALSE, + 'default' => NULL, + ), + ), + ); + try { + db_create_table('test_timestamp', $table_specification); + } + catch (Exception $e) {} + $this->assertTrue(db_table_exists('test_timestamp'), t('Table with database specific datatype was created.')); + } + + function tryInsert($table = 'test_table') { + try { + db_insert($table) + ->fields(array('id' => mt_rand(10, 20))) + ->execute(); + return TRUE; + } + catch (Exception $e) { + return FALSE; + } + } + + /** + * Checks that a table or column comment matches a given description. + * + * @param $description + * The asserted description. + * @param $table + * The table to test. + * @param $column + * Optional column to test. + */ + function checkSchemaComment($description, $table, $column = NULL) { + if (method_exists(Database::getConnection()->schema(), 'getComment')) { + $comment = Database::getConnection()->schema()->getComment($table, $column); + $this->assertEqual($comment, $description, t('The comment matches the schema description.')); + } + } + + /** + * Tests creating unsigned columns and data integrity thereof. + */ + function testUnsignedColumns() { + // First create the table with just a serial column. + $table_name = 'unsigned_table'; + $table_spec = array( + 'fields' => array('serial_column' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE)), + 'primary key' => array('serial_column'), + ); + $ret = array(); + db_create_table($table_name, $table_spec); + + // Now set up columns for the other types. + $types = array('int', 'float', 'numeric'); + foreach ($types as $type) { + $column_spec = array('type' => $type, 'unsigned'=> TRUE); + if ($type == 'numeric') { + $column_spec += array('precision' => 10, 'scale' => 0); + } + $column_name = $type . '_column'; + $table_spec['fields'][$column_name] = $column_spec; + db_add_field($table_name, $column_name, $column_spec); + } + + // Finally, check each column and try to insert invalid values into them. + foreach ($table_spec['fields'] as $column_name => $column_spec) { + $this->assertTrue(db_field_exists($table_name, $column_name), t('Unsigned @type column was created.', array('@type' => $column_spec['type']))); + $this->assertFalse($this->tryUnsignedInsert($table_name, $column_name), t('Unsigned @type column rejected a negative value.', array('@type' => $column_spec['type']))); + } + } + + /** + * Tries to insert a negative value into columns defined as unsigned. + * + * @param $table_name + * The table to insert + * @param $column_name + * The column to insert + * @return + * TRUE if the insert succeeded, FALSE otherwise + */ + function tryUnsignedInsert($table_name, $column_name) { + try { + db_insert($table_name) + ->fields(array($column_name => -1)) + ->execute(); + return TRUE; + } + catch (Exception $e) { + return FALSE; + } + } + + /** + * Test adding columns to an existing table. + */ + function testSchemaAddField() { + // Test varchar types. + foreach (array(1, 32, 128, 256, 512) as $length) { + $base_field_spec = array( + 'type' => 'varchar', + 'length' => $length, + ); + $variations = array( + array('not null' => FALSE), + array('not null' => FALSE, 'default' => '7'), + array('not null' => TRUE, 'initial' => 'd'), + array('not null' => TRUE, 'initial' => 'd', 'default' => '7'), + ); + + foreach ($variations as $variation) { + $field_spec = $variation + $base_field_spec; + $this->assertFieldAdditionRemoval($field_spec); + } + } + + // Test int and float types. + foreach (array('int', 'float') as $type) { + foreach (array('tiny', 'small', 'medium', 'normal', 'big') as $size) { + $base_field_spec = array( + 'type' => $type, + 'size' => $size, + ); + $variations = array( + array('not null' => FALSE), + array('not null' => FALSE, 'default' => 7), + array('not null' => TRUE, 'initial' => 1), + array('not null' => TRUE, 'initial' => 1, 'default' => 7), + ); + + foreach ($variations as $variation) { + $field_spec = $variation + $base_field_spec; + $this->assertFieldAdditionRemoval($field_spec); + } + } + } + + // Test numeric types. + foreach (array(1, 5, 10, 40, 65) as $precision) { + foreach (array(0, 2, 10, 30) as $scale) { + if ($precision <= $scale) { + // Precision must be smaller then scale. + continue; + } + + $base_field_spec = array( + 'type' => 'numeric', + 'scale' => $scale, + 'precision' => $precision, + ); + $variations = array( + array('not null' => FALSE), + array('not null' => FALSE, 'default' => 7), + array('not null' => TRUE, 'initial' => 1), + array('not null' => TRUE, 'initial' => 1, 'default' => 7), + ); + + foreach ($variations as $variation) { + $field_spec = $variation + $base_field_spec; + $this->assertFieldAdditionRemoval($field_spec); + } + } + } + } + + /** + * Assert that a given field can be added and removed from a table. + * + * The addition test covers both defining a field of a given specification + * when initially creating at table and extending an existing table. + * + * @param $field_spec + * The schema specification of the field. + */ + protected function assertFieldAdditionRemoval($field_spec) { + // Try creating the field on a new table. + $table_name = 'test_table_' . ($this->counter++); + $table_spec = array( + 'fields' => array( + 'serial_column' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE), + 'test_field' => $field_spec, + ), + 'primary key' => array('serial_column'), + ); + db_create_table($table_name, $table_spec); + $this->pass(t('Table %table created.', array('%table' => $table_name))); + + // Check the characteristics of the field. + $this->assertFieldCharacteristics($table_name, 'test_field', $field_spec); + + // Clean-up. + db_drop_table($table_name); + + // Try adding a field to an existing table. + $table_name = 'test_table_' . ($this->counter++); + $table_spec = array( + 'fields' => array( + 'serial_column' => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE), + ), + 'primary key' => array('serial_column'), + ); + db_create_table($table_name, $table_spec); + $this->pass(t('Table %table created.', array('%table' => $table_name))); + + // Insert some rows to the table to test the handling of initial values. + for ($i = 0; $i < 3; $i++) { + db_insert($table_name) + ->useDefaults(array('serial_column')) + ->execute(); + } + + db_add_field($table_name, 'test_field', $field_spec); + $this->pass(t('Column %column created.', array('%column' => 'test_field'))); + + // Check the characteristics of the field. + $this->assertFieldCharacteristics($table_name, 'test_field', $field_spec); + + // Clean-up. + db_drop_field($table_name, 'test_field'); + db_drop_table($table_name); + } + + /** + * Assert that a newly added field has the correct characteristics. + */ + protected function assertFieldCharacteristics($table_name, $field_name, $field_spec) { + // Check that the initial value has been registered. + if (isset($field_spec['initial'])) { + // There should be no row with a value different then $field_spec['initial']. + $count = db_select($table_name) + ->fields($table_name, array('serial_column')) + ->condition($field_name, $field_spec['initial'], '<>') + ->countQuery() + ->execute() + ->fetchField(); + $this->assertEqual($count, 0, t('Initial values filled out.')); + } + + // Check that the default value has been registered. + if (isset($field_spec['default'])) { + // Try inserting a row, and check the resulting value of the new column. + $id = db_insert($table_name) + ->useDefaults(array('serial_column')) + ->execute(); + $field_value = db_select($table_name) + ->fields($table_name, array($field_name)) + ->condition('serial_column', $id) + ->execute() + ->fetchField(); + $this->assertEqual($field_value, $field_spec['default'], t('Default value registered.')); + } + + db_drop_field($table_name, $field_name); + } +} From 5cfacefeb396448f24c630118dbe396f020d4277 Mon Sep 17 00:00:00 2001 From: Joshua Waihi Date: Tue, 4 Jan 2011 22:58:18 +1300 Subject: [PATCH 2/5] make DBTNG independent of DRUPAL_ROOT --- database.inc | 2 +- sqlite/database.inc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/database.inc b/database.inc index b384afe..5f76970 100644 --- a/database.inc +++ b/database.inc @@ -1569,7 +1569,7 @@ abstract class Database { // We cannot rely on the registry yet, because the registry requires an // open database connection. $driver_class = 'DatabaseConnection_' . $driver; - require_once DRUPAL_ROOT . '/includes/database/' . $driver . '/database.inc'; + require_once DBTNG_DIR . '/' . $driver . '/database.inc'; $new_connection = new $driver_class(self::$databaseInfo[$key][$target]); $new_connection->setTarget($target); $new_connection->setKey($key); diff --git a/sqlite/database.inc b/sqlite/database.inc index 651efa2..d29715d 100644 --- a/sqlite/database.inc +++ b/sqlite/database.inc @@ -11,7 +11,7 @@ * @{ */ -include_once DRUPAL_ROOT . '/includes/database/prefetch.inc'; +include_once DBTNG_DIR . '/prefetch.inc'; /** * Specific SQLite implementation of DatabaseConnection. From 28ddfd47f66e08f6b34aafc7912454517c9b6eb8 Mon Sep 17 00:00:00 2001 From: Joshua Waihi Date: Tue, 4 Jan 2011 23:08:56 +1300 Subject: [PATCH 3/5] removing Drupal terminology so PHPUnit works on schema.test --- tests/schema.test | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/schema.test b/tests/schema.test index 13490d6..fdda005 100644 --- a/tests/schema.test +++ b/tests/schema.test @@ -69,12 +69,12 @@ class SchemaTestCase extends DBTNG_PHPUnit_Framework_TestCase { // Test for fake index and test for the boolean result of indexExists(). $index_exists = Database::getConnection()->schema()->indexExists('test_table', 'test_field'); - $this->assertIdentical($index_exists, FALSE, t('Fake index does not exists')); + $this->assertSame($index_exists, FALSE, t('Fake index does not exists')); // Add index. db_add_index('test_table', 'test_field', array('test_field')); // Test for created index and test for the boolean result of indexExists(). $index_exists = Database::getConnection()->schema()->indexExists('test_table', 'test_field'); - $this->assertIdentical($index_exists, TRUE, t('Index created.')); + $this->assertSame($index_exists, TRUE, t('Index created.')); // Rename the table. db_rename_table('test_table', 'test_table2'); @@ -90,7 +90,7 @@ class SchemaTestCase extends DBTNG_PHPUnit_Framework_TestCase { // We should have successfully inserted exactly two rows. $count = db_query('SELECT COUNT(*) FROM {test_table2}')->fetchField(); - $this->assertEqual($count, 2, t('Two fields were successfully inserted.')); + $this->assertEquals($count, 2, t('Two fields were successfully inserted.')); // Try to drop the table. db_drop_table('test_table2'); @@ -117,7 +117,7 @@ class SchemaTestCase extends DBTNG_PHPUnit_Framework_TestCase { $this->assertTrue($max2 > $max1, t('The serial is monotone.')); $count = db_query('SELECT COUNT(*) FROM {test_table}')->fetchField(); - $this->assertEqual($count, 2, t('There were two rows.')); + $this->assertEquals($count, 2, t('There were two rows.')); // Use database specific data type and ensure that table is created. $table_specification = array( @@ -164,7 +164,7 @@ class SchemaTestCase extends DBTNG_PHPUnit_Framework_TestCase { function checkSchemaComment($description, $table, $column = NULL) { if (method_exists(Database::getConnection()->schema(), 'getComment')) { $comment = Database::getConnection()->schema()->getComment($table, $column); - $this->assertEqual($comment, $description, t('The comment matches the schema description.')); + $this->assertEquals($comment, $description, t('The comment matches the schema description.')); } } @@ -314,7 +314,8 @@ class SchemaTestCase extends DBTNG_PHPUnit_Framework_TestCase { 'primary key' => array('serial_column'), ); db_create_table($table_name, $table_spec); - $this->pass(t('Table %table created.', array('%table' => $table_name))); + // Assert that the table exists. + $this->assertTrue(db_table_exists($table_name), t('Table %table created.', array('%table' => $table_name))); // Check the characteristics of the field. $this->assertFieldCharacteristics($table_name, 'test_field', $field_spec); @@ -331,7 +332,8 @@ class SchemaTestCase extends DBTNG_PHPUnit_Framework_TestCase { 'primary key' => array('serial_column'), ); db_create_table($table_name, $table_spec); - $this->pass(t('Table %table created.', array('%table' => $table_name))); + // Assert that the table exists. + $this->assertTrue(db_table_exists($table_name), t('Table %table created.', array('%table' => $table_name))); // Insert some rows to the table to test the handling of initial values. for ($i = 0; $i < 3; $i++) { @@ -341,7 +343,7 @@ class SchemaTestCase extends DBTNG_PHPUnit_Framework_TestCase { } db_add_field($table_name, 'test_field', $field_spec); - $this->pass(t('Column %column created.', array('%column' => 'test_field'))); + //$this->pass(t('Column %column created.', array('%column' => 'test_field'))); // Check the characteristics of the field. $this->assertFieldCharacteristics($table_name, 'test_field', $field_spec); @@ -364,7 +366,7 @@ class SchemaTestCase extends DBTNG_PHPUnit_Framework_TestCase { ->countQuery() ->execute() ->fetchField(); - $this->assertEqual($count, 0, t('Initial values filled out.')); + $this->assertEquals($count, 0, t('Initial values filled out.')); } // Check that the default value has been registered. @@ -378,7 +380,7 @@ class SchemaTestCase extends DBTNG_PHPUnit_Framework_TestCase { ->condition('serial_column', $id) ->execute() ->fetchField(); - $this->assertEqual($field_value, $field_spec['default'], t('Default value registered.')); + $this->assertEquals($field_value, $field_spec['default'], t('Default value registered.')); } db_drop_field($table_name, $field_name); From 2e4a7572d2ebda1231a6e444ed3812eba8d0376a Mon Sep 17 00:00:00 2001 From: Joshua Waihi Date: Wed, 5 Jan 2011 09:06:24 +1300 Subject: [PATCH 4/5] removed drupal function from DBTNG --- pgsql/schema.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pgsql/schema.inc b/pgsql/schema.inc index 30f12ef..2fee2c7 100644 --- a/pgsql/schema.inc +++ b/pgsql/schema.inc @@ -223,7 +223,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema { // Set the correct database-engine specific datatype. // In case one is already provided, force it to lowercase. if (isset($field['pgsql_type'])) { - $field['pgsql_type'] = drupal_strtolower($field['pgsql_type']); + $field['pgsql_type'] = strtolower($field['pgsql_type']); } else { $map = $this->getFieldTypeMap(); From 80bccf2e323f8965fa4e5021783dd40dc7fcb95d Mon Sep 17 00:00:00 2001 From: Joshua Waihi Date: Wed, 9 Mar 2011 16:24:20 -0600 Subject: [PATCH 5/5] added a "default.settings.php" and made schema.test work! --- default.settings.php | 157 +++++++++++++++++++++ tests/DBTNG_PHPUnit_Framework_TestCase.php | 30 ++++ tests/README.txt | 9 ++ tests/schema.test | 8 -- 4 files changed, 196 insertions(+), 8 deletions(-) create mode 100644 default.settings.php create mode 100644 tests/README.txt diff --git a/default.settings.php b/default.settings.php new file mode 100644 index 0000000..13afcfe --- /dev/null +++ b/default.settings.php @@ -0,0 +1,157 @@ + 'mysql', + * 'database' => 'databasename', + * 'username' => 'username', + * 'password' => 'password', + * 'host' => 'localhost', + * 'port' => 3306, + * 'prefix' => 'myprefix_', + * 'collation' => 'utf8_general_ci', + * ); + * @endcode + * + * The "driver" property indicates what DBTNG driver the connection + * should use. This is usually the same as the name of the database + * type, such as mysql or sqlite, but not always. The other + * properties will vary depending on the driver. For SQLite, you must + * specify a database file name in a directory that is writable by the + * webserver. For most other drivers, you must specify a + * username, password, host, and database name. + * + * Some database engines support transactions. In order to enable + * transaction support for a given database, set the 'transactions' key + * to TRUE. To disable it, set it to FALSE. Note that the default value + * varies by driver. For MySQL, the default is FALSE since MyISAM tables + * do not support transactions. + * + * For each database, you may optionally specify multiple "target" databases. + * A target database allows DBTNG to try to send certain queries to a + * different database if it can but fall back to the default connection if not. + * That is useful for master/slave replication, as DBTNG may try to connect + * to a slave server when appropriate and if one is not available will simply + * fall back to the single master server. + * + * The general format for the $databases array is as follows: + * @code + * $databases['default']['default'] = $info_array; + * $databases['default']['slave'][] = $info_array; + * $databases['default']['slave'][] = $info_array; + * $databases['extra']['default'] = $info_array; + * @endcode + * + * In the above example, $info_array is an array of settings described above. + * The first line sets a "default" database that has one master database + * (the second level default). The second and third lines create an array + * of potential slave databases. DBTNG will select one at random for a given + * request as needed. The fourth line creates a new database with a name of + * "extra". + * + * For a single database configuration, the following is sufficient: + * @code + * $databases['default']['default'] = array( + * 'driver' => 'mysql', + * 'database' => 'databasename', + * 'username' => 'username', + * 'password' => 'password', + * 'host' => 'localhost', + * 'prefix' => 'main_', + * 'collation' => 'utf8_general_ci', + * ); + * @endcode + * + * You can optionally set prefixes for some or all database table names + * by using the 'prefix' setting. If a prefix is specified, the table + * name will be prepended with its value. Be sure to use valid database + * characters only, usually alphanumeric and underscore. If no prefixes + * are desired, leave it as an empty string ''. + * + * To have all database names prefixed, set 'prefix' as a string: + * @code + * 'prefix' => 'main_', + * @endcode + * To provide prefixes for specific tables, set 'prefix' as an array. + * The array's keys are the table names and the values are the prefixes. + * The 'default' element is mandatory and holds the prefix for any tables + * not specified elsewhere in the array. Example: + * @code + * 'prefix' => array( + * 'default' => 'main_', + * 'users' => 'shared_', + * 'sessions' => 'shared_', + * 'role' => 'shared_', + * 'authmap' => 'shared_', + * ), + * @endcode + * You can also use a reference to a schema/database as a prefix. This maybe + * useful if your DBTNG installation exists in a schema that is not the default + * or you want to access several databases from the same code base at the same + * time. + * Example: + * @code + * 'prefix' => array( + * 'default' => 'main.', + * 'users' => 'shared.', + * 'sessions' => 'shared.', + * 'role' => 'shared.', + * 'authmap' => 'shared.', + * ); + * @endcode + * NOTE: MySQL and SQLite's definition of a schema is a database. + * + * Database configuration format: + * @code + * $databases['default']['default'] = array( + * 'driver' => 'mysql', + * 'database' => 'databasename', + * 'username' => 'username', + * 'password' => 'password', + * 'host' => 'localhost', + * 'prefix' => '', + * ); + * $databases['default']['default'] = array( + * 'driver' => 'pgsql', + * 'database' => 'databasename', + * 'username' => 'username', + * 'password' => 'password', + * 'host' => 'localhost', + * 'prefix' => '', + * ); + * $databases['default']['default'] = array( + * 'driver' => 'sqlite', + * 'database' => '/path/to/databasefilename', + * ); + * @endcode + */ + +global $databases; + +$databases['default']['default'] = array( + 'driver' => 'pgsql', + 'database' => 'dbtng', + 'username' => 'drupal', + 'host' => 'localhost', + 'prefix' => '', +); + +if (!function_exists('t')) { + function t($text, $vars = array()) { + return strtr($text, $vars); + } +} + +define('DBTNG_DIR', dirname(__FILE__)); + +include_once DBTNG_DIR . '/database.inc'; diff --git a/tests/DBTNG_PHPUnit_Framework_TestCase.php b/tests/DBTNG_PHPUnit_Framework_TestCase.php index 7b93ce9..37be5e7 100644 --- a/tests/DBTNG_PHPUnit_Framework_TestCase.php +++ b/tests/DBTNG_PHPUnit_Framework_TestCase.php @@ -2,9 +2,39 @@ class DBTNG_PHPUnit_Framework_TestCase extends PHPUnit_Framework_TestCase { + protected $databasePrefix; + public function __construct() { + parent::__construct(); $settings = realpath(dirname(__FILE__) . '/../settings.php'); require_once $settings; } + public function setUp() { + $this->databasePrefix = 'dbtngtest' . mt_rand(1000, 1000000); + // Clone the current connection and replace the current prefix. + $connection_info = Database::getConnectionInfo('default'); + Database::renameConnection('default', 'dbtng_original_default'); + foreach ($connection_info as $target => $value) { + $connection_info[$target]['prefix'] = array( + 'default' => $value['prefix']['default'] . $this->databasePrefix, + ); + } + Database::addConnectionInfo('default', 'default', $connection_info['default']); + } + + public function tearDown() { + // This would be better if it were database specific, but for now we'll + // live with information_schema. + $connection_info = Database::getConnectionInfo('default'); + $result = db_query("SELECT table_name FROM information_schema.tables WHERE table_catalog = '" . $connection_info['database'] . "' AND table_schema = 'public'")->fetchAll(); + foreach ($result as $row) { + db_drop_table($row->table_name); + } + + // Get back to the original connection. + Database::removeConnection('default'); + Database::renameConnection('dbtng_original_default', 'default'); + } + } diff --git a/tests/README.txt b/tests/README.txt new file mode 100644 index 0000000..b5fb4cd --- /dev/null +++ b/tests/README.txt @@ -0,0 +1,9 @@ +* DBTNG TEST SUITE * +DBTNG uses PHPUnit to run its test suite. To run the tests +You'll need to first install the phpunit framework. See +http://www.phpunit.de/manual/current/en/installation.html +for more information on installing phpunit. + +Run unit tests by using the phpunit CLI tool: + $ phpunit tests/schema.test + diff --git a/tests/schema.test b/tests/schema.test index fdda005..4821760 100644 --- a/tests/schema.test +++ b/tests/schema.test @@ -16,14 +16,6 @@ class SchemaTestCase extends DBTNG_PHPUnit_Framework_TestCase { */ var $counter; - public static function getInfo() { - return array( - 'name' => 'Schema API', - 'description' => 'Tests table creation and modification via the schema API.', - 'group' => 'Database', - ); - } - /** * */