Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUGFIX: Fix Neos.ContentRepository.LegacyNodeMigration behat tests #4548

Merged
merged 5 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"type": "neos-package-collection",
"require": {
"neos/flow-development-collection": "9.0.x-dev",
"neos/neos-setup": "^2.0"
"neos/neos-setup": "^2.0",
"league/flysystem-memory": "^3"
},
"replace": {
},
Expand Down Expand Up @@ -40,7 +41,8 @@
"../../bin/behat -vvv --stop-on-failure -f progress -c Neos.ContentRepository.BehavioralTests/Tests/Behavior/behat.yml.dist",
"../../bin/behat -vvv --stop-on-failure -f progress -c Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/behat.yml.dist",
"../../flow doctrine:migrate --quiet; ../../flow cr:setup",
"../../bin/behat -vvv --stop-on-failure -f progress -c Neos.Neos/Tests/Behavior/behat.yml.dist --tags ~@browser"
"../../bin/behat -vvv --stop-on-failure -f progress -c Neos.Neos/Tests/Behavior/behat.yml.dist --tags ~@browser",
"../../bin/behat -vvv --stop-on-failure -f progress -c Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/behat.yml.dist"
],
"test": [
"@test:unit",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Neos\ContentRepository\LegacyNodeMigration;

use Doctrine\DBAL\Platforms\PostgreSQL100Platform;
use Doctrine\DBAL\Types\ConversionException;
use League\Flysystem\Filesystem;
use League\Flysystem\FilesystemException;
use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet;
Expand Down Expand Up @@ -272,7 +273,11 @@ public function extractPropertyValuesAndReferences(array $nodeDataRow, NodeType
$references = [];

// Note: We use a PostgreSQL platform because the implementation is forward-compatible, @see JsonArrayType::convertToPHPValue()
$decodedProperties = (new JsonArrayType())->convertToPHPValue($nodeDataRow['properties'], new PostgreSQL100Platform());
try {
$decodedProperties = (new JsonArrayType())->convertToPHPValue($nodeDataRow['properties'], new PostgreSQL100Platform());
} catch (ConversionException $exception) {
throw new MigrationException(sprintf('Failed to decode properties %s of node "%s" (type: "%s"): %s', json_encode($nodeDataRow['properties']), $nodeDataRow['identifier'], $nodeType->name->value, $exception->getMessage()), 1695391558, $exception);
}
if (!is_array($decodedProperties)) {
throw new MigrationException(sprintf('Failed to decode properties %s of node "%s" (type: "%s")', json_encode($nodeDataRow['properties']), $nodeDataRow['identifier'], $nodeType->name->value), 1656057035);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,16 @@
use League\Flysystem\Filesystem;
use League\Flysystem\InMemory\InMemoryFilesystemAdapter;
use Neos\Behat\Tests\Behat\FlowContextTrait;
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\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteTrait;
use Neos\ContentRepository\Core\Factory\ContentRepositoryId;
use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceFactoryInterface;
use Neos\ContentRepository\Core\Factory\ContentRepositoryServiceInterface;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId;
use Neos\ContentRepository\Export\Asset\AssetExporter;
use Neos\ContentRepository\Export\Asset\AssetLoaderInterface;
use Neos\ContentRepository\Export\Asset\ResourceLoaderInterface;
Expand All @@ -24,9 +31,8 @@
use Neos\ContentRepository\Export\Severity;
use Neos\ContentRepository\LegacyNodeMigration\NodeDataToAssetsProcessor;
use Neos\ContentRepository\LegacyNodeMigration\NodeDataToEventsProcessor;
use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId;
use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId;
use Neos\ContentRepositoryRegistry\TestSuite\Behavior\CRRegistrySubjectProvider;
use Neos\ContentRepository\TestSuite\Behavior\Features\Bootstrap\CRTestSuiteTrait;
use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry;
use Neos\Flow\Property\PropertyMapper;
use Neos\Flow\ResourceManagement\PersistentResource;
use PHPUnit\Framework\Assert;
Expand All @@ -39,7 +45,7 @@ class FeatureContext implements Context
{
use FlowContextTrait;
use CRTestSuiteTrait;
use CRRegistrySubjectProvider;
use CRBehavioralTestsSubjectProvider;

protected $isolated = false;

Expand All @@ -53,18 +59,26 @@ class FeatureContext implements Context

private ProcessorResult|null $lastMigrationResult = null;

/**
* @var array<string>
*/
private array $loggedErrors = [];

private ContentRepository $contentRepository;

protected ContentRepositoryRegistry $contentRepositoryRegistry;

public function __construct()
{
if (self::$bootstrap === null) {
self::$bootstrap = $this->initializeFlow();
}
$this->objectManager = self::$bootstrap->getObjectManager();
$this->contentRepositoryRegistry = $this->objectManager->get(ContentRepositoryRegistry::class);

$this->mockFilesystemAdapter = new InMemoryFilesystemAdapter();
$this->mockFilesystem = new Filesystem($this->mockFilesystemAdapter);
$this->setupCRTestSuiteTrait();

}

/**
Expand All @@ -73,7 +87,10 @@ public function __construct()
public function failIfLastMigrationHasErrors(): void
{
if ($this->lastMigrationResult !== null && $this->lastMigrationResult->severity === Severity::ERROR) {
Assert::fail(sprintf('The last migration run led to an error: %s', $this->lastMigrationResult->message));
throw new \RuntimeException(sprintf('The last migration run led to an error: %s', $this->lastMigrationResult->message));
}
if ($this->loggedErrors !== []) {
throw new \RuntimeException(sprintf('The last migration run logged %d error%s', count($this->loggedErrors), count($this->loggedErrors) === 1 ? '' : 's'));
}
}

Expand Down Expand Up @@ -126,6 +143,11 @@ public function iRunTheEventMigration(string $contentStream = null): void
if ($contentStream !== null) {
$migration->setContentStreamId(ContentStreamId::fromString($contentStream));
}
$migration->onMessage(function (Severity $severity, string $message) {
if ($severity === Severity::ERROR) {
$this->loggedErrors[] = $message;
}
});
$this->lastMigrationResult = $migration->run();
}

Expand Down Expand Up @@ -166,6 +188,15 @@ public function iExpectTheFollowingEventsToBeExported(TableNode $table): void
Assert::assertCount(count($table->getHash()), $exportedEvents, 'Expected number of events does not match actual number');
}

/**
* @Then I expect the following errors to be logged
*/
public function iExpectTheFollwingErrorsToBeLogged(TableNode $table): void
{
Assert::assertSame($this->loggedErrors, $table->getColumn(0), 'Expected logged errors do not match');
$this->loggedErrors = [];
}

/**
* @Then I expect a MigrationError
* @Then I expect a MigrationError with the message
Expand Down Expand Up @@ -278,6 +309,11 @@ public function findAssetById(string $assetId): SerializedAsset|SerializedImageV
$this->mockFilesystemAdapter->deleteEverything();
$assetExporter = new AssetExporter($this->mockFilesystem, $mockAssetLoader, $mockResourceLoader);
$migration = new NodeDataToAssetsProcessor($nodeTypeManager, $assetExporter, $this->nodeDataRows);
$migration->onMessage(function (Severity $severity, string $message) {
if ($severity === Severity::ERROR) {
$this->loggedErrors[] = $message;
}
});
$this->lastMigrationResult = $migration->run();
}

Expand Down Expand Up @@ -345,4 +381,24 @@ private function parseJsonTable(TableNode $table): array
}, $row);
}, $table->getHash());
}

protected function getContentRepositoryService(
ContentRepositoryServiceFactoryInterface $factory
): ContentRepositoryServiceInterface {
return $this->contentRepositoryRegistry->buildService(
$this->currentContentRepository->id,
$factory
);
}

protected function createContentRepository(
ContentRepositoryId $contentRepositoryId
): ContentRepository {
$this->contentRepositoryRegistry->resetFactoryInstance($contentRepositoryId);
$contentRepository = $this->contentRepositoryRegistry->get($contentRepositoryId);
GherkinTableNodeBasedContentDimensionSourceFactory::reset();
GherkinPyStringNodeBasedNodeTypeManagerFactory::reset();

return $contentRepository;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,5 @@ Feature: Export of used Assets, Image Variants and Persistent Resources
Then I expect no Assets to be exported
And I expect no ImageVariants to be exported
And I expect no PersistentResources to be exported
And I expect the following errors to be logged
| Failed to extract assets of property "string" of node "site-node-id" (type: "Some.Package:SomeNodeType"): Failed to find mock asset with id "non-existing-asset" |
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,23 @@ Feature: Exceptional cases during migrations
Node aggregate with id "site-node-id" has a type of "Some.Package:SomeOtherNodeType" in content dimension [{"language":"en"}]. I was visited previously for content dimension [{"language":"de"}] with the type "Some.Package:SomeNodeType". Node variants must not have different types
"""

# Note: The behavior was changed with https://github.com/neos/neos-development-collection/pull/4201
Scenario: Node with missing parent
When I have the following node data rows:
| Identifier | Path |
| sites | /sites |
| a | /sites/a |
| c | /sites/b/c |
And I run the event migration
Then I expect a MigrationError with the message
"""
Failed to find parent node for node with id "c" and dimensions: []. Did you properly configure your dimensions setup to be in sync with the old setup?
"""
Then I expect the following events to be exported
| Type | Payload |
| RootNodeAggregateWithNodeWasCreated | {"nodeAggregateId": "sites", "nodeTypeName": "Neos.Neos:Sites", "nodeAggregateClassification": "root"} |
| NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a", "parentNodeAggregateId": "sites"} |
And I expect the following errors to be logged
| Failed to find parent node for node with id "c" and dimensions: []. Please ensure that the new content repository has a valid content dimension configuration. Also note that the old CR can sometimes have orphaned nodes. |

# TODO: is it possible that nodes are processed in an order where a ancestor node is processed after a child node? -> in that case the following example should work (i.e. the scenario should fail)

# Note: The behavior was changed with https://github.com/neos/neos-development-collection/pull/4201
Scenario: Nodes out of order
When I have the following node data rows:
| Identifier | Path |
Expand All @@ -52,10 +56,14 @@ Feature: Exceptional cases during migrations
| c | /sites/b/c |
| b | /sites/b |
And I run the event migration
Then I expect a MigrationError with the message
"""
Failed to find parent node for node with id "c" and dimensions: []. Did you properly configure your dimensions setup to be in sync with the old setup?
"""
Then I expect the following events to be exported
| Type | Payload |
| RootNodeAggregateWithNodeWasCreated | {"nodeAggregateId": "sites", "nodeTypeName": "Neos.Neos:Sites", "nodeAggregateClassification": "root"} |
| NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a", "parentNodeAggregateId": "sites"} |
| NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "b", "parentNodeAggregateId": "sites"} |
And I expect the following errors to be logged
| Failed to find parent node for node with id "c" and dimensions: []. Please ensure that the new content repository has a valid content dimension configuration. Also note that the old CR can sometimes have orphaned nodes. |


Scenario: Invalid dimension configuration (unknown value)
Given I change the content dimensions in content repository "default" to:
Expand All @@ -66,7 +74,11 @@ Feature: Exceptional cases during migrations
| sites | /sites | |
| a | /sites/a | {"language": ["unknown"]} |
And I run the event migration
Then I expect a MigrationError
Then I expect the following events to be exported
| Type | Payload |
| RootNodeAggregateWithNodeWasCreated | {"nodeAggregateId": "sites", "nodeTypeName": "Neos.Neos:Sites", "nodeAggregateClassification": "root"} |
And I expect the following errors to be logged
| Failed to find parent node for node with id "a" and dimensions: {"language":"unknown"}. Please ensure that the new content repository has a valid content dimension configuration. Also note that the old CR can sometimes have orphaned nodes. |

Scenario: Invalid dimension configuration (no json)
When I have the following node data rows:
Expand All @@ -84,7 +96,7 @@ Feature: Exceptional cases during migrations
And I run the event migration
Then I expect a MigrationError with the message
"""
Failed to decode properties "not json" of node "a" (type: "Some.Package:SomeNodeType")
Failed to decode properties "not json" of node "a" (type: "Some.Package:SomeNodeType"): Could not convert database value "not json" to Doctrine Type flow_json_array
"""

Scenario: Node variants with the same dimension
Expand Down
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"neos/fusion-form": "^1.0 || ^2.0",
"behat/transliterator": "~1.0",
"neos/form": "*",
"neos/kickstarter": "~9.0.0"
"neos/kickstarter": "~9.0.0",
"league/flysystem-memory": "^3"
},
"replace": {
"packagefactory/atomicfusion-afx": "*",
Expand Down Expand Up @@ -117,7 +118,8 @@
"../../bin/behat -vvv --stop-on-failure -f progress -c Neos.ContentRepository.BehavioralTests/Tests/Behavior/behat.yml.dist",
"../../bin/behat -vvv --stop-on-failure -f progress -c Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/behat.yml.dist",
"../../flow doctrine:migrate --quiet; ../../flow cr:setup",
"../../bin/behat -vvv --stop-on-failure -f progress -c Neos.Neos/Tests/Behavior/behat.yml.dist --tags ~@browser"
"../../bin/behat -vvv --stop-on-failure -f progress -c Neos.Neos/Tests/Behavior/behat.yml.dist --tags ~@browser",
"../../bin/behat -vvv --stop-on-failure -f progress -c Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/behat.yml.dist"
],
"test": [
"@test:unit",
Expand Down
Loading