Skip to content

Commit 1c43c3c

Browse files
committed
WIP: Try to fix transaction error
RuntimeException: A transaction is active already, can't commit events! RuntimeException: Failed to acquire checkpoint lock for subscriber "Neos\ContentRepository\Core\Projection\ContentStream\ContentStreamProjection" because a transaction is active already
1 parent feeec56 commit 1c43c3c

File tree

3 files changed

+130
-2
lines changed

3 files changed

+130
-2
lines changed

Tests/Functional/AbstractNodeTemplateTestCase.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use Flowpack\NodeTemplates\Domain\NodeTemplateDumper\NodeTemplateDumper;
88
use Flowpack\NodeTemplates\Domain\Template\RootTemplate;
99
use Flowpack\NodeTemplates\Domain\TemplateConfiguration\TemplateConfigurationProcessor;
10-
use Neos\Behat\FlowEntitiesTrait;
1110
use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint;
1211
use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint;
1312
use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNode;

Tests/Functional/Features/StandaloneValidationCommand/StandaloneValidationCommandTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
use Flowpack\NodeTemplates\Application\Command\NodeTemplateCommandController;
88
use Flowpack\NodeTemplates\Tests\Functional\ContentRepositoryTestTrait;
99
use Flowpack\NodeTemplates\Tests\Functional\FakeNodeTypeManagerTrait;
10+
use Flowpack\NodeTemplates\Tests\Functional\FlowEntitiesTrait;
1011
use Flowpack\NodeTemplates\Tests\Functional\SnapshotTrait;
11-
use Neos\Behat\FlowEntitiesTrait;
1212
use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint;
1313
use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint;
1414
use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNode;
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Flowpack\NodeTemplates\Tests\Functional;
6+
7+
use Behat\Hook\BeforeScenario;
8+
use Doctrine\DBAL\Connection;
9+
use Doctrine\DBAL\Exception as DoctrineException;
10+
use Doctrine\DBAL\Schema\Schema;
11+
use Doctrine\ORM\EntityManagerInterface;
12+
use Neos\Flow\Configuration\ConfigurationManager;
13+
use Neos\Flow\Persistence\Doctrine\Service as FlowDoctrineService;
14+
use Neos\Flow\Persistence\PersistenceManagerInterface;
15+
16+
/**
17+
* Tag your test with [at]flowEntities to enable support for flow entities
18+
*
19+
* Copied from {@see \Neos\Behat\FlowEntitiesTrait}
20+
*/
21+
trait FlowEntitiesTrait
22+
{
23+
/** @internal */
24+
private static ?Schema $databaseSchema = null;
25+
26+
/**
27+
* @template T of object
28+
* @param class-string<T> $className
29+
*
30+
* @return T
31+
*/
32+
abstract protected function getObject(string $className): object;
33+
34+
/** @internal */
35+
final public function truncateAndSetupFlowEntities(): void
36+
{
37+
$connection = $this->getObject(Connection::class);
38+
$entityManager = $this->getObject(EntityManagerInterface::class);
39+
$entityManager->clear();
40+
41+
if (self::$databaseSchema !== null) {
42+
$this->truncateTables($connection);
43+
} else {
44+
try {
45+
$doctrineService = $this->getObject(FlowDoctrineService::class);
46+
47+
$doctrineService->executeMigrations();
48+
$needsTruncate = true;
49+
} catch (DoctrineException $exception) {
50+
// Do an initial teardown to drop the schema cleanly
51+
$this->getObject(PersistenceManagerInterface::class)->tearDown();
52+
53+
$doctrineService = $this->getObject(FlowDoctrineService::class);
54+
$doctrineService->executeMigrations();
55+
$needsTruncate = false;
56+
} catch (\PDOException $exception) {
57+
if ($exception->getMessage() !== 'There is no active transaction') {
58+
throw $exception;
59+
}
60+
$needsTruncate = true;
61+
}
62+
63+
$schema = $connection->getSchemaManager()->createSchema();
64+
self::$databaseSchema = $schema;
65+
66+
if ($needsTruncate) {
67+
$this->truncateTables($connection);
68+
}
69+
}
70+
}
71+
72+
/** @internal */
73+
private function truncateTables(Connection $connection): void
74+
{
75+
/**
76+
* We respect flows option "ignoredTables" to preserve certain tables while resetting the database.
77+
* In our case we interpret everything in "ignoredTables" as not managed by doctrine.
78+
* And this trait should only clear tables for @flowEntities.
79+
* An important use case is keeping the Neos ESCR tables `cr_*.` alive for speeding up tests.
80+
*
81+
* Docs for original idea of "ignoredTables": {@link https://flowframework.readthedocs.io/en/9.0/TheDefinitiveGuide/PartIII/Persistence.html#ignoring-tables}
82+
*
83+
* Implementation copied from {@link https://github.com/neos/flow-development-collection/blob/ed6a26603f682966816c71840524c7da6ed919a5/Neos.Flow/Classes/Command/DoctrineCommandController.php#L468-L474}
84+
*/
85+
$ignoredTables = $this->getObject(ConfigurationManager::class)
86+
->getConfiguration(ConfigurationManager::CONFIGURATION_TYPE_SETTINGS, 'Neos.Flow.persistence.doctrine.migrations.ignoredTables') ?? [];
87+
$filterExpression = null;
88+
$ignoredTables = array_keys(array_filter($ignoredTables));
89+
if ($ignoredTables !== []) {
90+
$filterExpression = sprintf('/^(?!%s$).*$/xs', implode('$|', $ignoredTables));
91+
}
92+
93+
$tables = array_filter(self::$databaseSchema->getTables(), function ($table) use ($filterExpression) {
94+
if ($table->getName() === FlowDoctrineService::DOCTRINE_MIGRATIONSTABLENAME) {
95+
return false;
96+
}
97+
if ($filterExpression === null) {
98+
return true;
99+
}
100+
return preg_match($filterExpression, $table->getName()) === 1;
101+
});
102+
103+
switch ($connection->getDatabasePlatform()->getName()) {
104+
case 'mysql':
105+
$sql = 'SET FOREIGN_KEY_CHECKS=0;';
106+
foreach ($tables as $table) {
107+
$sql .= 'TRUNCATE `' . $table->getName() . '`;';
108+
}
109+
$sql .= 'SET FOREIGN_KEY_CHECKS=1;';
110+
$connection->executeQuery($sql);
111+
break;
112+
case 'sqlite':
113+
$sql = 'PRAGMA foreign_keys = OFF;';
114+
foreach ($tables as $table) {
115+
$sql .= 'DELETE FROM `' . $table->getName() . '`;';
116+
}
117+
$sql .= 'PRAGMA foreign_keys = ON;';
118+
$connection->executeQuery($sql);
119+
break;
120+
case 'postgresql':
121+
default:
122+
foreach ($tables as $table) {
123+
$sql = 'TRUNCATE ' . $table->getName() . ' CASCADE;';
124+
$connection->executeQuery($sql);
125+
}
126+
break;
127+
}
128+
}
129+
}

0 commit comments

Comments
 (0)