diff --git a/.composer.json b/.composer.json index e7f37b99667..2f96abd741b 100644 --- a/.composer.json +++ b/.composer.json @@ -13,7 +13,7 @@ "scripts": { "lint:phpcs": "../../bin/phpcs --colors", "lint:phpcs:fix": "../../bin/phpcbf --colors", - "lint:phpstan": "../../bin/phpstan analyse", + "lint:phpstan": "../../bin/phpstan analyse -v", "lint:phpstan-generate-baseline": "../../bin/phpstan analyse --generate-baseline", "lint:distributionintegrity": "[ -d 'Neos.ContentRepository' ] && { echo 'Package Neos.ContentRepository should not exist.' 1>&2; exit 1; } || exit 0;", "lint": [ @@ -27,7 +27,7 @@ ], "test:paratest-cli": "../../bin/paratest --debug -v --functional --processes 2 --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml", "test:parallel": [ - "for f in Neos.ContentRepository.BehavioralTests/Tests/Parallel/**/*Test.php; do composer test:paratest-cli $f; done" + "for f in Neos.ContentRepository.BehavioralTests/Tests/Parallel/**/*Test.php; do composer test:paratest-cli $f || exit 1; done" ], "test:behat-cli": "../../bin/behat -f progress --strict --no-interaction", "test:behavioral": [ diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Bootstrap/FeatureContext.php b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Bootstrap/FeatureContext.php index 3df89de8c1f..6fa805c907c 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Bootstrap/FeatureContext.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Bootstrap/FeatureContext.php @@ -18,13 +18,13 @@ use Neos\Behat\FlowBootstrapTrait; use Neos\ContentGraph\DoctrineDbalAdapter\Tests\Behavior\Features\Bootstrap\ProjectionIntegrityViolationDetectionTrait; use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\CRBehavioralTestsSubjectProvider; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinPyStringNodeBasedNodeTypeManagerFactory; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinTableNodeBasedContentDimensionSourceFactory; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryInterface; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteTrait; +use Neos\ContentRepository\TestSuite\Fakes\FakeNodeTypeManagerFactory; +use Neos\ContentRepository\TestSuite\Fakes\FakeContentDimensionSourceFactory; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; /** @@ -52,8 +52,8 @@ public function __construct() */ public function resetContentRepositoryComponents(BeforeScenarioScope $scope): void { - GherkinTableNodeBasedContentDimensionSourceFactory::reset(); - GherkinPyStringNodeBasedNodeTypeManagerFactory::reset(); + FakeContentDimensionSourceFactory::reset(); + FakeNodeTypeManagerFactory::reset(); } protected function getContentRepositoryService( @@ -70,8 +70,8 @@ protected function createContentRepository( ): ContentRepository { $this->contentRepositoryRegistry->resetFactoryInstance($contentRepositoryId); $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - GherkinTableNodeBasedContentDimensionSourceFactory::reset(); - GherkinPyStringNodeBasedNodeTypeManagerFactory::reset(); + FakeContentDimensionSourceFactory::reset(); + FakeNodeTypeManagerFactory::reset(); return $contentRepository; } diff --git a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/CRBehavioralTestsSubjectProvider.php b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/CRBehavioralTestsSubjectProvider.php index 19eb183ff16..9f8d56cda7f 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/CRBehavioralTestsSubjectProvider.php +++ b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/CRBehavioralTestsSubjectProvider.php @@ -20,7 +20,10 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers\GherkinTableNodeBasedContentDimensionSource; +use Neos\ContentRepository\TestSuite\Fakes\FakeContentDimensionSourceFactory; +use Neos\ContentRepository\TestSuite\Fakes\FakeNodeTypeManagerFactory; use Neos\EventStore\EventStoreInterface; +use Symfony\Component\Yaml\Yaml; /** * Subject provider for behavioral tests @@ -57,7 +60,7 @@ protected function getContentRepository(ContentRepositoryId $contentRepositoryId */ public function usingNoContentDimensions(): void { - GherkinTableNodeBasedContentDimensionSourceFactory::$contentDimensionsToUse = GherkinTableNodeBasedContentDimensionSource::createEmpty(); + FakeContentDimensionSourceFactory::setWithoutDimensions(); } /** @@ -65,7 +68,9 @@ public function usingNoContentDimensions(): void */ public function usingTheFollowingContentDimensions(TableNode $contentDimensions): void { - GherkinTableNodeBasedContentDimensionSourceFactory::initializeFromTableNode($contentDimensions); + FakeContentDimensionSourceFactory::setContentDimensionSource( + GherkinTableNodeBasedContentDimensionSource::fromGherkinTableNode($contentDimensions) + ); } /** @@ -73,7 +78,7 @@ public function usingTheFollowingContentDimensions(TableNode $contentDimensions) */ public function usingTheFollowingNodeTypes(PyStringNode $serializedNodeTypesConfiguration): void { - GherkinPyStringNodeBasedNodeTypeManagerFactory::initializeWithPyStringNode($serializedNodeTypesConfiguration); + FakeNodeTypeManagerFactory::setConfiguration(Yaml::parse($serializedNodeTypesConfiguration->getRaw()) ?? []); } /** @@ -97,8 +102,11 @@ public function iChangeTheContentDimensionsInContentRepositoryTo(string $content throw new \DomainException('undeclared content repository ' . $contentRepositoryId); } else { $contentRepository = $this->contentRepositories[$contentRepositoryId]; - GherkinPyStringNodeBasedNodeTypeManagerFactory::$nodeTypesToUse = $contentRepository->getNodeTypeManager(); - GherkinTableNodeBasedContentDimensionSourceFactory::initializeFromTableNode($contentDimensions); + // ensure that the current node types of exactly THE content repository are preserved + FakeNodeTypeManagerFactory::setNodeTypeManager($contentRepository->getNodeTypeManager()); + FakeContentDimensionSourceFactory::setContentDimensionSource( + GherkinTableNodeBasedContentDimensionSource::fromGherkinTableNode($contentDimensions) + ); $this->contentRepositories[$contentRepositoryId] = $this->createContentRepository(ContentRepositoryId::fromString($contentRepositoryId)); if ($this->currentContentRepository->id->value === $contentRepositoryId) { $this->currentContentRepository = $this->contentRepositories[$contentRepositoryId]; @@ -117,8 +125,9 @@ public function iChangeTheNodeTypesInContentRepositoryTo( throw new \DomainException('undeclared content repository ' . $contentRepositoryId); } else { $contentRepository = $this->contentRepositories[$contentRepositoryId]; - GherkinPyStringNodeBasedNodeTypeManagerFactory::initializeWithPyStringNode($serializedNodeTypesConfiguration); - GherkinTableNodeBasedContentDimensionSourceFactory::$contentDimensionsToUse = $contentRepository->getContentDimensionSource(); + // ensure that the current node types of exactly THE content repository are preserved + FakeContentDimensionSourceFactory::setContentDimensionSource($contentRepository->getContentDimensionSource()); + FakeNodeTypeManagerFactory::setConfiguration(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 deleted file mode 100644 index 82796bf1738..00000000000 --- a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinPyStringNodeBasedNodeTypeManagerFactory.php +++ /dev/null @@ -1,52 +0,0 @@ - $options - */ - public function build(ContentRepositoryId $contentRepositoryId, array $options): NodeTypeManager - { - if (!self::$nodeTypesToUse) { - throw new \DomainException('NodeTypeManagerFactory uninitialized'); - } - return self::$nodeTypesToUse; - } - - public static function initializeWithPyStringNode(PyStringNode $nodeTypesToUse): void - { - self::$nodeTypesToUse = new NodeTypeManager( - fn (): array => Yaml::parse($nodeTypesToUse->getRaw()) ?? [] - ); - } - - public static function reset(): void - { - self::$nodeTypesToUse = null; - } -} diff --git a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinTableNodeBasedContentDimensionSourceFactory.php b/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinTableNodeBasedContentDimensionSourceFactory.php deleted file mode 100644 index cb379048f81..00000000000 --- a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/GherkinTableNodeBasedContentDimensionSourceFactory.php +++ /dev/null @@ -1,37 +0,0 @@ - $options - */ - public function build(ContentRepositoryId $contentRepositoryId, array $options): ContentDimensionSourceInterface - { - if (!self::$contentDimensionsToUse) { - throw new \DomainException('Content dimension source not initialized.'); - } - return self::$contentDimensionsToUse; - } - - public static function initializeFromTableNode(TableNode $contentDimensionsToUse): void - { - self::$contentDimensionsToUse = GherkinTableNodeBasedContentDimensionSource::fromGherkinTableNode($contentDimensionsToUse); - } - - public static function reset(): void - { - self::$contentDimensionsToUse = null; - } -} diff --git a/Neos.ContentRepository.BehavioralTests/Configuration/Testing/Behat/Settings.ContentRepositoryRegistry.yaml b/Neos.ContentRepository.BehavioralTests/Configuration/Testing/Behat/Settings.ContentRepositoryRegistry.yaml index c7bd8303a73..be295835ab5 100644 --- a/Neos.ContentRepository.BehavioralTests/Configuration/Testing/Behat/Settings.ContentRepositoryRegistry.yaml +++ b/Neos.ContentRepository.BehavioralTests/Configuration/Testing/Behat/Settings.ContentRepositoryRegistry.yaml @@ -3,10 +3,10 @@ Neos: presets: default: authProvider: - factoryObjectName: 'Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\TestingAuthProviderFactory' + factoryObjectName: Neos\ContentRepository\TestSuite\Fakes\FakeAuthProviderFactory clock: - factoryObjectName: 'Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\FakeClockFactory' + factoryObjectName: 'Neos\ContentRepository\TestSuite\Fakes\FakeClockFactory' nodeTypeManager: - factoryObjectName: 'Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinPyStringNodeBasedNodeTypeManagerFactory' + factoryObjectName: 'Neos\ContentRepository\TestSuite\Fakes\FakeNodeTypeManagerFactory' contentDimensionSource: - factoryObjectName: 'Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinTableNodeBasedContentDimensionSourceFactory' + factoryObjectName: 'Neos\ContentRepository\TestSuite\Fakes\FakeContentDimensionSourceFactory' diff --git a/Neos.ContentRepository.BehavioralTests/Configuration/Settings.yaml b/Neos.ContentRepository.BehavioralTests/Configuration/Testing/Settings.yaml similarity index 79% rename from Neos.ContentRepository.BehavioralTests/Configuration/Settings.yaml rename to Neos.ContentRepository.BehavioralTests/Configuration/Testing/Settings.yaml index d38e376fd54..2d0fe1e74c0 100644 --- a/Neos.ContentRepository.BehavioralTests/Configuration/Settings.yaml +++ b/Neos.ContentRepository.BehavioralTests/Configuration/Testing/Settings.yaml @@ -24,11 +24,11 @@ Neos: eventStore: factoryObjectName: Neos\ContentRepositoryRegistry\Factory\EventStore\DoctrineEventStoreFactory nodeTypeManager: - factoryObjectName: Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinPyStringNodeBasedNodeTypeManagerFactory + factoryObjectName: Neos\ContentRepository\TestSuite\Fakes\FakeNodeTypeManagerFactory contentDimensionSource: - factoryObjectName: Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinTableNodeBasedContentDimensionSourceFactory + factoryObjectName: Neos\ContentRepository\TestSuite\Fakes\FakeContentDimensionSourceFactory authProvider: - factoryObjectName: Neos\ContentRepositoryRegistry\Factory\AuthProvider\StaticAuthProviderFactory + factoryObjectName: Neos\ContentRepository\TestSuite\Fakes\FakeAuthProviderFactory clock: factoryObjectName: Neos\ContentRepositoryRegistry\Factory\Clock\SystemClockFactory propertyConverters: {} diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Bootstrap/FeatureContext.php b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Bootstrap/FeatureContext.php index 682bf3c0d66..9646198d20d 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Bootstrap/FeatureContext.php +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Bootstrap/FeatureContext.php @@ -23,8 +23,6 @@ use Neos\ContentRepository\BehavioralTests\ProjectionRaceConditionTester\Dto\TraceEntryType; use Neos\ContentRepository\BehavioralTests\ProjectionRaceConditionTester\RedisInterleavingLogger; use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\CRBehavioralTestsSubjectProvider; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinPyStringNodeBasedNodeTypeManagerFactory; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinTableNodeBasedContentDimensionSourceFactory; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryInterface; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; @@ -36,6 +34,8 @@ use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteTrait; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\MigrationsTrait; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\StructureAdjustmentsTrait; +use Neos\ContentRepository\TestSuite\Fakes\FakeNodeTypeManagerFactory; +use Neos\ContentRepository\TestSuite\Fakes\FakeContentDimensionSourceFactory; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Configuration\ConfigurationManager; @@ -106,8 +106,8 @@ public function logToRaceConditionTracker(array $payload): void */ public function resetContentRepositoryComponents(BeforeScenarioScope $scope): void { - GherkinTableNodeBasedContentDimensionSourceFactory::reset(); - GherkinPyStringNodeBasedNodeTypeManagerFactory::reset(); + FakeContentDimensionSourceFactory::reset(); + FakeNodeTypeManagerFactory::reset(); } protected function getContentRepositoryService( @@ -161,8 +161,8 @@ protected function createContentRepository( ): ContentRepository { $this->contentRepositoryRegistry->resetFactoryInstance($contentRepositoryId); $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - GherkinTableNodeBasedContentDimensionSourceFactory::reset(); - GherkinPyStringNodeBasedNodeTypeManagerFactory::reset(); + FakeContentDimensionSourceFactory::reset(); + FakeNodeTypeManagerFactory::reset(); return $contentRepository; } diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Parallel/WorkspacePublicationDuringWriting/WorkspacePublicationDuringWritingTest.php b/Neos.ContentRepository.BehavioralTests/Tests/Parallel/WorkspacePublicationDuringWriting/WorkspacePublicationDuringWritingTest.php index d96a9adddf0..1dcc9fcdd03 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Parallel/WorkspacePublicationDuringWriting/WorkspacePublicationDuringWritingTest.php +++ b/Neos.ContentRepository.BehavioralTests/Tests/Parallel/WorkspacePublicationDuringWriting/WorkspacePublicationDuringWritingTest.php @@ -15,12 +15,7 @@ namespace Neos\ContentRepository\BehavioralTests\Tests\Parallel\WorkspacePublicationDuringWriting; use Neos\ContentRepository\BehavioralTests\Tests\Parallel\AbstractParallelTestCase; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinPyStringNodeBasedNodeTypeManagerFactory; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinTableNodeBasedContentDimensionSourceFactory; use Neos\ContentRepository\Core\ContentRepository; -use Neos\ContentRepository\Core\Dimension\ContentDimension; -use Neos\ContentRepository\Core\Dimension\ContentDimensionId; -use Neos\ContentRepository\Core\Dimension\ContentDimensionSourceInterface; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNode; @@ -30,7 +25,6 @@ use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateRootWorkspace; use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateWorkspace; use Neos\ContentRepository\Core\Feature\WorkspacePublication\Command\PublishWorkspace; -use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; @@ -38,6 +32,8 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; +use Neos\ContentRepository\TestSuite\Fakes\FakeContentDimensionSourceFactory; +use Neos\ContentRepository\TestSuite\Fakes\FakeNodeTypeManagerFactory; use Neos\EventStore\Exception\ConcurrencyException; use Neos\Flow\ObjectManagement\ObjectManagerInterface; use PHPUnit\Framework\Assert; @@ -55,31 +51,17 @@ public function setUp(): void { parent::setUp(); $this->log('------ process started ------'); - // todo refrain from Gherkin naming here and make fakes easier to use: https://github.com/neos/neos-development-collection/pull/5346 - GherkinTableNodeBasedContentDimensionSourceFactory::$contentDimensionsToUse = new class implements ContentDimensionSourceInterface - { - public function getDimension(ContentDimensionId $dimensionId): ?ContentDimension - { - return null; - } - public function getContentDimensionsOrderedByPriority(): array - { - return []; - } - }; - // todo refrain from Gherkin naming here and make fakes easier to use: https://github.com/neos/neos-development-collection/pull/5346 - GherkinPyStringNodeBasedNodeTypeManagerFactory::$nodeTypesToUse = new NodeTypeManager( - fn (): array => [ - 'Neos.ContentRepository:Root' => [], - 'Neos.ContentRepository.Testing:Document' => [ - 'properties' => [ - 'title' => [ - 'type' => 'string' - ] + FakeContentDimensionSourceFactory::setWithoutDimensions(); + FakeNodeTypeManagerFactory::setConfiguration([ + 'Neos.ContentRepository:Root' => [], + 'Neos.ContentRepository.Testing:Document' => [ + 'properties' => [ + 'title' => [ + 'type' => 'string' ] ] ] - ); + ]); $setupLockResource = fopen(self::SETUP_LOCK_PATH, 'w+'); diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Parallel/WorkspaceWritingDuringRebase/WorkspaceWritingDuringRebaseTest.php b/Neos.ContentRepository.BehavioralTests/Tests/Parallel/WorkspaceWritingDuringRebase/WorkspaceWritingDuringRebaseTest.php index 802205f2e16..f4a37360ed1 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Parallel/WorkspaceWritingDuringRebase/WorkspaceWritingDuringRebaseTest.php +++ b/Neos.ContentRepository.BehavioralTests/Tests/Parallel/WorkspaceWritingDuringRebase/WorkspaceWritingDuringRebaseTest.php @@ -15,12 +15,7 @@ namespace Neos\ContentRepository\BehavioralTests\Tests\Parallel\WorkspaceWritingDuringRebase; use Neos\ContentRepository\BehavioralTests\Tests\Parallel\AbstractParallelTestCase; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinPyStringNodeBasedNodeTypeManagerFactory; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinTableNodeBasedContentDimensionSourceFactory; use Neos\ContentRepository\Core\ContentRepository; -use Neos\ContentRepository\Core\Dimension\ContentDimension; -use Neos\ContentRepository\Core\Dimension\ContentDimensionId; -use Neos\ContentRepository\Core\Dimension\ContentDimensionSourceInterface; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\Feature\NodeCreation\Command\CreateNodeAggregateWithNode; @@ -31,7 +26,6 @@ use Neos\ContentRepository\Core\Feature\WorkspaceCreation\Command\CreateWorkspace; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Command\RebaseWorkspace; use Neos\ContentRepository\Core\Feature\WorkspaceRebase\Dto\RebaseErrorHandlingStrategy; -use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\ContentRepository\Core\NodeType\NodeTypeName; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; @@ -39,6 +33,8 @@ use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; +use Neos\ContentRepository\TestSuite\Fakes\FakeContentDimensionSourceFactory; +use Neos\ContentRepository\TestSuite\Fakes\FakeNodeTypeManagerFactory; use Neos\EventStore\Exception\ConcurrencyException; use Neos\Flow\ObjectManagement\ObjectManagerInterface; use PHPUnit\Framework\Assert; @@ -57,31 +53,17 @@ public function setUp(): void { parent::setUp(); $this->log('------ process started ------'); - // todo refrain from Gherkin naming here and make fakes easier to use: https://github.com/neos/neos-development-collection/pull/5346 - GherkinTableNodeBasedContentDimensionSourceFactory::$contentDimensionsToUse = new class implements ContentDimensionSourceInterface - { - public function getDimension(ContentDimensionId $dimensionId): ?ContentDimension - { - return null; - } - public function getContentDimensionsOrderedByPriority(): array - { - return []; - } - }; - // todo refrain from Gherkin naming here and make fakes easier to use: https://github.com/neos/neos-development-collection/pull/5346 - GherkinPyStringNodeBasedNodeTypeManagerFactory::$nodeTypesToUse = new NodeTypeManager( - fn (): array => [ - 'Neos.ContentRepository:Root' => [], - 'Neos.ContentRepository.Testing:Document' => [ - 'properties' => [ - 'title' => [ - 'type' => 'string' - ] + FakeContentDimensionSourceFactory::setWithoutDimensions(); + FakeNodeTypeManagerFactory::setConfiguration([ + 'Neos.ContentRepository:Root' => [], + 'Neos.ContentRepository.Testing:Document' => [ + 'properties' => [ + 'title' => [ + 'type' => 'string' ] ] ] - ); + ]); $setupLockResource = fopen(self::SETUP_LOCK_PATH, 'w+'); diff --git a/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeManager.php b/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeManager.php index 75cef7fa24f..700ae691cad 100644 --- a/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeManager.php +++ b/Neos.ContentRepository.Core/Classes/NodeType/NodeTypeManager.php @@ -40,14 +40,55 @@ final class NodeTypeManager */ private array $cachedSubNodeTypes = []; - /** - * @internal - */ - public function __construct( + private function __construct( private readonly \Closure $nodeTypeConfigLoader ) { } + /** + * Initialise the NodeType manager with the NodeTypes configuration. + * + * The configuration is usually written in yaml format and then passed as array. + * + * A simple schema might look like this, were each key represents a NodeType: + * + * 'Vendor.Package:Root': + * superTypes: + * 'Neos.ContentRepository:Root': true + * 'Vendor.Package:Document': + * properties: + * title: + * type: string + * uri: + * type: GuzzleHttp\Psr7\Uri + * references: + * someReference: {} + * 'Vendor.Package:Text': + * properties: + * text: + * type: string + * + * FIXME, for standalone integrations a type safe API should be offered: {@link https://github.com/neos/neos-development-collection/issues/4228} + * + * @param array $configuration + * @internal only API for custom content repository integrations + */ + public static function createFromArrayConfiguration(array $configuration): self + { + return new self(fn () => $configuration); + } + + /** + * For documentation regarding the configuration format {@see NodeTypeManager::createFromArrayConfiguration} + * + * @param \Closure(): array $nodeTypeConfigurationLoader + * @internal only API for custom content repository integrations + */ + public static function createFromArrayConfigurationLoader(\Closure $nodeTypeConfigurationLoader): self + { + return new self($nodeTypeConfigurationLoader); + } + /** * Return all registered node types. * @@ -158,34 +199,6 @@ private function loadNodeTypes(): void } } - /** - * This method can be used by Functional of Behavioral Tests to completely - * override the node types known in the system. - * - * In order to reset the node type override, an empty array can be passed in. - * In this case, the system-node-types are used again. - * - * @internal - * @param array $completeNodeTypeConfiguration - */ - public function overrideNodeTypes(array $completeNodeTypeConfiguration): void - { - $this->cachedNodeTypes = []; - - if ($completeNodeTypeConfiguration === []) { - // as cachedNodeTypes is now empty loadNodeTypes will reload the default nodeTypes - return; - } - - // the root node type must always exist - $completeNodeTypeConfiguration[NodeTypeName::ROOT_NODE_TYPE_NAME] ??= []; - - foreach (array_keys($completeNodeTypeConfiguration) as $nodeTypeName) { - /** @var string $nodeTypeName */ - $this->loadNodeType($nodeTypeName, $completeNodeTypeConfiguration); - } - } - /** * Checks if the given $nodeTypeNameToCheck is allowed as a childNode of the given $tetheredNodeName. * diff --git a/Neos.ContentRepository.Core/Tests/Unit/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePathsTest.php b/Neos.ContentRepository.Core/Tests/Unit/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePathsTest.php index cc4a645daf6..e5126866499 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePathsTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/Feature/NodeCreation/Dto/NodeAggregateIdsByNodePathsTest.php @@ -32,8 +32,8 @@ class NodeAggregateIdsByNodePathsTest extends TestCase */ public function testCompleteForNodeOfType(NodeAggregateIdsByNodePaths $subject, array $expectedNodeAggregateIdsByPath): void { - $nodeTypeManager = new NodeTypeManager( - fn (): array => [ + $nodeTypeManager = NodeTypeManager::createFromArrayConfiguration( + [ 'Neos.ContentRepository.Testing:Content' => [], 'Neos.ContentRepository.Testing:LeafDocument' => [ 'childNodes' => [ diff --git a/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeManagerTest.php b/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeManagerTest.php index 578378366ce..97c50d28f27 100644 --- a/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeManagerTest.php +++ b/Neos.ContentRepository.Core/Tests/Unit/NodeType/NodeTypeManagerTest.php @@ -41,8 +41,8 @@ public function setUp(): void */ protected function prepareNodeTypeManager(array $nodeTypesFixtureData) { - $this->nodeTypeManager = new NodeTypeManager( - fn() => $nodeTypesFixtureData + $this->nodeTypeManager = NodeTypeManager::createFromArrayConfiguration( + $nodeTypesFixtureData ); } @@ -443,23 +443,10 @@ public function getAutoCreatedChildNodesReturnsLowercaseNames() */ public function rootNodeTypeIsAlwaysPresent() { - $nodeTypeManager = new NodeTypeManager( - fn() => [] + $nodeTypeManager = NodeTypeManager::createFromArrayConfiguration( + [] ); self::assertTrue($nodeTypeManager->hasNodeType(NodeTypeName::ROOT_NODE_TYPE_NAME)); self::assertInstanceOf(NodeType::class, $nodeTypeManager->getNodeType(NodeTypeName::ROOT_NODE_TYPE_NAME)); } - - /** - * @test - */ - public function rootNodeTypeIsPresentAfterOverride() - { - $nodeTypeManager = new NodeTypeManager( - fn() => [] - ); - $nodeTypeManager->overrideNodeTypes(['Some:NewNodeType' => []]); - self::assertTrue($nodeTypeManager->hasNodeType(NodeTypeName::fromString('Some:NewNodeType'))); - self::assertTrue($nodeTypeManager->hasNodeType(NodeTypeName::ROOT_NODE_TYPE_NAME)); - } } diff --git a/Neos.ContentRepository.Core/composer.json b/Neos.ContentRepository.Core/composer.json index 0951197e5b6..c7cc7e759bb 100644 --- a/Neos.ContentRepository.Core/composer.json +++ b/Neos.ContentRepository.Core/composer.json @@ -25,7 +25,7 @@ }, "require-dev": { "roave/security-advisories": "dev-latest", - "phpstan/phpstan": "^1.5", + "phpstan/phpstan": "^1.11", "squizlabs/php_codesniffer": "^3.6", "phpunit/phpunit": "^9.0" }, diff --git a/Neos.ContentRepository.Export/Tests/Behavior/Features/Bootstrap/FeatureContext.php b/Neos.ContentRepository.Export/Tests/Behavior/Features/Bootstrap/FeatureContext.php index 01310c7beff..15543eef068 100644 --- a/Neos.ContentRepository.Export/Tests/Behavior/Features/Bootstrap/FeatureContext.php +++ b/Neos.ContentRepository.Export/Tests/Behavior/Features/Bootstrap/FeatureContext.php @@ -18,13 +18,13 @@ use Neos\Behat\FlowBootstrapTrait; use Neos\ContentGraph\DoctrineDbalAdapter\Tests\Behavior\Features\Bootstrap\CrImportExportTrait; use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\CRBehavioralTestsSubjectProvider; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinPyStringNodeBasedNodeTypeManagerFactory; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinTableNodeBasedContentDimensionSourceFactory; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryInterface; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteTrait; +use Neos\ContentRepository\TestSuite\Fakes\FakeNodeTypeManagerFactory; +use Neos\ContentRepository\TestSuite\Fakes\FakeContentDimensionSourceFactory; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; /** @@ -52,8 +52,8 @@ public function __construct() */ public function resetContentRepositoryComponents(BeforeScenarioScope $scope): void { - GherkinTableNodeBasedContentDimensionSourceFactory::reset(); - GherkinPyStringNodeBasedNodeTypeManagerFactory::reset(); + FakeContentDimensionSourceFactory::reset(); + FakeNodeTypeManagerFactory::reset(); } protected function getContentRepositoryService( @@ -70,8 +70,8 @@ protected function createContentRepository( ): ContentRepository { $this->contentRepositoryRegistry->resetFactoryInstance($contentRepositoryId); $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - GherkinTableNodeBasedContentDimensionSourceFactory::reset(); - GherkinPyStringNodeBasedNodeTypeManagerFactory::reset(); + FakeContentDimensionSourceFactory::reset(); + FakeNodeTypeManagerFactory::reset(); return $contentRepository; } diff --git a/Neos.ContentRepository.Export/composer.json b/Neos.ContentRepository.Export/composer.json index cdaf568f4ed..545aceb6c37 100644 --- a/Neos.ContentRepository.Export/composer.json +++ b/Neos.ContentRepository.Export/composer.json @@ -15,7 +15,7 @@ }, "require-dev": { "roave/security-advisories": "dev-latest", - "phpstan/phpstan": "^1.8" + "phpstan/phpstan": "^1.11" }, "suggest": { "league/flysystem-ziparchive": "to export zip archives", diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Bootstrap/FeatureContext.php b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Bootstrap/FeatureContext.php index 415bf6d8b04..7b8ef635cf2 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Bootstrap/FeatureContext.php +++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Bootstrap/FeatureContext.php @@ -9,8 +9,6 @@ use Neos\Behat\FlowBootstrapTrait; use Neos\ContentGraph\DoctrineDbalAdapter\Tests\Behavior\Features\Bootstrap\CrImportExportTrait; use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\CRBehavioralTestsSubjectProvider; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinPyStringNodeBasedNodeTypeManagerFactory; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinTableNodeBasedContentDimensionSourceFactory; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\EventStore\EventNormalizer; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryDependencies; @@ -30,6 +28,8 @@ use Neos\ContentRepository\LegacyNodeMigration\Processors\SitesExportProcessor; use Neos\ContentRepository\LegacyNodeMigration\RootNodeTypeMapping; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteTrait; +use Neos\ContentRepository\TestSuite\Fakes\FakeNodeTypeManagerFactory; +use Neos\ContentRepository\TestSuite\Fakes\FakeContentDimensionSourceFactory; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Property\PropertyMapper; use Neos\Flow\ResourceManagement\PersistentResource; @@ -266,8 +266,8 @@ protected function createContentRepository( ): ContentRepository { $this->contentRepositoryRegistry->resetFactoryInstance($contentRepositoryId); $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - GherkinTableNodeBasedContentDimensionSourceFactory::reset(); - GherkinPyStringNodeBasedNodeTypeManagerFactory::reset(); + FakeContentDimensionSourceFactory::reset(); + FakeNodeTypeManagerFactory::reset(); return $contentRepository; } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php index e60a77b6e09..dee8d3a7d45 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/CRTestSuiteRuntimeVariables.php @@ -15,7 +15,6 @@ namespace Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap; use Neos\ContentRepository\Core\ContentRepository; -use Neos\ContentRepository\Core\ContentRepositoryReadModel; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\Feature\Security\Dto\UserId; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface; @@ -26,8 +25,8 @@ use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; -use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers\TestingAuthProvider; -use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers\FakeClock; +use Neos\ContentRepository\TestSuite\Fakes\FakeAuthProvider; +use Neos\ContentRepository\TestSuite\Fakes\FakeClock; /** * The node creation trait for behavioral tests @@ -73,7 +72,7 @@ abstract protected function getContentRepository(ContentRepositoryId $id): Conte */ public function iAmUserIdentifiedBy(string $userId): void { - TestingAuthProvider::setDefaultUserId(UserId::fromString($userId)); + FakeAuthProvider::setDefaultUserId(UserId::fromString($userId)); } /** diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/GherkinTableNodeBasedContentDimensionSource.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/GherkinTableNodeBasedContentDimensionSource.php index 9de355dfa0a..0b528ef7337 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/GherkinTableNodeBasedContentDimensionSource.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/GherkinTableNodeBasedContentDimensionSource.php @@ -27,13 +27,14 @@ use Neos\Utility\Arrays; /** - * The node creation trait for behavioral tests - * todo colocate with GherkinTableNodeBasedContentDimensionSourceFactory + * Compact syntax to declare content dimensions in gherkin tables. + * + * see also {@see \Neos\ContentRepository\TestSuite\Tests\Unit\GherkinTableNodeBasedContentDimensionSourceTest} */ final readonly class GherkinTableNodeBasedContentDimensionSource implements ContentDimensionSourceInterface { + /** @param array $contentDimensions */ private function __construct( - /** @var array */ private array $contentDimensions ) { } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/TestingAuthProvider.php b/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeAuthProvider.php similarity index 90% rename from Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/TestingAuthProvider.php rename to Neos.ContentRepository.TestSuite/Classes/Fakes/FakeAuthProvider.php index 604402b7bf6..7cf61436185 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/TestingAuthProvider.php +++ b/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeAuthProvider.php @@ -2,23 +2,24 @@ declare(strict_types=1); -namespace Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers; +namespace Neos\ContentRepository\TestSuite\Fakes; use Neos\ContentRepository\Core\CommandHandler\CommandInterface; -use Neos\ContentRepository\Core\Feature\Security\AuthProviderInterface; use Neos\ContentRepository\Core\Feature\Security\Dto\Privilege; use Neos\ContentRepository\Core\Feature\Security\Dto\UserId; +use Neos\ContentRepository\Core\Feature\Security\AuthProviderInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\Neos\Security\ContentRepositoryAuthProvider\ContentRepositoryAuthProvider; /** * Content Repository AuthProvider implementation for tests - * This is a mutable class in order to allow to replace the implementation during a request, e.g. for behat tests + * This is a mutable class in order to allow to adjust the behaviour during runtime for testing purposes */ -final class TestingAuthProvider implements AuthProviderInterface +final class FakeAuthProvider implements AuthProviderInterface { private static ?UserId $userId = null; + private static ?ContentRepositoryAuthProvider $contentRepositoryAuthProvider = null; public static function setDefaultUserId(UserId $userId): void @@ -41,6 +42,7 @@ public function getAuthenticatedUserId(): ?UserId if (self::$contentRepositoryAuthProvider !== null) { return self::$contentRepositoryAuthProvider->getAuthenticatedUserId(); } + return self::$userId ?? null; } @@ -49,6 +51,7 @@ public function getVisibilityConstraints(WorkspaceName $workspaceName): Visibili if (self::$contentRepositoryAuthProvider !== null) { return self::$contentRepositoryAuthProvider->getVisibilityConstraints($workspaceName); } + return VisibilityConstraints::withoutRestrictions(); } @@ -57,6 +60,7 @@ public function canReadNodesFromWorkspace(WorkspaceName $workspaceName): Privile if (self::$contentRepositoryAuthProvider !== null) { return self::$contentRepositoryAuthProvider->canReadNodesFromWorkspace($workspaceName); } + return Privilege::granted(self::class . ' always grants privileges'); } @@ -65,6 +69,7 @@ public function canExecuteCommand(CommandInterface $command): Privilege if (self::$contentRepositoryAuthProvider !== null) { return self::$contentRepositoryAuthProvider->canExecuteCommand($command); } + return Privilege::granted(self::class . ' always grants privileges'); } } diff --git a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/TestingAuthProviderFactory.php b/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeAuthProviderFactory.php similarity index 50% rename from Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/TestingAuthProviderFactory.php rename to Neos.ContentRepository.TestSuite/Classes/Fakes/FakeAuthProviderFactory.php index 0fb820d5f03..b2081f14b3c 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/TestingAuthProviderFactory.php +++ b/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeAuthProviderFactory.php @@ -2,17 +2,17 @@ declare(strict_types=1); -namespace Neos\ContentRepository\BehavioralTests\TestSuite\Behavior; +namespace Neos\ContentRepository\TestSuite\Fakes; +use Neos\ContentRepository\Core\Feature\Security\AuthProviderInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphReadModelInterface; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; -use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers\TestingAuthProvider; use Neos\ContentRepositoryRegistry\Factory\AuthProvider\AuthProviderFactoryInterface; -final class TestingAuthProviderFactory implements AuthProviderFactoryInterface +final class FakeAuthProviderFactory implements AuthProviderFactoryInterface { - public function build(ContentRepositoryId $contentRepositoryId, ContentGraphReadModelInterface $contentGraphReadModel): TestingAuthProvider + public function build(ContentRepositoryId $contentRepositoryId, ContentGraphReadModelInterface $contentGraphReadModel): AuthProviderInterface { - return new TestingAuthProvider(); + return new FakeAuthProvider(); } } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/FakeClock.php b/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeClock.php similarity index 67% rename from Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/FakeClock.php rename to Neos.ContentRepository.TestSuite/Classes/Fakes/FakeClock.php index 145d3b43b51..a77e9f92801 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/Helpers/FakeClock.php +++ b/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeClock.php @@ -2,11 +2,15 @@ declare(strict_types=1); -namespace Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers; +namespace Neos\ContentRepository\TestSuite\Fakes; use DateTimeImmutable; use Psr\Clock\ClockInterface; +/** + * Clock implementation for tests + * This is a mutable class in order to allow to adjust the behaviour during runtime for testing purposes + */ final class FakeClock implements ClockInterface { private static ?DateTimeImmutable $now = null; diff --git a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/FakeClockFactory.php b/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeClockFactory.php similarity index 76% rename from Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/FakeClockFactory.php rename to Neos.ContentRepository.TestSuite/Classes/Fakes/FakeClockFactory.php index 0ebded80a10..918cd6923d2 100644 --- a/Neos.ContentRepository.BehavioralTests/Classes/TestSuite/Behavior/FakeClockFactory.php +++ b/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeClockFactory.php @@ -2,10 +2,9 @@ declare(strict_types=1); -namespace Neos\ContentRepository\BehavioralTests\TestSuite\Behavior; +namespace Neos\ContentRepository\TestSuite\Fakes; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; -use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers\FakeClock; use Neos\ContentRepositoryRegistry\Factory\Clock\ClockFactoryInterface; use Psr\Clock\ClockInterface; diff --git a/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeContentDimensionSourceFactory.php b/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeContentDimensionSourceFactory.php new file mode 100644 index 00000000000..66a2bbd612f --- /dev/null +++ b/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeContentDimensionSourceFactory.php @@ -0,0 +1,59 @@ + $options + */ + public function build(ContentRepositoryId $contentRepositoryId, array $options): ContentDimensionSourceInterface + { + if (!self::$contentDimensionSource) { + throw new \RuntimeException('Content dimension source not initialized.'); + } + return self::$contentDimensionSource; + } + + public static function setContentDimensionSource(ContentDimensionSourceInterface $contentDimensionSource): void + { + self::$contentDimensionSource = $contentDimensionSource; + } + + /** + * Configures a zero-dimensional content repository + */ + public static function setWithoutDimensions(): void + { + self::$contentDimensionSource = new class implements ContentDimensionSourceInterface + { + public function getDimension(ContentDimensionId $dimensionId): ?ContentDimension + { + return null; + } + public function getContentDimensionsOrderedByPriority(): array + { + return []; + } + }; + } + + public static function reset(): void + { + self::$contentDimensionSource = null; + } +} diff --git a/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeNodeTypeManagerFactory.php b/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeNodeTypeManagerFactory.php new file mode 100644 index 00000000000..6a06acc6bfe --- /dev/null +++ b/Neos.ContentRepository.TestSuite/Classes/Fakes/FakeNodeTypeManagerFactory.php @@ -0,0 +1,63 @@ + $options + */ + public function build(ContentRepositoryId $contentRepositoryId, array $options): NodeTypeManager + { + if (self::$nodeTypeManager) { + return self::$nodeTypeManager; + } + if (isset($options['nodeTypes'])) { + // allows to be configured for testing + return NodeTypeManager::createFromArrayConfiguration($options['nodeTypes']); + } + throw new \RuntimeException('NodeTypeManagerFactory uninitialized'); + } + + /** + * @param array $nodeTypesToUse + */ + public static function setConfiguration(array $nodeTypesToUse): void + { + self::$nodeTypeManager = NodeTypeManager::createFromArrayConfiguration( + $nodeTypesToUse + ); + } + + public static function setNodeTypeManager(NodeTypeManager $nodeTypeManager): void + { + self::$nodeTypeManager = $nodeTypeManager; + } + + public static function reset(): void + { + self::$nodeTypeManager = null; + } +} diff --git a/Neos.ContentRepository.TestSuite/Tests/Unit/GherkinTableNodeBasedContentDimensionSourceTest.php b/Neos.ContentRepository.TestSuite/Tests/Unit/GherkinTableNodeBasedContentDimensionSourceTest.php new file mode 100644 index 00000000000..dfc29c25490 --- /dev/null +++ b/Neos.ContentRepository.TestSuite/Tests/Unit/GherkinTableNodeBasedContentDimensionSourceTest.php @@ -0,0 +1,236 @@ +valueA1'], + ['dimensionB', 'valueB1,valueB2,valueB3' , '' ], + ]; + $this->subject = GherkinTableNodeBasedContentDimensionSource::fromGherkinTableNode(new TableNode($table)); + } + + public function testEmptyDimensionConfigurationIsCorrectlyInitialized() + { + $subject = GherkinTableNodeBasedContentDimensionSource::createEmpty(); + + $this->assertSame([], $subject->getContentDimensionsOrderedByPriority()); + } + + public function testDimensionsAreInitializedInCorrectOrder() + { + $dimensions = $this->subject->getContentDimensionsOrderedByPriority(); + $dimensionKeys = array_keys($dimensions); + + $this->assertSame('dimensionA', $dimensionKeys[0]); + $this->assertSame('dimensionB', $dimensionKeys[1]); + } + + public function testDimensionValuesAreCorrectlyInitialized() + { + $dimensionA = $this->subject->getDimension(new ContentDimensionId('dimensionA')); + $dimensionB = $this->subject->getDimension(new ContentDimensionId('dimensionB')); + + $this->assertEquals( + new ContentDimensionValue( + 'valueA1', + new ContentDimensionValueSpecializationDepth(0), + ContentDimensionConstraintSet::createEmpty(), + [] + ), + $dimensionA->getValue('valueA1') + ); + $this->assertEquals( + new ContentDimensionValue( + 'valueA1.1', + new ContentDimensionValueSpecializationDepth(1), + ContentDimensionConstraintSet::createEmpty() + ), + $dimensionA->getValue('valueA1.1') + ); + $this->assertEquals( + new ContentDimensionValue( + 'valueA2', + new ContentDimensionValueSpecializationDepth(0), + ContentDimensionConstraintSet::createEmpty() + ), + $dimensionA->getValue('valueA2') + ); + + $this->assertEquals( + new ContentDimensionValue( + 'valueB1', + new ContentDimensionValueSpecializationDepth(0) + ), + $dimensionB->getValue('valueB1') + ); + $this->assertEquals( + new ContentDimensionValue( + 'valueB2', + new ContentDimensionValueSpecializationDepth(0) + ), + $dimensionB->getValue('valueB2') + ); + $this->assertEquals( + new ContentDimensionValue( + 'valueB3', + new ContentDimensionValueSpecializationDepth(0) + ), + $dimensionB->getValue('valueB3') + ); + } + + public function testSpecializationsAreCorrectlyInitialized() + { + $dimensionA = $this->subject->getDimension(new ContentDimensionId('dimensionA')); + $this->assertSame( + [ + 'valueA1.1' => $dimensionA->getValue('valueA1.1') + ], + $dimensionA->getSpecializations($dimensionA->getValue('valueA1')) + ); + $this->assertSame( + null, + $dimensionA->getGeneralization($dimensionA->getValue('valueA1')) + ); + + $this->assertSame( + [], + $dimensionA->getSpecializations($dimensionA->getValue('valueA1.1')) + ); + $this->assertSame( + $dimensionA->getValue('valueA1'), + $dimensionA->getGeneralization($dimensionA->getValue('valueA1.1')) + ); + + $this->assertSame( + [], + $dimensionA->getSpecializations($dimensionA->getValue('valueA2')) + ); + $this->assertSame( + null, + $dimensionA->getGeneralization($dimensionA->getValue('valueA2')) + ); + + $dimensionB = $this->subject->getDimension(new ContentDimensionId('dimensionB')); + $this->assertSame( + [], + $dimensionB->getSpecializations($dimensionB->getValue('valueB1')) + ); + $this->assertSame( + null, + $dimensionA->getGeneralization($dimensionB->getValue('valueB1')) + ); + + $this->assertSame( + [], + $dimensionB->getSpecializations($dimensionB->getValue('valueB2')) + ); + $this->assertSame( + null, + $dimensionA->getGeneralization($dimensionB->getValue('valueB2')) + ); + + $this->assertSame( + [], + $dimensionB->getSpecializations($dimensionB->getValue('valueB3')) + ); + $this->assertSame( + null, + $dimensionA->getGeneralization($dimensionB->getValue('valueB3')) + ); + } + + public function testMaximumDepthIsCorrectlyInitialized() + { + $dimensionA = $this->subject->getDimension(new ContentDimensionId('dimensionA')); + $dimensionB = $this->subject->getDimension(new ContentDimensionId('dimensionB')); + + $this->assertEquals( + new ContentDimensionValueSpecializationDepth(1), + $dimensionA->getMaximumDepth() + ); + $this->assertEquals( + new ContentDimensionValueSpecializationDepth(0), + $dimensionB->getMaximumDepth() + ); + } + + public function testRestrictionsAreCorrectlyInitialized() + { + $dimensionA = $this->subject->getDimension(new ContentDimensionId('dimensionA')); + $dimensionB = $this->subject->getDimension(new ContentDimensionId('dimensionB')); + + $valueA1 = $dimensionA->getValue('valueA1'); + $this->assertEquals( + ContentDimensionConstraintSet::createEmpty(), + $valueA1->constraints + ); + + $valueA11 = $dimensionA->getValue('valueA1.1'); + $this->assertEquals( + ContentDimensionConstraintSet::createEmpty(), + $valueA11->constraints + ); + + $valueA2 = $dimensionA->getValue('valueA2'); + $this->assertEquals( + ContentDimensionConstraintSet::createEmpty(), + $valueA2->constraints + ); + + $valueB1 = $dimensionB->getValue('valueB1'); + $this->assertEquals( + ContentDimensionConstraintSet::createEmpty(), + $valueB1->constraints + ); + + $valueB2 = $dimensionB->getValue('valueB2'); + $this->assertEquals( + ContentDimensionConstraintSet::createEmpty(), + $valueB2->constraints + ); + + $valueB3 = $dimensionB->getValue('valueB3'); + $this->assertEquals( + ContentDimensionConstraintSet::createEmpty(), + $valueB3->constraints + ); + } +} diff --git a/Neos.ContentRepositoryRegistry/Classes/Factory/NodeTypeManager/DefaultNodeTypeManagerFactory.php b/Neos.ContentRepositoryRegistry/Classes/Factory/NodeTypeManager/DefaultNodeTypeManagerFactory.php index 2b1d783ec05..2be87c7696a 100644 --- a/Neos.ContentRepositoryRegistry/Classes/Factory/NodeTypeManager/DefaultNodeTypeManagerFactory.php +++ b/Neos.ContentRepositoryRegistry/Classes/Factory/NodeTypeManager/DefaultNodeTypeManagerFactory.php @@ -18,7 +18,7 @@ public function __construct( /** @param array $options */ public function build(ContentRepositoryId $contentRepositoryId, array $options): NodeTypeManager { - return new NodeTypeManager( + return NodeTypeManager::createFromArrayConfigurationLoader( function () { $configuration = $this->configurationManager->getConfiguration('NodeTypes'); return $this->nodeTypeEnrichmentService->enrichNodeTypeLabelsConfiguration($configuration); diff --git a/Neos.Neos/Tests/Behavior/Features/Bootstrap/ContentRepositorySecurityTrait.php b/Neos.Neos/Tests/Behavior/Features/Bootstrap/ContentRepositorySecurityTrait.php index 86fc2bb454e..8d22c21adfc 100644 --- a/Neos.Neos/Tests/Behavior/Features/Bootstrap/ContentRepositorySecurityTrait.php +++ b/Neos.Neos/Tests/Behavior/Features/Bootstrap/ContentRepositorySecurityTrait.php @@ -20,11 +20,11 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\ContentGraphProjectionInterface; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; -use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\Helpers\TestingAuthProvider; use Neos\Flow\Mvc\ActionRequest; use Neos\Flow\Security\Authentication\Provider\TestingProvider; use Neos\Neos\Domain\Service\UserService; use Neos\Neos\Security\ContentRepositoryAuthProvider\ContentRepositoryAuthProviderFactory; +use Neos\ContentRepository\TestSuite\Fakes\FakeAuthProvider; use PHPUnit\Framework\Assert; /** @@ -57,7 +57,7 @@ abstract private function getObject(string $className): object; */ public function resetContentRepositorySecurity(): void { - TestingAuthProvider::resetAuthProvider(); + FakeAuthProvider::resetAuthProvider(); $this->crSecurity_contentRepositorySecurityEnabled = false; } @@ -81,7 +81,7 @@ public function __construct( })->contentGraphProjection; $contentRepositoryAuthProvider = $contentRepositoryAuthProviderFactory->build($this->currentContentRepository->id, $contentGraphProjection->getState()); - TestingAuthProvider::replaceAuthProvider($contentRepositoryAuthProvider); + FakeAuthProvider::replaceAuthProvider($contentRepositoryAuthProvider); $this->crSecurity_contentRepositorySecurityEnabled = true; } diff --git a/Neos.Neos/Tests/Behavior/Features/Bootstrap/FeatureContext.php b/Neos.Neos/Tests/Behavior/Features/Bootstrap/FeatureContext.php index 4580d4b5dc0..8ec72284b4d 100644 --- a/Neos.Neos/Tests/Behavior/Features/Bootstrap/FeatureContext.php +++ b/Neos.Neos/Tests/Behavior/Features/Bootstrap/FeatureContext.php @@ -14,18 +14,18 @@ use Neos\Behat\FlowBootstrapTrait; use Neos\Behat\FlowEntitiesTrait; use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\CRBehavioralTestsSubjectProvider; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinPyStringNodeBasedNodeTypeManagerFactory; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinTableNodeBasedContentDimensionSourceFactory; use Neos\ContentRepository\Core\ContentRepository; -use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryInterface; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; +use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; +use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteTrait; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\MigrationsTrait; +use Neos\ContentRepository\TestSuite\Fakes\FakeNodeTypeManagerFactory; +use Neos\ContentRepository\TestSuite\Fakes\FakeContentDimensionSourceFactory; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; -use Neos\Flow\Utility\Environment; -use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; use Neos\Flow\Persistence\PersistenceManagerInterface; +use Neos\Flow\Utility\Environment; class FeatureContext implements BehatContext { @@ -77,8 +77,8 @@ public function __construct() */ public function resetContentRepositoryComponents(): void { - GherkinTableNodeBasedContentDimensionSourceFactory::reset(); - GherkinPyStringNodeBasedNodeTypeManagerFactory::reset(); + FakeContentDimensionSourceFactory::reset(); + FakeNodeTypeManagerFactory::reset(); } /** @@ -110,8 +110,8 @@ protected function createContentRepository( ): ContentRepository { $this->contentRepositoryRegistry->resetFactoryInstance($contentRepositoryId); $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - GherkinTableNodeBasedContentDimensionSourceFactory::reset(); - GherkinPyStringNodeBasedNodeTypeManagerFactory::reset(); + FakeContentDimensionSourceFactory::reset(); + FakeNodeTypeManagerFactory::reset(); return $contentRepository; } diff --git a/Neos.Neos/Tests/Functional/Service/NodeTypeSchemaBuilderTest.php b/Neos.Neos/Tests/Functional/Service/NodeTypeSchemaBuilderTest.php index a71db4cd5fe..abc88364265 100644 --- a/Neos.Neos/Tests/Functional/Service/NodeTypeSchemaBuilderTest.php +++ b/Neos.Neos/Tests/Functional/Service/NodeTypeSchemaBuilderTest.php @@ -38,7 +38,7 @@ public function setUp(): void parent::setUp(); $configurationManager = $this->objectManager->get(ConfigurationManager::class); $this->nodeTypeSchemaBuilder = NodeTypeSchemaBuilder::create( - new NodeTypeManager( + NodeTypeManager::createFromArrayConfigurationLoader( fn() => $configurationManager->getConfiguration('NodeTypes') ) ); diff --git a/Neos.TimeableNodeVisibility/Tests/Behavior/Bootstrap/FeatureContext.php b/Neos.TimeableNodeVisibility/Tests/Behavior/Bootstrap/FeatureContext.php index d1b22507e62..2656730cb90 100644 --- a/Neos.TimeableNodeVisibility/Tests/Behavior/Bootstrap/FeatureContext.php +++ b/Neos.TimeableNodeVisibility/Tests/Behavior/Bootstrap/FeatureContext.php @@ -4,8 +4,6 @@ use Behat\Behat\Context\Context; use Neos\Behat\FlowBootstrapTrait; use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\CRBehavioralTestsSubjectProvider; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinPyStringNodeBasedNodeTypeManagerFactory; -use Neos\ContentRepository\BehavioralTests\TestSuite\Behavior\GherkinTableNodeBasedContentDimensionSourceFactory; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryInterface; use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface; @@ -14,6 +12,8 @@ use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteTrait; +use Neos\ContentRepository\TestSuite\Fakes\FakeNodeTypeManagerFactory; +use Neos\ContentRepository\TestSuite\Fakes\FakeContentDimensionSourceFactory; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\TimeableNodeVisibility\Service\TimeableNodeVisibilityService; use PHPUnit\Framework\Assert; @@ -91,8 +91,8 @@ protected function createContentRepository( ): ContentRepository { $this->contentRepositoryRegistry->resetFactoryInstance($contentRepositoryId); $contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId); - GherkinTableNodeBasedContentDimensionSourceFactory::reset(); - GherkinPyStringNodeBasedNodeTypeManagerFactory::reset(); + FakeContentDimensionSourceFactory::reset(); + FakeNodeTypeManagerFactory::reset(); return $contentRepository; } diff --git a/composer.json b/composer.json index 03aa1e334b2..63c270f6526 100644 --- a/composer.json +++ b/composer.json @@ -110,7 +110,7 @@ ], "test:paratest-cli": "../../bin/paratest --debug -v --functional --processes 2 --colors --stop-on-failure -c ../../Build/BuildEssentials/PhpUnit/FunctionalTests.xml", "test:parallel": [ - "for f in Neos.ContentRepository.BehavioralTests/Tests/Parallel/**/*Test.php; do composer test:paratest-cli $f; done" + "for f in Neos.ContentRepository.BehavioralTests/Tests/Parallel/**/*Test.php; do composer test:paratest-cli $f || exit 1; done" ], "test:behat-cli": "../../bin/behat -f progress --strict --no-interaction", "test:behavioral": [