diff --git a/.composer.json b/.composer.json index 7bb9de59aa4..5b0acf1a2a0 100644 --- a/.composer.json +++ b/.composer.json @@ -32,7 +32,10 @@ "test:functional": [ "../../bin/phpunit --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml Neos.ContentRepository.Core/Tests/Functional" ], - "test:behat-cli": "../../bin/behat -f progress --strict --no-interaction", + "test:behat-cli": [ + "Composer\\Config::disableProcessTimeout", + "../../bin/behat -f progress --strict --no-interaction" + ], "test:behavioral": [ "@test:behat-cli -c Neos.ContentRepository.BehavioralTests/Tests/Behavior/behat.yml.dist", "@test:behat-cli -c Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/behat.yml.dist", diff --git a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/CRBehavioralTestsSubjectProvider.php b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/CRBehavioralTestsSubjectProvider.php index 24d758de0f4..355c1e29b1f 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/CRBehavioralTestsSubjectProvider.php +++ b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/CRBehavioralTestsSubjectProvider.php @@ -18,9 +18,11 @@ use Behat\Gherkin\Node\TableNode; use Doctrine\DBAL\Connection; use Neos\ContentRepository\Core\ContentRepository; +use Neos\ContentRepository\Core\Dimension\ContentDimensionSourceInterface; use Neos\ContentRepository\Core\Factory\ContentRepositoryId; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers\GherkinTableNodeBasedContentDimensionSource; use Neos\EventStore\EventStoreInterface; +use Symfony\Component\Yaml\Yaml; /** * Subject provider for behavioral tests @@ -40,6 +42,10 @@ trait CRBehavioralTestsSubjectProvider protected ?ContentRepository $currentContentRepository = null; + private ?array $nodeTypesConfiguration = null; + + private ?ContentDimensionSourceInterface $contentDimensionsToUse = null; + /** * @throws \DomainException if the requested content repository instance does not exist */ @@ -57,7 +63,7 @@ protected function getContentRepository(ContentRepositoryId $contentRepositoryId */ public function usingNoContentDimensions(): void { - GherkinTableNodeBasedContentDimensionSourceFactory::$contentDimensionsToUse = GherkinTableNodeBasedContentDimensionSource::createEmpty(); + $this->contentDimensionsToUse = GherkinTableNodeBasedContentDimensionSource::createEmpty(); } /** @@ -65,7 +71,7 @@ public function usingNoContentDimensions(): void */ public function usingTheFollowingContentDimensions(TableNode $contentDimensions): void { - GherkinTableNodeBasedContentDimensionSourceFactory::initializeFromTableNode($contentDimensions); + $this->contentDimensionsToUse = GherkinTableNodeBasedContentDimensionSource::fromGherkinTableNode($contentDimensions); } /** @@ -73,7 +79,7 @@ public function usingTheFollowingContentDimensions(TableNode $contentDimensions) */ public function usingTheFollowingNodeTypes(PyStringNode $serializedNodeTypesConfiguration): void { - GherkinPyStringNodeBasedNodeTypeManagerFactory::initializeWithPyStringNode($serializedNodeTypesConfiguration); + $this->nodeTypesConfiguration = Yaml::parse($serializedNodeTypesConfiguration->getRaw()) ?? []; } /** @@ -83,9 +89,14 @@ public function usingIdentifierIDefineAContentRepository(string $contentReposito { if (array_key_exists($contentRepositoryId, $this->contentRepositories)) { throw new \DomainException('already defined content repository ' . $contentRepositoryId); - } else { - $this->contentRepositories[$contentRepositoryId] = $this->setUpContentRepository(ContentRepositoryId::fromString($contentRepositoryId)); } + if ($this->nodeTypesConfiguration !== null) { + GherkinPyStringNodeBasedNodeTypeManagerFactory::registerNodeTypeConfigurationForContentRepository(ContentRepositoryId::fromString($contentRepositoryId), $this->nodeTypesConfiguration); + } + if ($this->contentDimensionsToUse !== null) { + GherkinTableNodeBasedContentDimensionSourceFactory::registerContentDimensionsForContentRepository(ContentRepositoryId::fromString($contentRepositoryId), $this->contentDimensionsToUse); + } + $this->contentRepositories[$contentRepositoryId] = $this->setUpContentRepository(ContentRepositoryId::fromString($contentRepositoryId)); } /** @@ -95,14 +106,12 @@ public function iChangeTheContentDimensionsInContentRepositoryTo(string $content { if (!array_key_exists($contentRepositoryId, $this->contentRepositories)) { throw new \DomainException('undeclared content repository ' . $contentRepositoryId); - } else { - $contentRepository = $this->contentRepositories[$contentRepositoryId]; - GherkinPyStringNodeBasedNodeTypeManagerFactory::$nodeTypesToUse = $contentRepository->getNodeTypeManager(); - GherkinTableNodeBasedContentDimensionSourceFactory::initializeFromTableNode($contentDimensions); - $this->contentRepositories[$contentRepositoryId] = $this->createContentRepository(ContentRepositoryId::fromString($contentRepositoryId)); - if ($this->currentContentRepository->id->value === $contentRepositoryId) { - $this->currentContentRepository = $this->contentRepositories[$contentRepositoryId]; - } + } + $contentRepository = $this->contentRepositories[$contentRepositoryId]; + GherkinTableNodeBasedContentDimensionSourceFactory::registerContentDimensionsForContentRepository($contentRepository->id, GherkinTableNodeBasedContentDimensionSource::fromGherkinTableNode($contentDimensions)); + $this->contentRepositories[$contentRepositoryId] = $this->createContentRepository(ContentRepositoryId::fromString($contentRepositoryId)); + if ($this->currentContentRepository->id->value === $contentRepositoryId) { + $this->currentContentRepository = $this->contentRepositories[$contentRepositoryId]; } } @@ -115,14 +124,12 @@ public function iChangeTheNodeTypesInContentRepositoryTo( ): void { if (!array_key_exists($contentRepositoryId, $this->contentRepositories)) { throw new \DomainException('undeclared content repository ' . $contentRepositoryId); - } else { - $contentRepository = $this->contentRepositories[$contentRepositoryId]; - GherkinPyStringNodeBasedNodeTypeManagerFactory::initializeWithPyStringNode($serializedNodeTypesConfiguration); - GherkinTableNodeBasedContentDimensionSourceFactory::$contentDimensionsToUse = $contentRepository->getContentDimensionSource(); - $this->contentRepositories[$contentRepositoryId] = $this->createContentRepository(ContentRepositoryId::fromString($contentRepositoryId)); - if ($this->currentContentRepository->id->value === $contentRepositoryId) { - $this->currentContentRepository = $this->contentRepositories[$contentRepositoryId]; - } + } + $contentRepository = $this->contentRepositories[$contentRepositoryId]; + GherkinPyStringNodeBasedNodeTypeManagerFactory::registerNodeTypeConfigurationForContentRepository($contentRepository->id, Yaml::parse($serializedNodeTypesConfiguration->getRaw()) ?? []); + $this->contentRepositories[$contentRepositoryId] = $this->createContentRepository(ContentRepositoryId::fromString($contentRepositoryId)); + if ($this->currentContentRepository->id->value === $contentRepositoryId) { + $this->currentContentRepository = $this->contentRepositories[$contentRepositoryId]; } } diff --git a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinPyStringNodeBasedNodeTypeManagerFactory.php b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinPyStringNodeBasedNodeTypeManagerFactory.php index 026136c0ca3..49314ee3515 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinPyStringNodeBasedNodeTypeManagerFactory.php +++ b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinPyStringNodeBasedNodeTypeManagerFactory.php @@ -15,6 +15,7 @@ namespace Neos\ContentRepository\BehavioralTests\TestSuite\Behavior; use Behat\Gherkin\Node\PyStringNode; +use JsonException; use Neos\ContentRepository\Core\Factory\ContentRepositoryId; use Neos\ContentRepository\Core\NodeType\NodeLabelGeneratorFactoryInterface; use Neos\ContentRepository\Core\NodeType\NodeLabelGeneratorInterface; @@ -29,23 +30,22 @@ */ final class GherkinPyStringNodeBasedNodeTypeManagerFactory implements NodeTypeManagerFactoryInterface { - public static ?NodeTypeManager $nodeTypesToUse = null; - /** * @param array $options */ public function build(ContentRepositoryId $contentRepositoryId, array $options): NodeTypeManager { - if (!self::$nodeTypesToUse) { - throw new \DomainException('NodeTypeManagerFactory uninitialized'); + $nodeTypesConfigurationJson = file_get_contents(self::cacheFileName($contentRepositoryId)); + if ($nodeTypesConfigurationJson === false) { + throw new \RuntimeException(sprintf('NodeTypeManagerFactory uninitialized for ContentRepository "%s"', $contentRepositoryId->value)); } - return self::$nodeTypesToUse; - } - - public static function initializeWithPyStringNode(PyStringNode $nodeTypesToUse): void - { - self::$nodeTypesToUse = new NodeTypeManager( - fn (): array => Yaml::parse($nodeTypesToUse->getRaw()) ?? [], + try { + $nodeTypesConfiguration = json_decode($nodeTypesConfigurationJson, true, 512, JSON_THROW_ON_ERROR); + } catch (JsonException $e) { + throw new \RuntimeException(sprintf('Failed to parse JSON for node types configuration: %s', $nodeTypesConfigurationJson)); + } + return new NodeTypeManager( + fn () => $nodeTypesConfiguration, new class implements NodeLabelGeneratorFactoryInterface { public function create(NodeType $nodeType): NodeLabelGeneratorInterface { @@ -60,8 +60,20 @@ public function getLabel(Node $node): string ); } + /** + * @param array $nodeTypeConfiguration + */ + public static function registerNodeTypeConfigurationForContentRepository(ContentRepositoryId $contentRepositoryId, array $nodeTypeConfiguration): void + { + file_put_contents(self::cacheFileName($contentRepositoryId), json_encode($nodeTypeConfiguration, JSON_THROW_ON_ERROR)); + } + public static function reset(): void { - self::$nodeTypesToUse = null; + } + + private static function cacheFileName(ContentRepositoryId $contentRepositoryId): string + { + return sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'nodeTypesConfiguration_' . $contentRepositoryId->value . '.json'; } } diff --git a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinTableNodeBasedContentDimensionSourceFactory.php b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinTableNodeBasedContentDimensionSourceFactory.php index cea611ec680..e34aa59565d 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinTableNodeBasedContentDimensionSourceFactory.php +++ b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinTableNodeBasedContentDimensionSourceFactory.php @@ -4,7 +4,6 @@ namespace Neos\ContentRepository\BehavioralTests\TestSuite\Behavior; -use Behat\Gherkin\Node\TableNode; use Neos\ContentRepository\Core\Dimension\ContentDimensionSourceInterface; use Neos\ContentRepository\Core\Factory\ContentRepositoryId; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers\GherkinTableNodeBasedContentDimensionSource; @@ -12,26 +11,29 @@ class GherkinTableNodeBasedContentDimensionSourceFactory implements ContentDimensionSourceFactoryInterface { - public static ?ContentDimensionSourceInterface $contentDimensionsToUse = null; + public static function registerContentDimensionsForContentRepository(ContentRepositoryId $contentRepositoryId, GherkinTableNodeBasedContentDimensionSource $contentDimensions): void + { + file_put_contents(self::cacheFileName($contentRepositoryId), serialize($contentDimensions)); + } /** * @param array $options */ public function build(ContentRepositoryId $contentRepositoryId, array $options): ContentDimensionSourceInterface { - if (!self::$contentDimensionsToUse) { - throw new \DomainException('Content dimension source not initialized.'); + $contentDimensionSource = file_get_contents(self::cacheFileName($contentRepositoryId)); + if ($contentDimensionSource === false) { + throw new \RuntimeException(sprintf('Content dimension source uninitialized for ContentRepository "%s"', $contentRepositoryId->value)); } - return self::$contentDimensionsToUse; + return unserialize($contentDimensionSource); } - public static function initializeFromTableNode(TableNode $contentDimensionsToUse): void + public static function reset(): void { - self::$contentDimensionsToUse = GherkinTableNodeBasedContentDimensionSource::fromGherkinTableNode($contentDimensionsToUse); } - public static function reset(): void + private static function cacheFileName(ContentRepositoryId $contentRepositoryId): string { - self::$contentDimensionsToUse = null; + return sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'contentDimensionsConfiguration_' . $contentRepositoryId->value . '.json'; } } diff --git a/Neos.ContentRepository.BehavioralTests/composer.json b/Neos.ContentRepository.BehavioralTests/composer.json index 2ef917d4816..d1b62f49b3e 100644 --- a/Neos.ContentRepository.BehavioralTests/composer.json +++ b/Neos.ContentRepository.BehavioralTests/composer.json @@ -10,7 +10,8 @@ "GPL-3.0-or-later" ], "require": { - "neos/contentrepository-core": "self.version" + "neos/contentrepository-core": "self.version", + "neos/contentrepositoryregistry": "*" }, "autoload": { "psr-4": { diff --git a/composer.json b/composer.json index ef5a937ac53..5067e50a878 100644 --- a/composer.json +++ b/composer.json @@ -9,8 +9,8 @@ "neos/flow-development-collection": "9.0.x-dev", "doctrine/dbal": "^2.8", "doctrine/migrations": "*", - "neos/eventstore": "~1.0.0", - "neos/eventstore-doctrineadapter": "~1.0.0", + "neos/eventstore": "^1", + "neos/eventstore-doctrineadapter": "^1 || ^2", "php": "^8.2", "neos/error-messages": "*", "neos/utility-objecthandling": "*", @@ -116,7 +116,10 @@ "test:functional": [ "../../bin/phpunit --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml Neos.ContentRepository.Core/Tests/Functional" ], - "test:behat-cli": "../../bin/behat -f progress --strict --no-interaction", + "test:behat-cli": [ + "Composer\\Config::disableProcessTimeout", + "../../bin/behat -f progress --strict --no-interaction" + ], "test:behavioral": [ "@test:behat-cli -c Neos.ContentRepository.BehavioralTests/Tests/Behavior/behat.yml.dist", "@test:behat-cli -c Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/behat.yml.dist",