mirror of
https://github.com/phpbb/phpbb.git
synced 2025-06-07 20:08:53 +00:00
Merge branch 'develop-olympus' into develop
* develop-olympus: [task/refactor-db-testcase] Further improve error messages. [task/refactor-db-testcase] Do not show db password on connect error [task/refactor-db-testcase] Improve error message of db tests [task/refactor-db-testcase] Refactor phpbb_database_test_case
This commit is contained in:
commit
bd51bbda4e
3 changed files with 359 additions and 273 deletions
|
@ -34,3 +34,4 @@ $class_loader->register();
|
|||
require_once 'test_framework/phpbb_test_case_helpers.php';
|
||||
require_once 'test_framework/phpbb_test_case.php';
|
||||
require_once 'test_framework/phpbb_database_test_case.php';
|
||||
require_once 'test_framework/phpbb_database_test_connection_manager.php';
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_TestCase
|
||||
{
|
||||
private static $already_connected;
|
||||
static private $already_connected;
|
||||
|
||||
protected $test_case_helpers;
|
||||
|
||||
|
@ -38,66 +38,6 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test
|
|||
return $this->test_case_helpers;
|
||||
}
|
||||
|
||||
public function get_dbms_data($dbms)
|
||||
{
|
||||
$available_dbms = array(
|
||||
'firebird' => array(
|
||||
'SCHEMA' => 'firebird',
|
||||
'DELIM' => ';;',
|
||||
'PDO' => 'firebird',
|
||||
),
|
||||
'mysqli' => array(
|
||||
'SCHEMA' => 'mysql_41',
|
||||
'DELIM' => ';',
|
||||
'PDO' => 'mysql',
|
||||
),
|
||||
'mysql' => array(
|
||||
'SCHEMA' => 'mysql',
|
||||
'DELIM' => ';',
|
||||
'PDO' => 'mysql',
|
||||
),
|
||||
'mssql' => array(
|
||||
'SCHEMA' => 'mssql',
|
||||
'DELIM' => 'GO',
|
||||
'PDO' => 'odbc',
|
||||
),
|
||||
'mssql_odbc'=> array(
|
||||
'SCHEMA' => 'mssql',
|
||||
'DELIM' => 'GO',
|
||||
'PDO' => 'odbc',
|
||||
),
|
||||
'mssqlnative' => array(
|
||||
'SCHEMA' => 'mssql',
|
||||
'DELIM' => 'GO',
|
||||
'PDO' => 'sqlsrv',
|
||||
),
|
||||
'oracle' => array(
|
||||
'SCHEMA' => 'oracle',
|
||||
'DELIM' => '/',
|
||||
'PDO' => 'oci',
|
||||
),
|
||||
'postgres' => array(
|
||||
'SCHEMA' => 'postgres',
|
||||
'DELIM' => ';',
|
||||
'PDO' => 'pgsql',
|
||||
),
|
||||
'sqlite' => array(
|
||||
'SCHEMA' => 'sqlite',
|
||||
'DELIM' => ';',
|
||||
'PDO' => 'sqlite2',
|
||||
),
|
||||
);
|
||||
|
||||
if (isset($available_dbms[$dbms]))
|
||||
{
|
||||
return $available_dbms[$dbms];
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error('Database unsupported', E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public function get_database_config()
|
||||
{
|
||||
if (isset($_SERVER['PHPBB_TEST_DBMS']))
|
||||
|
@ -142,232 +82,26 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE: This function is not the same as split_sql_file from functions_install
|
||||
public function split_sql_file($sql, $dbms)
|
||||
{
|
||||
$dbms_data = $this->get_dbms_data($dbms);
|
||||
|
||||
$sql = str_replace("\r" , '', $sql);
|
||||
$data = preg_split('/' . preg_quote($dbms_data['DELIM'], '/') . '$/m', $sql);
|
||||
|
||||
$data = array_map('trim', $data);
|
||||
|
||||
// The empty case
|
||||
$end_data = end($data);
|
||||
|
||||
if (empty($end_data))
|
||||
{
|
||||
unset($data[key($data)]);
|
||||
}
|
||||
|
||||
if ($dbms == 'sqlite')
|
||||
{
|
||||
// remove comment lines starting with # - they are not proper sqlite
|
||||
// syntax and break sqlite2
|
||||
foreach ($data as $i => $query)
|
||||
{
|
||||
$data[$i] = preg_replace('/^#.*$/m', "\n", $query);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of all tables from the database.
|
||||
*
|
||||
* @param PDO $pdo
|
||||
* @param string $dbms
|
||||
* @return array(string)
|
||||
*/
|
||||
function get_tables($pdo, $dbms)
|
||||
{
|
||||
switch ($pdo)
|
||||
{
|
||||
case 'mysql':
|
||||
case 'mysql4':
|
||||
case 'mysqli':
|
||||
$sql = 'SHOW TABLES';
|
||||
break;
|
||||
|
||||
case 'sqlite':
|
||||
$sql = 'SELECT name
|
||||
FROM sqlite_master
|
||||
WHERE type = "table"';
|
||||
break;
|
||||
|
||||
case 'mssql':
|
||||
case 'mssql_odbc':
|
||||
case 'mssqlnative':
|
||||
$sql = "SELECT name
|
||||
FROM sysobjects
|
||||
WHERE type='U'";
|
||||
break;
|
||||
|
||||
case 'postgres':
|
||||
$sql = 'SELECT relname
|
||||
FROM pg_stat_user_tables';
|
||||
break;
|
||||
|
||||
case 'firebird':
|
||||
$sql = 'SELECT rdb$relation_name
|
||||
FROM rdb$relations
|
||||
WHERE rdb$view_source is null
|
||||
AND rdb$system_flag = 0';
|
||||
break;
|
||||
|
||||
case 'oracle':
|
||||
$sql = 'SELECT table_name
|
||||
FROM USER_TABLES';
|
||||
break;
|
||||
}
|
||||
|
||||
$result = $pdo->query($sql);
|
||||
|
||||
$tables = array();
|
||||
while ($row = $result->fetch(PDO::FETCH_NUM))
|
||||
{
|
||||
$tables[] = current($row);
|
||||
}
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a PDO connection for the configured database.
|
||||
*
|
||||
* @param array $config The database configuration
|
||||
* @param array $dbms Information on the used DBMS.
|
||||
* @param bool $use_db Whether the DSN should be tied to a
|
||||
* particular database making it impossible
|
||||
* to delete that database.
|
||||
* @return PDO The PDO database connection.
|
||||
*/
|
||||
public function new_pdo($config, $dbms, $use_db)
|
||||
{
|
||||
$dsn = $dbms['PDO'] . ':';
|
||||
|
||||
switch ($dbms['PDO'])
|
||||
{
|
||||
case 'sqlite2':
|
||||
$dsn .= $config['dbhost'];
|
||||
break;
|
||||
|
||||
case 'sqlsrv':
|
||||
// prefix the hostname (or DSN) with Server= so using just (local)\SQLExpress
|
||||
// works for example, further parameters can still be appended using ;x=y
|
||||
$dsn .= 'Server=';
|
||||
// no break -> rest like ODBC
|
||||
case 'odbc':
|
||||
// for ODBC assume dbhost is a suitable DSN
|
||||
// e.g. Driver={SQL Server Native Client 10.0};Server=(local)\SQLExpress;
|
||||
$dsn .= $config['dbhost'];
|
||||
|
||||
if ($use_db)
|
||||
{
|
||||
$dsn .= ';Database=' . $config['dbname'];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$dsn .= 'host=' . $config['dbhost'];
|
||||
|
||||
if ($use_db)
|
||||
{
|
||||
$dsn .= ';dbname=' . $config['dbname'];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$pdo = new PDO($dsn, $config['dbuser'], $config['dbpasswd']);;
|
||||
|
||||
// good for debug
|
||||
// $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
private function recreate_db($config, $dbms)
|
||||
{
|
||||
switch ($config['dbms'])
|
||||
{
|
||||
case 'sqlite':
|
||||
if (file_exists($config['dbhost']))
|
||||
{
|
||||
unlink($config['dbhost']);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$pdo = $this->new_pdo($config, $dbms, false);
|
||||
|
||||
try
|
||||
{
|
||||
$pdo->exec('DROP DATABASE ' . $config['dbname']);
|
||||
}
|
||||
catch (PDOException $e)
|
||||
{
|
||||
// try to delete all tables if dropping the database was not possible.
|
||||
foreach ($this->get_tables() as $table)
|
||||
{
|
||||
try
|
||||
{
|
||||
$pdo->exec('DROP TABLE ' . $table);
|
||||
}
|
||||
catch (PDOException $e){} // ignore non-existent tables
|
||||
}
|
||||
}
|
||||
|
||||
$pdo->exec('CREATE DATABASE ' . $config['dbname']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function load_schema($pdo, $config, $dbms)
|
||||
{
|
||||
if ($config['dbms'] == 'mysql')
|
||||
{
|
||||
$sth = $pdo->query('SELECT VERSION() AS version');
|
||||
$row = $sth->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (version_compare($row['version'], '4.1.3', '>='))
|
||||
{
|
||||
$dbms['SCHEMA'] .= '_41';
|
||||
}
|
||||
else
|
||||
{
|
||||
$dbms['SCHEMA'] .= '_40';
|
||||
}
|
||||
}
|
||||
|
||||
$sql = $this->split_sql_file(file_get_contents(dirname(__FILE__) . "/../../phpBB/install/schemas/{$dbms['SCHEMA']}_schema.sql"), $config['dbms']);
|
||||
|
||||
foreach ($sql as $query)
|
||||
{
|
||||
$pdo->exec($query);
|
||||
}
|
||||
}
|
||||
|
||||
public function getConnection()
|
||||
{
|
||||
$config = $this->get_database_config();
|
||||
$dbms = $this->get_dbms_data($config['dbms']);
|
||||
|
||||
$manager = $this->create_connection_manager($config);
|
||||
|
||||
if (!self::$already_connected)
|
||||
{
|
||||
$this->recreate_db($config, $dbms);
|
||||
$manager->recreate_db();
|
||||
}
|
||||
|
||||
$pdo = $this->new_pdo($config, $dbms, true);
|
||||
$manager->connect();
|
||||
|
||||
if (!self::$already_connected)
|
||||
{
|
||||
$this->load_schema($pdo, $config, $dbms);
|
||||
|
||||
$manager->load_schema();
|
||||
self::$already_connected = true;
|
||||
}
|
||||
|
||||
return $this->createDefaultDBConnection($pdo, 'testdb');
|
||||
return $this->createDefaultDBConnection($manager->get_pdo(), 'testdb');
|
||||
}
|
||||
|
||||
public function new_dbal()
|
||||
|
@ -399,4 +133,9 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test
|
|||
{
|
||||
$this->get_test_case_helpers()->setExpectedTriggerError($errno, $message);
|
||||
}
|
||||
|
||||
protected function create_connection_manager($config)
|
||||
{
|
||||
return new phpbb_database_test_connection_manager($config);
|
||||
}
|
||||
}
|
||||
|
|
346
tests/test_framework/phpbb_database_test_connection_manager.php
Normal file
346
tests/test_framework/phpbb_database_test_connection_manager.php
Normal file
|
@ -0,0 +1,346 @@
|
|||
<?php
|
||||
/**
|
||||
*
|
||||
* @package testing
|
||||
* @copyright (c) 2011 phpBB Group
|
||||
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
|
||||
*
|
||||
*/
|
||||
|
||||
class phpbb_database_test_connection_manager
|
||||
{
|
||||
private $config;
|
||||
private $dbms;
|
||||
private $pdo;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $config Tests database configuration as returned by
|
||||
* phpbb_database_test_case::get_database_config()
|
||||
*/
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->dbms = $this->get_dbms_data($this->config['dbms']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current PDO instance
|
||||
*/
|
||||
public function get_pdo()
|
||||
{
|
||||
return $this->pdo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PDO connection for the configured database.
|
||||
*
|
||||
* @param bool $use_db Whether the DSN should be tied to a
|
||||
* particular database making it impossible
|
||||
* to delete that database.
|
||||
*/
|
||||
public function connect($use_db = true)
|
||||
{
|
||||
$dsn = $this->dbms['PDO'] . ':';
|
||||
|
||||
switch ($this->dbms['PDO'])
|
||||
{
|
||||
case 'sqlite2':
|
||||
$dsn .= $this->config['dbhost'];
|
||||
break;
|
||||
|
||||
case 'sqlsrv':
|
||||
// prefix the hostname (or DSN) with Server= so using just (local)\SQLExpress
|
||||
// works for example, further parameters can still be appended using ;x=y
|
||||
$dsn .= 'Server=';
|
||||
// no break -> rest like ODBC
|
||||
case 'odbc':
|
||||
// for ODBC assume dbhost is a suitable DSN
|
||||
// e.g. Driver={SQL Server Native Client 10.0};Server=(local)\SQLExpress;
|
||||
$dsn .= $this->config['dbhost'];
|
||||
|
||||
if ($use_db)
|
||||
{
|
||||
$dsn .= ';Database=' . $this->config['dbname'];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$dsn .= 'host=' . $this->config['dbhost'];
|
||||
|
||||
if ($use_db)
|
||||
{
|
||||
$dsn .= ';dbname=' . $this->config['dbname'];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$this->pdo = new PDO($dsn, $this->config['dbuser'], $this->config['dbpasswd']);
|
||||
}
|
||||
catch (PDOException $e)
|
||||
{
|
||||
$cleaned_dsn = str_replace($this->config['dbpasswd'], '*password*', $dsn);
|
||||
throw new Exception("Unable do connect to $cleaned_dsn using PDO with error: {$e->getMessage()}");
|
||||
}
|
||||
|
||||
// good for debug
|
||||
// $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the phpBB database schema into the database
|
||||
*/
|
||||
public function load_schema()
|
||||
{
|
||||
$this->ensure_connected(__METHOD__);
|
||||
|
||||
$directory = dirname(__FILE__) . '/../../phpBB/install/schemas/';
|
||||
$this->load_schema_from_file($directory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop the database if it exists and re-create it
|
||||
*
|
||||
* Note: This does not load the schema, and it is suggested
|
||||
* to re-connect after calling to get use_db isolation.
|
||||
*/
|
||||
public function recreate_db()
|
||||
{
|
||||
switch ($this->config['dbms'])
|
||||
{
|
||||
case 'sqlite':
|
||||
if (file_exists($this->config['dbhost']))
|
||||
{
|
||||
unlink($this->config['dbhost']);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->connect(false);
|
||||
|
||||
try
|
||||
{
|
||||
$this->pdo->exec('DROP DATABASE ' . $config['dbname']);
|
||||
}
|
||||
catch (PDOException $e)
|
||||
{
|
||||
// try to delete all tables if dropping the database was not possible.
|
||||
foreach ($this->get_tables() as $table)
|
||||
{
|
||||
$this->pdo->exec('DROP TABLE ' . $table);
|
||||
}
|
||||
}
|
||||
|
||||
$this->pdo->exec('CREATE DATABASE ' . $this->config['dbname']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of all tables from the database.
|
||||
*
|
||||
* @return array(string)
|
||||
*/
|
||||
public function get_tables()
|
||||
{
|
||||
$this->ensure_connected(__METHOD__);
|
||||
|
||||
switch ($this->config['dbms'])
|
||||
{
|
||||
case 'mysql':
|
||||
case 'mysql4':
|
||||
case 'mysqli':
|
||||
$sql = 'SHOW TABLES';
|
||||
break;
|
||||
|
||||
case 'sqlite':
|
||||
$sql = 'SELECT name
|
||||
FROM sqlite_master
|
||||
WHERE type = "table"';
|
||||
break;
|
||||
|
||||
case 'mssql':
|
||||
case 'mssql_odbc':
|
||||
case 'mssqlnative':
|
||||
$sql = "SELECT name
|
||||
FROM sysobjects
|
||||
WHERE type='U'";
|
||||
break;
|
||||
|
||||
case 'postgres':
|
||||
$sql = 'SELECT relname
|
||||
FROM pg_stat_user_tables';
|
||||
break;
|
||||
|
||||
case 'firebird':
|
||||
$sql = 'SELECT rdb$relation_name
|
||||
FROM rdb$relations
|
||||
WHERE rdb$view_source is null
|
||||
AND rdb$system_flag = 0';
|
||||
break;
|
||||
|
||||
case 'oracle':
|
||||
$sql = 'SELECT table_name
|
||||
FROM USER_TABLES';
|
||||
break;
|
||||
}
|
||||
|
||||
$result = $this->pdo->query($sql);
|
||||
|
||||
$tables = array();
|
||||
while ($row = $result->fetch(PDO::FETCH_NUM))
|
||||
{
|
||||
$tables[] = current($row);
|
||||
}
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception if not connected
|
||||
*/
|
||||
protected function ensure_connected($method_name)
|
||||
{
|
||||
if (null === $this->pdo)
|
||||
{
|
||||
throw new Exception(sprintf('You must connect before calling %s', $method_name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the correct schema filename (as per create_schema_files) and
|
||||
* load it into the database.
|
||||
*/
|
||||
protected function load_schema_from_file($directory)
|
||||
{
|
||||
$schema = $this->dbms['SCHEMA'];
|
||||
|
||||
if ($this->config['dbms'] == 'mysql')
|
||||
{
|
||||
$sth = $this->pdo->query('SELECT VERSION() AS version');
|
||||
$row = $sth->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (version_compare($row['version'], '4.1.3', '>='))
|
||||
{
|
||||
$schema .= '_41';
|
||||
}
|
||||
else
|
||||
{
|
||||
$schema .= '_40';
|
||||
}
|
||||
}
|
||||
|
||||
$filename = $directory . $schema . '_schema.sql';
|
||||
$sql = $this->split_sql(file_get_contents($filename));
|
||||
|
||||
foreach ($sql as $query)
|
||||
{
|
||||
$this->pdo->exec($query);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Split contents of an SQL file into an array of SQL statements
|
||||
*
|
||||
* Note: This method is not the same as split_sql_file from functions_install.
|
||||
*
|
||||
* @param string $sql Raw contents of an SQL file
|
||||
*
|
||||
* @return Array of runnable SQL statements
|
||||
*/
|
||||
protected function split_sql($sql)
|
||||
{
|
||||
$sql = str_replace("\r" , '', $sql);
|
||||
$data = preg_split('/' . preg_quote($this->dbms['DELIM'], '/') . '$/m', $sql);
|
||||
|
||||
$data = array_map('trim', $data);
|
||||
|
||||
// The empty case
|
||||
$end_data = end($data);
|
||||
|
||||
if (empty($end_data))
|
||||
{
|
||||
unset($data[key($data)]);
|
||||
}
|
||||
|
||||
if ($this->config['dbms'] == 'sqlite')
|
||||
{
|
||||
// remove comment lines starting with # - they are not proper sqlite
|
||||
// syntax and break sqlite2
|
||||
foreach ($data as $i => $query)
|
||||
{
|
||||
$data[$i] = preg_replace('/^#.*$/m', "\n", $query);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a phpBB dbms driver name to dbms data array
|
||||
*/
|
||||
protected function get_dbms_data($dbms)
|
||||
{
|
||||
$available_dbms = array(
|
||||
'firebird' => array(
|
||||
'SCHEMA' => 'firebird',
|
||||
'DELIM' => ';;',
|
||||
'PDO' => 'firebird',
|
||||
),
|
||||
'mysqli' => array(
|
||||
'SCHEMA' => 'mysql_41',
|
||||
'DELIM' => ';',
|
||||
'PDO' => 'mysql',
|
||||
),
|
||||
'mysql' => array(
|
||||
'SCHEMA' => 'mysql',
|
||||
'DELIM' => ';',
|
||||
'PDO' => 'mysql',
|
||||
),
|
||||
'mssql' => array(
|
||||
'SCHEMA' => 'mssql',
|
||||
'DELIM' => 'GO',
|
||||
'PDO' => 'odbc',
|
||||
),
|
||||
'mssql_odbc'=> array(
|
||||
'SCHEMA' => 'mssql',
|
||||
'DELIM' => 'GO',
|
||||
'PDO' => 'odbc',
|
||||
),
|
||||
'mssqlnative' => array(
|
||||
'SCHEMA' => 'mssql',
|
||||
'DELIM' => 'GO',
|
||||
'PDO' => 'sqlsrv',
|
||||
),
|
||||
'oracle' => array(
|
||||
'SCHEMA' => 'oracle',
|
||||
'DELIM' => '/',
|
||||
'PDO' => 'oci',
|
||||
),
|
||||
'postgres' => array(
|
||||
'SCHEMA' => 'postgres',
|
||||
'DELIM' => ';',
|
||||
'PDO' => 'pgsql',
|
||||
),
|
||||
'sqlite' => array(
|
||||
'SCHEMA' => 'sqlite',
|
||||
'DELIM' => ';',
|
||||
'PDO' => 'sqlite2',
|
||||
),
|
||||
);
|
||||
|
||||
if (isset($available_dbms[$dbms]))
|
||||
{
|
||||
return $available_dbms[$dbms];
|
||||
}
|
||||
else
|
||||
{
|
||||
$message = "Supplied dbms \"$dbms\" is not a valid phpBB dbms, must be one of: ";
|
||||
$message .= implode(', ', array_keys($available_dbms));
|
||||
throw new Exception($message);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue