Skip to content
This repository has been archived by the owner on Aug 20, 2018. It is now read-only.

Commit

Permalink
Add support for shared databases
Browse files Browse the repository at this point in the history
Now you can setup new option to 'shareDatabase:yes' and in this case new database will be created but will NOT be deleted after test case. This means that database is shared with one thread. There will be up to 8 databases in case you are using 8 threads. Default behavior is "always create and delete database" therefore it's without BC break:

testbench:
    shareDatabase: no

Related PR: #38
Close issue #37
  • Loading branch information
mrtnzlml committed Oct 9, 2016
1 parent e42fefb commit 41ba977
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 16 deletions.
7 changes: 4 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
],
"require": {
"php": ">=5.6.0",
"kdyby/fake-session": "^2.0",
"nette/application": "^2.4",
"nette/bootstrap": "^2.4",
"nette/di": "^2.4",
"nette/tester": "2.0.x-dev as v1.7",
"nette/safe-stream": "^2.3",
"nette/security": "^2.4",
"nette/utils": "^2.4",
"kdyby/fake-session": "^2.0"
"nette/tester": "2.0.x-dev as v1.7",
"nette/utils": "^2.4"
},
"require-dev": {
"latte/latte": "^2.4",
Expand Down
37 changes: 37 additions & 0 deletions src/DatabasesRegistry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Testbench;

class DatabasesRegistry
{

private $dataFile;

public function __construct()
{
$this->dataFile = 'nette.safe://' . \Testbench\Bootstrap::$tempDir . '/../databases.testbench';
}

/**
* @return TRUE if registration successful or FALSE if database record already exists
*/
public function registerDatabase($databaseName)
{
if (file_exists($this->dataFile)) {
$data = file_get_contents($this->dataFile);
} else {
$data = '';
}

if (!preg_match('~' . $databaseName . '~', $data)) { //database doesn't exist in log file
$handle = fopen($this->dataFile, 'a+');
fwrite($handle, $databaseName . "\n");
fclose($handle);

return TRUE;
} else { //database already exists in log file
return FALSE;
}
}

}
34 changes: 29 additions & 5 deletions src/Mocks/DoctrineConnectionMock.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,19 @@ public function __construct(
return;
}
try {
$this->__testbench_database_setup($connection, $container);
$config = $container->parameters['testbench'];
if ($config['shareDatabase'] === TRUE) {
$registry = new \Testbench\DatabasesRegistry;
$dbName = $container->parameters['testbench']['dbprefix'] . getenv(\Tester\Environment::THREAD);
if ($registry->registerDatabase($dbName)) {
$this->__testbench_database_setup($connection, $container, TRUE);
} else {
$this->__testbench_databaseName = $dbName;
$this->__testbench_database_change($connection, $container);
}
} else { // always create new test database
$this->__testbench_database_setup($connection, $container);
}
} catch (\Exception $e) {
\Tester\Assert::fail($e->getMessage());
}
Expand All @@ -45,7 +57,7 @@ public function __construct(
}

/** @internal */
public function __testbench_database_setup($connection, \Nette\DI\Container $container)
public function __testbench_database_setup($connection, \Nette\DI\Container $container, $persistent = FALSE)
{
$config = $container->parameters['testbench'];
$this->__testbench_databaseName = $config['dbprefix'] . getenv(\Tester\Environment::THREAD);
Expand All @@ -68,9 +80,11 @@ public function __testbench_database_setup($connection, \Nette\DI\Container $con
}
}

register_shutdown_function(function () use ($connection, $container) {
$this->__testbench_database_drop($connection, $container);
});
if ($persistent === FALSE) {
register_shutdown_function(function () use ($connection, $container) {
$this->__testbench_database_drop($connection, $container);
});
}
}

/**
Expand All @@ -81,6 +95,16 @@ public function __testbench_database_setup($connection, \Nette\DI\Container $con
public function __testbench_database_create($connection, \Nette\DI\Container $container)
{
$connection->exec("CREATE DATABASE {$this->__testbench_databaseName}");
$this->__testbench_database_change($connection, $container);
}

/**
* @internal
*
* @param $connection \Kdyby\Doctrine\Connection
*/
public function __testbench_database_change($connection, \Nette\DI\Container $container)
{
if ($connection->getDatabasePlatform() instanceof MySqlPlatform) {
$connection->exec("USE {$this->__testbench_databaseName}");
} else {
Expand Down
34 changes: 29 additions & 5 deletions src/Mocks/NetteDatabaseConnectionMock.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,19 @@ public function __construct($dsn, $user = NULL, $password = NULL, array $options
return;
}
try {
$this->__testbench_database_setup($connection, $container);
$config = $container->parameters['testbench'];
if ($config['shareDatabase'] === TRUE) {
$registry = new \Testbench\DatabasesRegistry;
$dbName = $container->parameters['testbench']['dbprefix'] . getenv(\Tester\Environment::THREAD);
if ($registry->registerDatabase($dbName)) {
$this->__testbench_database_setup($connection, $container, TRUE);
} else {
$this->__testbench_databaseName = $dbName;
$this->__testbench_database_change($connection, $container);
}
} else { // always create new test database
$this->__testbench_database_setup($connection, $container);
}
} catch (\Exception $e) {
\Tester\Assert::fail($e->getMessage());
}
Expand All @@ -30,7 +42,7 @@ public function __construct($dsn, $user = NULL, $password = NULL, array $options
}

/** @internal */
public function __testbench_database_setup($connection, \Nette\DI\Container $container)
public function __testbench_database_setup($connection, \Nette\DI\Container $container, $persistent = FALSE)
{
$config = $container->parameters['testbench'];
$this->__testbench_databaseName = $config['dbprefix'] . getenv(\Tester\Environment::THREAD);
Expand All @@ -42,9 +54,11 @@ public function __testbench_database_setup($connection, \Nette\DI\Container $con
\Nette\Database\Helpers::loadFromFile($connection, $file);
}

register_shutdown_function(function () use ($connection, $container) {
$this->__testbench_database_drop($connection, $container);
});
if ($persistent === FALSE) {
register_shutdown_function(function () use ($connection, $container) {
$this->__testbench_database_drop($connection, $container);
});
}
}

/**
Expand All @@ -55,6 +69,16 @@ public function __testbench_database_setup($connection, \Nette\DI\Container $con
public function __testbench_database_create($connection, \Nette\DI\Container $container)
{
$connection->query("CREATE DATABASE {$this->__testbench_databaseName}");
$this->__testbench_database_change($connection, $container);
}

/**
* @internal
*
* @param $connection \Nette\Database\Connection
*/
public function __testbench_database_change($connection, \Nette\DI\Container $container)
{
if ($connection->getSupplementalDriver() instanceof MySqlDriver) {
$connection->query("USE {$this->__testbench_databaseName}");
} else {
Expand Down
27 changes: 26 additions & 1 deletion src/Providers/IDatabaseProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,40 @@

namespace Testbench\Providers;

/**
* This interface is not stable yet. In fact it's really bad design and it needs refactor (stay tuned).
*/
interface IDatabaseProvider
{

function __testbench_database_setup($connection, \Nette\DI\Container $container);
/**
* Perform complete database setup (should drop and create database, import sqls, run migrations).
* Register shutdown function only if it's not persistent setup.
*/
function __testbench_database_setup($connection, \Nette\DI\Container $container, $persistent = FALSE);

/**
* Drop database.
* This function uses internal '__testbench_databaseName'. Needs refactor!
*/
function __testbench_database_drop($connection, \Nette\DI\Container $container);

/**
* Create new database.
* This function uses internal '__testbench_databaseName'. Needs refactor!
*/
function __testbench_database_create($connection, \Nette\DI\Container $container);

/**
* Connect to the database.
* This function uses internal '__testbench_databaseName'. Needs refactor!
*/
function __testbench_database_connect($connection, \Nette\DI\Container $container, $databaseName = NULL);

/**
* Change database as quickly as possible (USE in MySQL, connect in PostgreSQL).
* This function uses internal '__testbench_databaseName'. Needs refactor!
*/
function __testbench_database_change($connection, \Nette\DI\Container $container);

}
3 changes: 2 additions & 1 deletion src/TestbenchExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ class TestbenchExtension extends \Nette\DI\CompilerExtension
{

private $defaults = [
'dbname' => NULL, // custom test database name
'dbname' => NULL, // custom initial test database name (should not be needed)
'dbprefix' => '_testbench_', // database prefix for created tests databases
'migrations' => FALSE, // set TRUE if you want to use Doctrine migrations
'shareDatabase' => FALSE, // should Testbench always create new databases (FALSE) or use shared databases (TRUE)
'sqls' => [], // sqls you want to import during new test database creation
'url' => 'http://test.bench/', // fake URL for HTTP request mock
];
Expand Down
2 changes: 1 addition & 1 deletion tests/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
tests.local.neon
_temp/
**/output/
tests.log
databases.testbench
2 changes: 2 additions & 0 deletions tests/tests.local.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ migrations:
testbench:
url: http://test.bench/
migrations: yes
shareDatabase: no
dbprefix: _testbench_
sqls:
- %testsDir%/_helpers/sqls/mysql_1.sql
- %testsDir%/_helpers/sqls/mysql_2.sql
Expand Down

0 comments on commit 41ba977

Please sign in to comment.