Skip to content

Commit

Permalink
Issue 4 Implements the temporary collector.
Browse files Browse the repository at this point in the history
  • Loading branch information
pabloelcolombiano committed Jan 4, 2021
1 parent 3268a45 commit f0a68d4
Show file tree
Hide file tree
Showing 32 changed files with 1,195 additions and 925 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,4 @@ jobs:
if [ ${{ matrix.db-type }} == 'mysql' ]; then
sudo service mysql start && mysql -h 127.0.0.1 -u root -proot -e 'CREATE DATABASE IF NOT EXISTS test_suite_light;';
fi
composer run-tests-${{ matrix.db-type }}
composer ${{ matrix.db-type }}
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@
}
},
"scripts": {
"run-tests-mysql": "bash run_tests.sh Mysql",
"run-tests-pgsql": "bash run_tests.sh Postgres",
"run-tests-sqlite": "bash run_tests.sh Sqlite"
"mysql": "bash run_tests.sh Mysql",
"pgsql": "bash run_tests.sh Postgres",
"sqlite": "bash run_tests.sh Sqlite"
},
"config": {
"sort-packages": true
Expand Down
9 changes: 0 additions & 9 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@
<testsuite name="Default">
<directory>./tests/TestCase/</directory>
</testsuite>
<testsuite name="DropCities">
<file>./tests/DropTablesTestCase/TableSnifferDropCitiesTest.php</file>
</testsuite>
<testsuite name="DropCountries">
<file>./tests/DropTablesTestCase/TableSnifferDropCountriesTest.php</file>
</testsuite>
<testsuite name="DropTables">
<file>./tests/DropTablesTestCase/TableSnifferDropTablesTest.php</file>
</testsuite>
</testsuites>

<!-- Setup a listener for fixtures -->
Expand Down
29 changes: 16 additions & 13 deletions run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@ DRIVER=$1;
echo "Starting PHPUNIT tests"
export DB_DRIVER=$DRIVER

# Test Cases where tables get dropped are put separately,
# since they are giving a hard time to the fixtures
# These can be put all together again once the migrations
# get required in the dependencies
./vendor/bin/phpunit --testsuite Default --stop-on-fail
./vendor/bin/phpunit --testsuite DropCities --stop-on-fail
./vendor/bin/phpunit --testsuite DropCountries --stop-on-fail
./vendor/bin/phpunit --testsuite DropTables --stop-on-fail
#######################
#### Tests with temporary sniffers
#######################
./vendor/bin/phpunit

# Run the tests again using non-triggered based sniffers
#######################
#### Tests with non temporary sniffers
#######################
export SNIFFERS_IN_MAIN_MODE="true"
./vendor/bin/phpunit

#### DEPRECATED #####
# Run the tests using
# non-triggered based sniffers
#####################
export TABLE_SNIFFER="CakephpTestSuiteLight\Sniffer\\${DRIVER}TableSniffer"
export USE_NON_TRIGGERED_BASED_SNIFFERS="true"
./vendor/bin/phpunit

./vendor/bin/phpunit --testsuite Default --stop-on-fail
./vendor/bin/phpunit --testsuite DropCities --stop-on-fail
./vendor/bin/phpunit --testsuite DropCountries --stop-on-fail
./vendor/bin/phpunit --testsuite DropTables --stop-on-fail
7 changes: 6 additions & 1 deletion src/FixtureInjector.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,17 @@ public function startTestSuite(TestSuite $suite)
*/
public function startTest(Test $test)
{
$this->statisticTool->startsTestTime();

// Truncation can be skipped if no DB interaction are expected
if (!$this->skipTablesTruncation($test)) {
$this->_fixtureManager->truncateDirtyTables();
}

$this->statisticTool->startsLoadingFixturesTime();
// Load CakePHP fixtures
parent::startTest($test);
$this->statisticTool->stopsLoadingFixturesTime();

// Run the seeds of your DB
// $this->rollbackAndMigrateIfRequired();
Expand All @@ -82,7 +86,8 @@ public function startTest(Test $test)
*/
public function endTest(Test $test, $time)
{
$this->statisticTool->collectTestStatistics($test, $time);
$this->statisticTool->stopsTestTime();
$this->statisticTool->collectTestStatistics($test);
}

/**
Expand Down
83 changes: 5 additions & 78 deletions src/FixtureManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@
use Cake\Datasource\ConnectionInterface;
use Cake\Datasource\ConnectionManager;
use Cake\TestSuite\Fixture\FixtureManager as BaseFixtureManager;
use CakephpTestSuiteLight\Sniffer\BaseTableSniffer;
use CakephpTestSuiteLight\Sniffer\MysqlTriggerBasedTableSniffer;
use CakephpTestSuiteLight\Sniffer\PostgresTriggerBasedTableSniffer;
use CakephpTestSuiteLight\Sniffer\SqliteTriggerBasedTableSniffer;
use CakephpTestSuiteLight\Sniffer\SnifferRegistry;
use Exception;
use function strpos;

Expand All @@ -35,11 +32,6 @@ class FixtureManager extends BaseFixtureManager
*/
private static $_configIsLoaded = false;

/**
* @var array
*/
private $sniffers = [];

/**
* @var array|null
*/
Expand Down Expand Up @@ -81,66 +73,14 @@ public function aliasConnections()
$this->_aliasConnections();
}

/**
* Each connection has it's own sniffer
*
* @param string $connectionName
* @return BaseTableSniffer
*/
public function getSniffer(string $connectionName): BaseTableSniffer
{
return $this->sniffers[$connectionName] ?? $this->addSniffer($connectionName);
}

/**
* @param string $connectionName
* @return BaseTableSniffer
*/
public function addSniffer(string $connectionName): BaseTableSniffer
{
$snifferName = $this->getConnectionSnifferName($connectionName);

/** @var BaseTableSniffer $sniffer */
$sniffer = new $snifferName($this->getConnection($connectionName));
return $this->sniffers[$connectionName] = $sniffer;
}

/**
* Read in the config the sniffer to use
* @param string $connectionName
* @return string
*/
public function getConnectionSnifferName(string $connectionName): string
{
$config = ConnectionManager::getConfig($connectionName);
$driver = '';

if (isset($config['tableSniffer'])) {
$snifferName = $config['tableSniffer'];
} else {
try {
$driver = $this->getConnection($connectionName)->config()['driver'];
$snifferName = $this->getDefaultTableSniffers()[$driver] ?? null;
if (is_null($snifferName)) {
throw new \RuntimeException();
}
} catch (\RuntimeException $e) {
$msg = "Testsuite light error for connection {$connectionName}. ";
$msg .= "The DB driver {$driver} is not supported or was not found";
throw new \PHPUnit\Framework\Exception($msg);
}
}
return $snifferName;
}

/**
* Scan all test connections and truncate the dirty tables
* @return void
*/
public function truncateDirtyTables()
{
foreach ($this->getActiveConnections() as $connection) {
$this->getSniffer($connection)->truncateDirtyTables();
SnifferRegistry::get($connection)->truncateDirtyTables();
}
}

Expand Down Expand Up @@ -198,27 +138,14 @@ public function loadConfig(): FixtureManager
}

/**
* Table sniffers provided by the package
* @return array
*/
public function getDefaultTableSniffers(): array
{
return [
\Cake\Database\Driver\Mysql::class => MysqlTriggerBasedTableSniffer::class,
\Cake\Database\Driver\Sqlite::class => SqliteTriggerBasedTableSniffer::class,
\Cake\Database\Driver\Postgres::class => PostgresTriggerBasedTableSniffer::class,
];
}

/**
* Get the appropriate truncator and drop all tables
* Get the appropriate sniffer and drop all tables
* @param string $connectionName
* @return void
*/
public function dropTables(string $connectionName)
{
$this->getSniffer($connectionName)->dropTables(
$this->getSniffer($connectionName)->fetchAllTables()
SnifferRegistry::get($connectionName)->dropTables(
SnifferRegistry::get($connectionName)->fetchAllTables()
);
}

Expand Down
82 changes: 35 additions & 47 deletions src/Sniffer/BaseTableSniffer.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@ abstract class BaseTableSniffer
protected $allTables;

/**
* Truncate all the tables found in the dirty table collector
* Truncate all the dirty tables
* @return void
*/
abstract public function truncateDirtyTables();

/**
* Get all the dirty tables
* @return array
*/
abstract public function getDirtyTables(): array;

/**
* List all tables
* @return array
Expand All @@ -54,17 +60,8 @@ abstract public function dropTables(array $tables);
*/
public function __construct(ConnectionInterface $connection)
{
$this->connection = $connection;
$this->setup();
}

/**
* Setup method
* @return void
*/
public function setup()
{
$this->getAllTables(true);
$this->setConnection($connection);
$this->start();
}

/**
Expand All @@ -84,14 +81,33 @@ public function setConnection(ConnectionInterface $connection)
}

/**
* Find all tables where an insert happened
* This also includes empty tables, where a delete
* was performed after an insert
* @return array
* Get the sniffer started
* Typically create the dirty table collector
* Truncate all tables
* Create the spying triggers
* @return void
*/
public function start()
{
$this->getAllTables(true);
}

/**
* Stop spying
* @return void
*/
public function shutdown()
{}

/**
* Stop spying and restart
* Useful if the schema or the
* dirty table collector changed
*/
public function getDirtyTables(): array
public function restart()
{
return $this->fetchQuery("SELECT table_name FROM " . TriggerBasedTableSnifferInterface::DIRTY_TABLE_COLLECTOR);
$this->shutdown();
$this->start();
}

/**
Expand Down Expand Up @@ -136,19 +152,6 @@ public function implodeSpecial(string $glueBefore, array $array, string $glueAft
return $glueBefore . implode($glueAfter.$glueBefore, $array) . $glueAfter;
}

/**
* The dirty table collector should never be dropped
* This method helps removing it from a list of tables
* @param array $tables
* @return void
*/
public function removeDirtyTableCollectorFromArray(array &$tables)
{
if (($key = array_search(TriggerBasedTableSnifferInterface::DIRTY_TABLE_COLLECTOR, $tables)) !== false) {
unset($tables[$key]);
}
}

/**
* Get all tables except the phinx tables
* * @param bool $forceFetch
Expand Down Expand Up @@ -177,27 +180,12 @@ public function getAllTables(bool $forceFetch = false): array
return $this->allTables;
}

/**
* Create the table gathering the dirty tables
* @return void
*/
public function createDirtyTableCollector()
{
$dirtyTable = TriggerBasedTableSnifferInterface::DIRTY_TABLE_COLLECTOR;
$this->getConnection()->execute("
CREATE TABLE IF NOT EXISTS {$dirtyTable} (
table_name VARCHAR(128) PRIMARY KEY
);
");
}

/**
* Checks if the present class implements triggers
* @return bool
*/
public function implementsTriggers(): bool
{
$class = new \ReflectionClass($this);
return $class->implementsInterface(TriggerBasedTableSnifferInterface::class);
return $this instanceof BaseTriggerBasedTableSniffer;
}
}
Loading

0 comments on commit f0a68d4

Please sign in to comment.