From 8a35000d807fb502c3c2332378971e23a1941fcf Mon Sep 17 00:00:00 2001 From: sebprt Date: Fri, 28 Jun 2024 09:13:09 +0200 Subject: [PATCH 1/2] Fixed normalisation for expression fields --- src/Cloud/Pipeline.php | 17 +++++++++++++---- src/Cloud/Workflow.php | 34 ++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/Cloud/Pipeline.php b/src/Cloud/Pipeline.php index ff7e9417..b3c03f32 100644 --- a/src/Cloud/Pipeline.php +++ b/src/Cloud/Pipeline.php @@ -35,11 +35,20 @@ public static function fromLegacyConfiguration(array $configuration): DTO\Pipeli $code = $stepConfig['code'] ?? sprintf('step%d', $order); unset($stepConfig['name'], $stepConfig['code']); - array_walk_recursive($stepConfig, function (&$value): void { - if ($value instanceof Expression) { - $value = '@='.$value; + array_walk_recursive( + $stepConfig, + function (&$value, $key) { + if ($value instanceof Expression && $key === 'expression') { + $value = (string) $value; + } + + if ($value instanceof Expression) { + $value = '@=' . $value; + } + + return $value; } - }); + ); return new DTO\Step( $name, diff --git a/src/Cloud/Workflow.php b/src/Cloud/Workflow.php index fec07ff9..4838e07f 100644 --- a/src/Cloud/Workflow.php +++ b/src/Cloud/Workflow.php @@ -40,11 +40,20 @@ function (array $config, int $order) { $code = $config['pipeline']['code'] ?? sprintf('pipeline%d', $order); unset($config['pipeline']['name'], $config['pipeline']['code']); - array_walk_recursive($config, function (&$value): void { - if ($value instanceof Expression) { - $value = '@='.$value; + array_walk_recursive( + $config, + function (&$value, $key) { + if ($value instanceof Expression && $key === 'expression') { + $value = (string) $value; + } + + if ($value instanceof Expression) { + $value = '@=' . $value; + } + + return $value; } - }); + ); return new DTO\Workflow\Pipeline( $name, @@ -70,11 +79,20 @@ function (array $config, int $order) { $code = $config['action']['code'] ?? sprintf('action%d', $order); unset($config['action']['name'], $config['action']['code']); - array_walk_recursive($config, function (&$value): void { - if ($value instanceof Expression) { - $value = '@='.$value; + array_walk_recursive( + $config, + function (&$value, $key) { + if ($value instanceof Expression && $key === 'expression') { + $value = (string) $value; + } + + if ($value instanceof Expression) { + $value = '@=' . $value; + } + + return $value; } - }); + ); $configuration = $config['action']; unset($config['action']); From c99f8e21e67162538caa1eff6fff94b35931c382 Mon Sep 17 00:00:00 2001 From: sebprt Date: Mon, 1 Jul 2024 12:28:09 +0200 Subject: [PATCH 2/2] Added tests for the Cloud --- tests/unit/Cloud/Client/GetWorkflowItem.php | 19 ++ .../GetWorkflowItemThrowNotFoundException.php | 14 + tests/unit/Cloud/DummyContext.php | 32 ++ tests/unit/Cloud/WorkflowTest.php | 306 ++++++++++++++++++ 4 files changed, 371 insertions(+) create mode 100644 tests/unit/Cloud/Client/GetWorkflowItem.php create mode 100644 tests/unit/Cloud/Client/GetWorkflowItemThrowNotFoundException.php create mode 100644 tests/unit/Cloud/DummyContext.php create mode 100644 tests/unit/Cloud/WorkflowTest.php diff --git a/tests/unit/Cloud/Client/GetWorkflowItem.php b/tests/unit/Cloud/Client/GetWorkflowItem.php new file mode 100644 index 00000000..effb222c --- /dev/null +++ b/tests/unit/Cloud/Client/GetWorkflowItem.php @@ -0,0 +1,19 @@ +setId($id); + $workflowRead->setLabel('Extract data from Akeneo'); + $workflowRead->setCode('from_akeneo'); + + return $workflowRead; + } +} diff --git a/tests/unit/Cloud/Client/GetWorkflowItemThrowNotFoundException.php b/tests/unit/Cloud/Client/GetWorkflowItemThrowNotFoundException.php new file mode 100644 index 00000000..421157c9 --- /dev/null +++ b/tests/unit/Cloud/Client/GetWorkflowItemThrowNotFoundException.php @@ -0,0 +1,14 @@ +changeOrganization(new Satellite\Cloud\DTO\OrganizationId('5624f073-4085-42ee-b33b-e8869c3f2f51')); + $context->changeWorkspace(new Satellite\Cloud\DTO\WorkspaceId('577d9281-88ad-45be-8e12-307adf5e787c')); + } + + public function testLegacyConfiguration(): void + { + $workflow = Satellite\Cloud\Workflow::fromLegacyConfiguration( + [ + 'composer' => [ + 'autoload' => ['psr4' => ['Namespace\\' => ['paths' => ['path/to/namespace']]]], + 'require' => ['vendor/package', 'vendor/package2'], + 'repositories' => [['name' => 'Repo Name', 'type' => 'git', 'url' => 'http://repo.url']], + 'auth' => [['url' => 'http://auth.url', 'token' => 'authToken']] + ], + 'code' => 'my_workflow', + 'workflow' => [ + 'jobs' => [ + [ + 'pipeline' => [ + 'name' => 'My products pipeline', + 'code' => 'products_pipeline', + 'steps' => [ + [ + 'name' => 'Extract products', + 'code' => 'csv.extractor', + 'csv' => + [ + 'extractor' => + [ + 'file_path' => '../data/products.csv', + ], + ], + ], + [ + 'name' => 'Transform', + 'code' => 'fastmap', + 'fastmap' => + [ + 'map' => + [ + [ + 'copy' => '[identifier]', + 'field' => '[sku]', + ], + ], + ], + ], + [ + 'name' => 'Loads products', + 'code' => 'stream.loader', + 'stream' => + [ + 'loader' => + [ + 'destination' => '../data/products.ldjson', + 'format' => 'json', + ], + ], + ], + ], + ], + ], + ['action' => ['name' => 'Test Action', 'code' => 'action123']] + + ], + ], + ], + ); + + $this->assertInstanceOf(Satellite\Cloud\DTO\Workflow::class, $workflow); + $this->assertEquals('my_workflow', $workflow->code()); + $this->assertEquals(1, $workflow->composer()->autoload()->count()); + $this->assertEquals(1, $workflow->composer()->auths()->count()); + $this->assertEquals(1, $workflow->composer()->repositories()->count()); + $this->assertEquals(2, $workflow->composer()->packages()->count()); + $this->assertEquals(2, $workflow->jobs()->count()); + } + + public function testCreatesDefaultNameAndCodeIfNotProvided(): void { + $configuration = [ + 'workflow' => [ + 'name' => 'Test Workflow', + 'jobs' => [ + ['pipeline' => ['name' => 'Test Pipeline', 'code' => 'pipeline123', 'steps' => []]], + ['action' => ['name' => 'Test Action', 'code' => 'action123']] + ] + ] + ]; + + $workflow = Satellite\Cloud\Workflow::fromLegacyConfiguration($configuration); + + $this->assertInstanceOf(Satellite\Cloud\DTO\Workflow::class, $workflow); + $this->assertMatchesRegularExpression('/workflow[a-f0-9]{8}/', $workflow->code()); + } + + public function testFromLegacyConfigurationWithEmptyConfig() + { + $this->expectException(\RuntimeException::class); + + $workflow = Satellite\Cloud\Workflow::fromLegacyConfiguration([]); + + $this->assertInstanceOf(Satellite\Cloud\DTO\Workflow::class, $workflow); + } + + public function testThrowsExceptionForUnsupportedJobType() + { + $configuration = [ + 'workflow' => ['jobs' => [['invalidType' => []]]], + 'composer' => [ + 'autoload' => ['psr4' => []], + 'require' => [], + 'repositories' => [] + ] + ]; + + $this->expectException(\RuntimeException::class); + + Satellite\Cloud\Workflow::fromLegacyConfiguration($configuration); + } + + public function testFromLegacyConfigurationWithExpressions() + { + $configuration = [ + 'workflow' => [ + 'jobs' => [ + [ + 'pipeline' => [ + 'code' => 'pipelineCode', + 'steps' => [ + [ + 'csv' => [ + 'extractor' => [ + 'file_path' => new Expression('../data/products.csv'), + ], + ], + ], + [ + 'fastmap' => [ + 'map' => [ + 'expression' => new Expression('value > 100'), + ], + ], + ], + ], + ], + ], + ], + ], + 'composer' => [ + 'autoload' => ['psr4' => []], + 'require' => [], + 'repositories' => [] + ] + ]; + + $workflow = Satellite\Cloud\Workflow::fromLegacyConfiguration($configuration); + + WorkflowTest::assertStringNotStartsWith( + '@=', $workflow->jobs()->get('pipelineCode')->stepList->get('step1')->config['fastmap']['map']['expression'] + ); + WorkflowTest::assertStringStartsWith( + '@=', $workflow->jobs()->get('pipelineCode')->stepList->get('step0')->config['csv']['extractor']['file_path'] + ); + } + + public function testFromApiWithIdIsSuccessful() + { + $workflowId = new Satellite\Cloud\DTO\WorkflowId('fe8a4711-624d-44ad-a4a5-e578427a7887'); + + $result = Satellite\Cloud\Workflow::fromApiWithId( + GetWorkflowItem::create(), + $workflowId + ); + + $this->assertInstanceOf(Satellite\Cloud\DTO\ReferencedWorkflow::class, $result); + $this->assertEquals('fe8a4711-624d-44ad-a4a5-e578427a7887', $result->id()->asString()); + } + + public function testFromApiWithIdThrowException() + { + $workflowId = new Satellite\Cloud\DTO\WorkflowId('fe8a4711-624d-44ad-a4a5-e578427a7887'); + + $this->expectException(Satellite\Cloud\AccessDeniedException::class); + $this->expectExceptionMessage('Could not retrieve the workflow.'); + + Satellite\Cloud\Workflow::fromApiWithId( + GetWorkflowItemThrowNotFoundException::create(), + $workflowId + ); + } + + public function testCreate() + { + $workflow = new Satellite\Cloud\Workflow( + new DummyContext() + ); + + $commandBatch = $workflow->create( + new Satellite\Cloud\DTO\Workflow( + 'Test Workflow', + 'test_workflow', + new Satellite\Cloud\DTO\JobList(), + new Satellite\Cloud\DTO\Composer( + new Satellite\Cloud\DTO\Autoload(), + new Satellite\Cloud\DTO\PackageList(), + new Satellite\Cloud\DTO\RepositoryList(), + new Satellite\Cloud\DTO\AuthList(), + ), + ) + ); + + $this->assertInstanceOf(Satellite\Cloud\DTO\CommandBatch::class, $commandBatch); + $this->assertCount(1, $commands = $commandBatch->getIterator()); + + $this->assertInstanceOf(Satellite\Cloud\Command\Workflow\DeclareWorkflowCommand::class, $commands[0]); + } + + public function testUpdate() + { + $workflow = new Satellite\Cloud\Workflow( + new DummyContext() + ); + + $commandBatch = $workflow->update( + new Satellite\Cloud\DTO\ReferencedWorkflow( + new Satellite\Cloud\DTO\WorkflowId('fe8a4711-624d-44ad-a4a5-e578427a7887'), + new Satellite\Cloud\DTO\Workflow( + 'Test Workflow', + 'test_workflow', + new Satellite\Cloud\DTO\JobList(), + new Satellite\Cloud\DTO\Composer( + new Satellite\Cloud\DTO\Autoload(), + new Satellite\Cloud\DTO\PackageList(), + new Satellite\Cloud\DTO\RepositoryList(), + new Satellite\Cloud\DTO\AuthList(), + ), + ), + ), + new Satellite\Cloud\DTO\Workflow( + 'Test Workflow', + 'test_workflow', + new Satellite\Cloud\DTO\JobList( + new Satellite\Cloud\DTO\Workflow\Pipeline( + 'Extract product from csv', + new Satellite\Cloud\DTO\JobCode('csv.extractor'), + new Satellite\Cloud\DTO\StepList(), + 0 + ) + ), + new Satellite\Cloud\DTO\Composer( + new Satellite\Cloud\DTO\Autoload(), + new Satellite\Cloud\DTO\PackageList(), + new Satellite\Cloud\DTO\RepositoryList(), + new Satellite\Cloud\DTO\AuthList(), + ), + ), + ); + + $this->assertInstanceOf(Satellite\Cloud\DTO\CommandBatch::class, $commandBatch); + $this->assertCount(1, $commands = $commandBatch->getIterator()); + + $this->assertInstanceOf(Satellite\Cloud\Command\Workflow\PrependWorkflowJobCommand::class, $commands[0]); + } + + public function testRemove() + { + $workflow = new Satellite\Cloud\Workflow( + new DummyContext() + ); + + $commandBatch = $workflow->remove( + new Satellite\Cloud\DTO\WorkflowId('fe8a4711-624d-44ad-a4a5-e578427a7887') + ); + + $this->assertInstanceOf(Satellite\Cloud\DTO\CommandBatch::class, $commandBatch); + $this->assertCount(1, $commands = $commandBatch->getIterator()); + + $this->assertInstanceOf(Satellite\Cloud\Command\Workflow\RemoveWorkflowCommand::class, $commands[0]); + } + + public static function assertStringNotStartsWith(mixed $needle, string $haystack, string $message = ''): void + { + $constraint = new LogicalNot( + new StringStartsWith($needle), + ); + + static::assertThat($haystack, $constraint, $message); + } +}