From 1298f8c26ef28e4fbb127d3f40949e6092188395 Mon Sep 17 00:00:00 2001 From: Spryker Release Bot Date: Thu, 4 Jul 2024 11:39:36 +0300 Subject: [PATCH] FRW-8523 Introduced caching for OMS processes. (#10973) FRW-8523 Introduced caching for OMS processes. --- composer.json | 1 + src/Spryker/Shared/Oms/OmsConstants.php | 10 ++ .../Zed/Oms/Business/OmsBusinessFactory.php | 25 ++++ .../Business/OrderStateMachine/Builder.php | 66 +++++++-- .../Zed/Oms/Business/Process/Process.php | 97 ++++++++++++- .../Oms/Business/Process/ProcessInterface.php | 5 + .../Business/Reader/ProcessCacheReader.php | 62 ++++++++ .../Reader/ProcessCacheReaderInterface.php | 34 +++++ .../Business/Writer/ProcessCacheWriter.php | 69 +++++++++ .../Writer/ProcessCacheWriterInterface.php | 21 +++ .../Console/ProcessCacheWarmUpConsole.php | 56 ++++++++ src/Spryker/Zed/Oms/OmsConfig.php | 39 +++++ .../OrderStateMachine/BuilderTest.php | 67 +++++---- .../Business/OrderStateMachine/FinderTest.php | 8 ++ .../Reader/ProcessCacheReaderTest.php | 134 ++++++++++++++++++ .../Util/ActiveProcessFetcherTest.php | 8 ++ .../Writer/ProcessCacheWriterTest.php | 127 +++++++++++++++++ .../Zed/Oms/_support/OmsBusinessTester.php | 20 +++ 18 files changed, 798 insertions(+), 51 deletions(-) create mode 100644 src/Spryker/Zed/Oms/Business/Reader/ProcessCacheReader.php create mode 100644 src/Spryker/Zed/Oms/Business/Reader/ProcessCacheReaderInterface.php create mode 100644 src/Spryker/Zed/Oms/Business/Writer/ProcessCacheWriter.php create mode 100644 src/Spryker/Zed/Oms/Business/Writer/ProcessCacheWriterInterface.php create mode 100644 src/Spryker/Zed/Oms/Communication/Console/ProcessCacheWarmUpConsole.php create mode 100644 tests/SprykerTest/Zed/Oms/Business/Reader/ProcessCacheReaderTest.php create mode 100644 tests/SprykerTest/Zed/Oms/Business/Writer/ProcessCacheWriterTest.php diff --git a/composer.json b/composer.json index 9a1f7903..8611b14d 100644 --- a/composer.json +++ b/composer.json @@ -4,6 +4,7 @@ "description": "Oms module", "license": "proprietary", "require": { + "ext-simplexml": "*", "php": ">=8.1", "spryker/acl-merchant-portal-extension": "^1.0.0", "spryker/decimal-object": "^1.0.0", diff --git a/src/Spryker/Shared/Oms/OmsConstants.php b/src/Spryker/Shared/Oms/OmsConstants.php index 0858d8bf..52bc9ac8 100644 --- a/src/Spryker/Shared/Oms/OmsConstants.php +++ b/src/Spryker/Shared/Oms/OmsConstants.php @@ -41,4 +41,14 @@ interface OmsConstants * @var string */ public const ENABLE_OMS_TRANSITION_LOG = 'OMS:ENABLE_OMS_TRANSITION_LOG'; + + /** + * Specification: + * - Defines where to store cached processes. + * + * @api + * + * @var string + */ + public const PROCESS_CACHE_PATH = 'OMS:PROCESS_CACHE_PATH'; } diff --git a/src/Spryker/Zed/Oms/Business/OmsBusinessFactory.php b/src/Spryker/Zed/Oms/Business/OmsBusinessFactory.php index 8dbd57d5..79577737 100644 --- a/src/Spryker/Zed/Oms/Business/OmsBusinessFactory.php +++ b/src/Spryker/Zed/Oms/Business/OmsBusinessFactory.php @@ -38,6 +38,8 @@ use Spryker\Zed\Oms\Business\Process\Process; use Spryker\Zed\Oms\Business\Process\State; use Spryker\Zed\Oms\Business\Process\Transition; +use Spryker\Zed\Oms\Business\Reader\ProcessCacheReader; +use Spryker\Zed\Oms\Business\Reader\ProcessCacheReaderInterface; use Spryker\Zed\Oms\Business\Reader\ReservationReader; use Spryker\Zed\Oms\Business\Reader\ReservationReaderInterface; use Spryker\Zed\Oms\Business\Reader\StateMachineReader; @@ -54,6 +56,8 @@ use Spryker\Zed\Oms\Business\Util\TimeoutProcessorCollection; use Spryker\Zed\Oms\Business\Util\TimeoutProcessorCollectionInterface; use Spryker\Zed\Oms\Business\Util\TransitionLog; +use Spryker\Zed\Oms\Business\Writer\ProcessCacheWriter; +use Spryker\Zed\Oms\Business\Writer\ProcessCacheWriterInterface; use Spryker\Zed\Oms\OmsDependencyProvider; /** @@ -127,6 +131,8 @@ public function createOrderStateMachineBuilder() $this->createProcessTransition(), $this->createProcessProcess(), $this->getConfig()->getProcessDefinitionLocation(), + $this->createProcessCacheReader(), + $this->createProcessCacheWriter(), $this->getConfig()->getSubProcessPrefixDelimiter(), ); } @@ -598,4 +604,23 @@ public function getOmsEventTriggeredListenerPlugins(): array { return $this->getProvidedDependency(OmsDependencyProvider::PLUGINS_OMS_EVENT_TRIGGERED_LISTENER); } + + /** + * @return \Spryker\Zed\Oms\Business\Reader\ProcessCacheReaderInterface + */ + public function createProcessCacheReader(): ProcessCacheReaderInterface + { + return new ProcessCacheReader($this->getConfig()); + } + + /** + * @return \Spryker\Zed\Oms\Business\Writer\ProcessCacheWriterInterface + */ + public function createProcessCacheWriter(): ProcessCacheWriterInterface + { + return new ProcessCacheWriter( + $this->getConfig(), + $this->createProcessCacheReader(), + ); + } } diff --git a/src/Spryker/Zed/Oms/Business/OrderStateMachine/Builder.php b/src/Spryker/Zed/Oms/Business/OrderStateMachine/Builder.php index 5329bd9a..d9455fcb 100644 --- a/src/Spryker/Zed/Oms/Business/OrderStateMachine/Builder.php +++ b/src/Spryker/Zed/Oms/Business/OrderStateMachine/Builder.php @@ -14,6 +14,8 @@ use Spryker\Zed\Oms\Business\Process\ProcessInterface; use Spryker\Zed\Oms\Business\Process\StateInterface; use Spryker\Zed\Oms\Business\Process\TransitionInterface; +use Spryker\Zed\Oms\Business\Reader\ProcessCacheReaderInterface; +use Spryker\Zed\Oms\Business\Writer\ProcessCacheWriterInterface; use Symfony\Component\Finder\Finder as SymfonyFinder; class Builder implements BuilderInterface @@ -58,12 +60,24 @@ class Builder implements BuilderInterface */ protected $subProcessPrefixDelimiter; + /** + * @var \Spryker\Zed\Oms\Business\Reader\ProcessCacheReaderInterface + */ + protected ProcessCacheReaderInterface $processCacheReader; + + /** + * @var \Spryker\Zed\Oms\Business\Writer\ProcessCacheWriterInterface + */ + protected ProcessCacheWriterInterface $processCacheWriter; + /** * @param \Spryker\Zed\Oms\Business\Process\EventInterface $event * @param \Spryker\Zed\Oms\Business\Process\StateInterface $state * @param \Spryker\Zed\Oms\Business\Process\TransitionInterface $transition * @param \Spryker\Zed\Oms\Business\Process\ProcessInterface $process * @param array|string $processDefinitionLocation + * @param \Spryker\Zed\Oms\Business\Reader\ProcessCacheReaderInterface $processCacheReader + * @param \Spryker\Zed\Oms\Business\Writer\ProcessCacheWriterInterface $processCacheWriter * @param string $subProcessPrefixDelimiter */ public function __construct( @@ -72,12 +86,16 @@ public function __construct( TransitionInterface $transition, ProcessInterface $process, $processDefinitionLocation, + ProcessCacheReaderInterface $processCacheReader, + ProcessCacheWriterInterface $processCacheWriter, $subProcessPrefixDelimiter = ' - ' ) { $this->event = $event; $this->state = $state; $this->transition = $transition; $this->process = $process; + $this->processCacheReader = $processCacheReader; + $this->processCacheWriter = $processCacheWriter; $this->subProcessPrefixDelimiter = $subProcessPrefixDelimiter; $this->setProcessDefinitionLocation($processDefinitionLocation); @@ -90,28 +108,50 @@ public function __construct( */ public function createProcess($processName) { - if (!isset(static::$processBuffer[$processName])) { - $this->rootElement = $this->loadXmlFromProcessName($processName); + if (isset(static::$processBuffer[$processName])) { + return static::$processBuffer[$processName]; + } + + if ($this->processCacheReader->hasProcess($processName)) { + static::$processBuffer[$processName] = $this->processCacheReader->getProcess($processName); + + return static::$processBuffer[$processName]; + } + + $mainProcess = $this->createMainProcess($processName); + + static::$processBuffer[$processName] = $mainProcess; - $this->mergeSubProcessFiles(); + $this->processCacheWriter->cacheProcess($mainProcess, $processName); - /** @var array<\Spryker\Zed\Oms\Business\Process\ProcessInterface> $processMap */ - $processMap = []; + return static::$processBuffer[$processName]; + } + + /** + * @param string $processName + * + * @return \Spryker\Zed\Oms\Business\Process\ProcessInterface + */ + protected function createMainProcess(string $processName): ProcessInterface + { + $this->rootElement = $this->loadXmlFromProcessName($processName); - [$processMap, $mainProcess] = $this->createSubProcess($processMap); + $this->mergeSubProcessFiles(); - $stateToProcessMap = $this->createStates($processMap); + /** @var array<\Spryker\Zed\Oms\Business\Process\ProcessInterface> $processMap */ + $processMap = []; - $this->createSubProcesses($processMap); + [$processMap, $mainProcess] = $this->createSubProcess($processMap); - $eventMap = $this->createEvents(); + $stateToProcessMap = $this->createStates($processMap); - $this->createTransitions($stateToProcessMap, $processMap, $eventMap); + $this->createSubProcesses($processMap); - static::$processBuffer[$processName] = $mainProcess; - } + $eventMap = $this->createEvents(); - return static::$processBuffer[$processName]; + $this->createTransitions($stateToProcessMap, $processMap, $eventMap); + + return $mainProcess->warmupCache(); } /** diff --git a/src/Spryker/Zed/Oms/Business/Process/Process.php b/src/Spryker/Zed/Oms/Business/Process/Process.php index 591767c7..5992e161 100644 --- a/src/Spryker/Zed/Oms/Business/Process/Process.php +++ b/src/Spryker/Zed/Oms/Business/Process/Process.php @@ -47,6 +47,41 @@ class Process implements ProcessInterface */ protected $subProcesses = []; + /** + * @var array|null + */ + protected ?array $processStates = null; + + /** + * @var array<\Spryker\Zed\Oms\Business\Process\StateInterface>|null + */ + protected ?array $allStates = null; + + /** + * @var array<\Spryker\Zed\Oms\Business\Process\StateInterface>|null + */ + protected ?array $allReservedStates = null; + + /** + * @var array<\Spryker\Zed\Oms\Business\Process\TransitionInterface>|null + */ + protected ?array $allTransitions = null; + + /** + * @var array<\Spryker\Zed\Oms\Business\Process\TransitionInterface>|null + */ + protected ?array $allTransitionsWithoutEvent = null; + + /** + * @var array<\Spryker\Zed\Oms\Business\Process\EventInterface>|null + */ + protected ?array $manualEvents = null; + + /** + * @var array>|null + */ + protected ?array $manualEventsBySource = null; + /** * @param \Spryker\Zed\Oms\Business\Util\DrawerInterface $drawer */ @@ -188,10 +223,16 @@ public function hasState($stateId) */ public function getStateFromAllProcesses($stateId) { + if ($this->processStates !== null && isset($this->processStates[$stateId])) { + return $this->processStates[$stateId]; + } + $processes = $this->getAllProcesses(); foreach ($processes as $process) { if ($process->hasState($stateId)) { - return $process->getState($stateId); + $this->processStates[$stateId] = $process->getState($stateId); + + return $this->processStates[$stateId]; } } @@ -255,6 +296,10 @@ public function hasTransitions() */ public function getAllStates() { + if ($this->allStates !== null) { + return $this->allStates; + } + $states = []; if ($this->hasStates()) { $states = $this->getStates(); @@ -267,7 +312,7 @@ public function getAllStates() } } - return $states; + return $this->allStates = $states; } /** @@ -275,6 +320,10 @@ public function getAllStates() */ public function getAllReservedStates() { + if ($this->allReservedStates !== null) { + return $this->allReservedStates; + } + $reservedStates = []; $states = $this->getAllStates(); foreach ($states as $state) { @@ -283,7 +332,7 @@ public function getAllReservedStates() } } - return $reservedStates; + return $this->allReservedStates = $reservedStates; } /** @@ -291,6 +340,10 @@ public function getAllReservedStates() */ public function getAllTransitions() { + if ($this->allTransitions !== null) { + return $this->allTransitions; + } + $transitions = []; if ($this->hasTransitions()) { $transitions = $this->getTransitions(); @@ -301,7 +354,7 @@ public function getAllTransitions() } } - return $transitions; + return $this->allTransitions = $transitions; } /** @@ -309,6 +362,10 @@ public function getAllTransitions() */ public function getAllTransitionsWithoutEvent() { + if ($this->allTransitionsWithoutEvent !== null) { + return $this->allTransitionsWithoutEvent; + } + $transitions = []; $allTransitions = $this->getAllTransitions(); foreach ($allTransitions as $transition) { @@ -317,7 +374,7 @@ public function getAllTransitionsWithoutEvent() } } - return $transitions; + return $this->allTransitionsWithoutEvent = $transitions; } /** @@ -327,6 +384,10 @@ public function getAllTransitionsWithoutEvent() */ public function getManualEvents() { + if ($this->manualEvents !== null) { + return $this->manualEvents; + } + $manuallyExecutableEventList = []; $transitions = $this->getAllTransitions(); foreach ($transitions as $transition) { @@ -338,7 +399,7 @@ public function getManualEvents() } } - return $manuallyExecutableEventList; + return $this->manualEvents = $manuallyExecutableEventList; } /** @@ -346,6 +407,10 @@ public function getManualEvents() */ public function getManualEventsBySource() { + if ($this->manualEventsBySource !== null) { + return $this->manualEventsBySource; + } + $events = $this->getManualEvents(); $eventsBySource = []; @@ -362,7 +427,7 @@ public function getManualEventsBySource() } } - return $eventsBySource; + return $this->manualEventsBySource = $eventsBySource; } /** @@ -402,4 +467,22 @@ public function getFile() { return $this->file; } + + /** + * @return $this + */ + public function warmupCache() + { + $allStates = $this->getAllStates(); + foreach ($allStates as $state) { + $this->getStateFromAllProcesses($state->getName()); + } + $this->getAllReservedStates(); + $this->getAllTransitions(); + $this->getAllTransitionsWithoutEvent(); + $this->getManualEvents(); + $this->getManualEventsBySource(); + + return $this; + } } diff --git a/src/Spryker/Zed/Oms/Business/Process/ProcessInterface.php b/src/Spryker/Zed/Oms/Business/Process/ProcessInterface.php index 41d91bff..28958019 100644 --- a/src/Spryker/Zed/Oms/Business/Process/ProcessInterface.php +++ b/src/Spryker/Zed/Oms/Business/Process/ProcessInterface.php @@ -188,4 +188,9 @@ public function hasFile(); * @return string */ public function getFile(); + + /** + * @return $this + */ + public function warmupCache(); } diff --git a/src/Spryker/Zed/Oms/Business/Reader/ProcessCacheReader.php b/src/Spryker/Zed/Oms/Business/Reader/ProcessCacheReader.php new file mode 100644 index 00000000..a0f48617 --- /dev/null +++ b/src/Spryker/Zed/Oms/Business/Reader/ProcessCacheReader.php @@ -0,0 +1,62 @@ +omsConfig = $omsConfig; + } + + /** + * @param string $processName + * + * @return bool + */ + public function hasProcess(string $processName): bool + { + $fullFilename = $this->getFullFilename($processName); + + return file_exists($fullFilename) && filesize($fullFilename) > 0; + } + + /** + * @param string $processName + * + * @return \Spryker\Zed\Oms\Business\Process\ProcessInterface + */ + public function getProcess(string $processName): ProcessInterface + { + /** @var \Spryker\Zed\Oms\Business\Process\ProcessInterface $process */ + $process = unserialize((string)file_get_contents($this->getFullFilename($processName))); + + return $process; + } + + /** + * @param string $processName + * + * @return string + */ + public function getFullFilename(string $processName): string + { + return sprintf('%s%s', $this->omsConfig->getProcessCachePath(), $processName); + } +} diff --git a/src/Spryker/Zed/Oms/Business/Reader/ProcessCacheReaderInterface.php b/src/Spryker/Zed/Oms/Business/Reader/ProcessCacheReaderInterface.php new file mode 100644 index 00000000..01933005 --- /dev/null +++ b/src/Spryker/Zed/Oms/Business/Reader/ProcessCacheReaderInterface.php @@ -0,0 +1,34 @@ +omsConfig = $omsConfig; + $this->processCacheReader = $processCacheReader; + } + + /** + * @param \Spryker\Zed\Oms\Business\Process\ProcessInterface $process + * @param string|null $processName + * + * @return string + */ + public function cacheProcess(ProcessInterface $process, ?string $processName = null): string + { + $this->createCacheDirectory(); + + if (!$processName) { + $processName = $process->getName(); + } + $fullFilename = $this->processCacheReader->getFullFilename($processName); + + file_put_contents($fullFilename, serialize($process)); + + return $fullFilename; + } + + /** + * @return void + */ + protected function createCacheDirectory(): void + { + if (file_exists($this->omsConfig->getProcessCachePath())) { + return; + } + + mkdir($this->omsConfig->getProcessCachePath(), $this->omsConfig->getOmsProcessCacheFilePermission(), true); + } +} diff --git a/src/Spryker/Zed/Oms/Business/Writer/ProcessCacheWriterInterface.php b/src/Spryker/Zed/Oms/Business/Writer/ProcessCacheWriterInterface.php new file mode 100644 index 00000000..0cd808f2 --- /dev/null +++ b/src/Spryker/Zed/Oms/Business/Writer/ProcessCacheWriterInterface.php @@ -0,0 +1,21 @@ +setName(static::COMMAND_NAME) + ->setDescription(static::COMMAND_DESCRIPTION); + + parent::configure(); + } + + /** + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->getFacade()->getProcesses(); + + return static::CODE_SUCCESS; + } +} diff --git a/src/Spryker/Zed/Oms/OmsConfig.php b/src/Spryker/Zed/Oms/OmsConfig.php index da268d7e..f518cc7c 100644 --- a/src/Spryker/Zed/Oms/OmsConfig.php +++ b/src/Spryker/Zed/Oms/OmsConfig.php @@ -28,6 +28,16 @@ class OmsConfig extends AbstractBundleConfig */ public const OMS_EVENT_TRIGGER_RESPONSE = 'oms_event_trigger_response'; + /** + * @var int + */ + protected const OMS_PROCESS_CACHE_FILE_PERMISSION = 0777; + + /** + * @var string + */ + protected const DEFAULT_PROCESS_CACHE_PATH = '/data/cache/oms/process/'; + /** * @api * @@ -171,4 +181,33 @@ public function getOrderFieldsForOrderStatusChangedMessage(): array OrderTransfer::ORDER_REFERENCE => OrderStatusChangedTransfer::ORDER_REFERENCE, ]; } + + /** + * Specification: + * - Defines where to store cached processes. + * + * @api + * + * @return string + */ + public function getProcessCachePath(): string + { + return $this->get( + OmsConstants::PROCESS_CACHE_PATH, + sprintf('%s%s', APPLICATION_ROOT_DIR, static::DEFAULT_PROCESS_CACHE_PATH), + ); + } + + /** + * Specification: + * - Returns process cache file permission. + * + * @api + * + * @return int + */ + public function getOmsProcessCacheFilePermission(): int + { + return static::OMS_PROCESS_CACHE_FILE_PERMISSION; + } } diff --git a/tests/SprykerTest/Zed/Oms/Business/OrderStateMachine/BuilderTest.php b/tests/SprykerTest/Zed/Oms/Business/OrderStateMachine/BuilderTest.php index 2660473f..6a39aa19 100644 --- a/tests/SprykerTest/Zed/Oms/Business/OrderStateMachine/BuilderTest.php +++ b/tests/SprykerTest/Zed/Oms/Business/OrderStateMachine/BuilderTest.php @@ -10,12 +10,14 @@ use Codeception\Test\Unit; use Spryker\Zed\Oms\Business\Exception\StatemachineException; use Spryker\Zed\Oms\Business\OrderStateMachine\Builder; +use Spryker\Zed\Oms\Business\OrderStateMachine\BuilderInterface; use Spryker\Zed\Oms\Business\Process\EventInterface; use Spryker\Zed\Oms\Business\Process\Process; use Spryker\Zed\Oms\Business\Process\ProcessInterface; use Spryker\Zed\Oms\Business\Process\StateInterface; use Spryker\Zed\Oms\Business\Process\TransitionInterface; use Spryker\Zed\Oms\Business\Util\DrawerInterface; +use SprykerTest\Zed\Oms\OmsBusinessTester; /** * Auto-generated group annotations @@ -30,6 +32,11 @@ */ class BuilderTest extends Unit { + /** + * @var \SprykerTest\Zed\Oms\OmsBusinessTester + */ + protected OmsBusinessTester $tester; + /** * @return void */ @@ -48,11 +55,7 @@ public function tearDown(): void */ public function testInstantiationWithoutXmlFolder(): void { - $eventMock = $this->getEventMock(); - $stateMock = $this->getStateMock(); - $transitionMock = $this->getTransitionMock(); - $process = $this->getProcess(); - $builder = new Builder($eventMock, $stateMock, $transitionMock, $process, null); + $builder = $this->createBuilder(); $this->assertInstanceOf(Builder::class, $builder); } @@ -62,11 +65,7 @@ public function testInstantiationWithoutXmlFolder(): void */ public function testInstantiationWithXmlFolderAsString(): void { - $eventMock = $this->getEventMock(); - $stateMock = $this->getStateMock(); - $transitionMock = $this->getTransitionMock(); - $process = $this->getProcess(); - $builder = new Builder($eventMock, $stateMock, $transitionMock, $process, ''); + $builder = $this->createBuilder(''); $this->assertInstanceOf(Builder::class, $builder); } @@ -76,11 +75,7 @@ public function testInstantiationWithXmlFolderAsString(): void */ public function testInstantiationWithXmlFolderAsArray(): void { - $eventMock = $this->getEventMock(); - $stateMock = $this->getStateMock(); - $transitionMock = $this->getTransitionMock(); - $process = $this->getProcess(); - $builder = new Builder($eventMock, $stateMock, $transitionMock, $process, []); + $builder = $this->createBuilder([]); $this->assertInstanceOf(Builder::class, $builder); } @@ -90,11 +85,7 @@ public function testInstantiationWithXmlFolderAsArray(): void */ public function testGetProcessShouldThrowExceptionWhenProcessFoundInMoreThenOneLocation(): void { - $eventMock = $this->getEventMock(); - $stateMock = $this->getStateMock(); - $transitionMock = $this->getTransitionMock(); - $process = $this->getProcess(); - $builder = new Builder($eventMock, $stateMock, $transitionMock, $process, [$this->getProcessLocationA(), $this->getProcessLocationB()]); + $builder = $this->createBuilder([$this->getProcessLocationA(), $this->getProcessLocationB()]); $processACopyTarget = $this->getProcessLocationB() . DIRECTORY_SEPARATOR . 'process-a.xml'; copy($this->getProcessLocationA() . DIRECTORY_SEPARATOR . 'process-a.xml', $processACopyTarget); @@ -108,11 +99,7 @@ public function testGetProcessShouldThrowExceptionWhenProcessFoundInMoreThenOneL */ public function testGetProcessShouldThrowExceptionWhenNoProcessFound(): void { - $eventMock = $this->getEventMock(); - $stateMock = $this->getStateMock(); - $transitionMock = $this->getTransitionMock(); - $process = $this->getProcess(); - $builder = new Builder($eventMock, $stateMock, $transitionMock, $process, [$this->getProcessLocationB()]); + $builder = $this->createBuilder([$this->getProcessLocationB()]); $this->expectException(StatemachineException::class); $this->expectExceptionMessage('Could not find "process-a.xml". Please check your process definition location'); @@ -124,12 +111,7 @@ public function testGetProcessShouldThrowExceptionWhenNoProcessFound(): void */ public function testGetProcess(): void { - $eventMock = $this->getEventMock(); - $stateMock = $this->getStateMock(); - $transitionMock = $this->getTransitionMock(); - $process = $this->getProcess(); - - $builder = new Builder($eventMock, $stateMock, $transitionMock, $process, [$this->getProcessLocationA(), $this->getProcessLocationB()]); + $builder = $this->createBuilder([$this->getProcessLocationA(), $this->getProcessLocationB()]); $result = $builder->createProcess('process-a'); $this->assertInstanceOf(ProcessInterface::class, $result); @@ -192,4 +174,27 @@ private function getProcessLocationB(): string { return __DIR__ . '/Builder/Fixtures/DefinitionLocationB'; } + + /** + * @param array|string|null $processDefinitionLocation + * + * @return \Spryker\Zed\Oms\Business\OrderStateMachine\BuilderInterface + */ + private function createBuilder(array|string|null $processDefinitionLocation = null): BuilderInterface + { + $eventMock = $this->getEventMock(); + $stateMock = $this->getStateMock(); + $transitionMock = $this->getTransitionMock(); + $process = $this->getProcess(); + + return new Builder( + $eventMock, + $stateMock, + $transitionMock, + $process, + $processDefinitionLocation, + $this->tester->createProcessCacheReader(), + $this->tester->createProcessCacheWriter(), + ); + } } diff --git a/tests/SprykerTest/Zed/Oms/Business/OrderStateMachine/FinderTest.php b/tests/SprykerTest/Zed/Oms/Business/OrderStateMachine/FinderTest.php index 565e8d17..507251b3 100644 --- a/tests/SprykerTest/Zed/Oms/Business/OrderStateMachine/FinderTest.php +++ b/tests/SprykerTest/Zed/Oms/Business/OrderStateMachine/FinderTest.php @@ -21,6 +21,7 @@ use Spryker\Zed\Oms\Business\Process\Transition; use Spryker\Zed\Oms\Business\Util\DrawerInterface; use Spryker\Zed\Oms\Persistence\OmsQueryContainerInterface; +use SprykerTest\Zed\Oms\OmsBusinessTester; /** * Auto-generated group annotations @@ -50,6 +51,11 @@ class FinderTest extends Unit */ public const TEST_STATE_MACHINE_NAME = 'StateMachine01'; + /** + * @var \SprykerTest\Zed\Oms\OmsBusinessTester + */ + protected OmsBusinessTester $tester; + /** * @return void */ @@ -151,6 +157,8 @@ protected function createBuilder(DrawerInterface $drawerMock): Builder new Transition(), new Process($drawerMock), $this->getProcessLocation(), + $this->tester->createProcessCacheReader(), + $this->tester->createProcessCacheWriter(), ); } diff --git a/tests/SprykerTest/Zed/Oms/Business/Reader/ProcessCacheReaderTest.php b/tests/SprykerTest/Zed/Oms/Business/Reader/ProcessCacheReaderTest.php new file mode 100644 index 00000000..9f084914 --- /dev/null +++ b/tests/SprykerTest/Zed/Oms/Business/Reader/ProcessCacheReaderTest.php @@ -0,0 +1,134 @@ +omsConfigMock = $this->createMock(OmsConfig::class); + $this->testDirectory = sprintf('%s%s', sys_get_temp_dir(), static::TEST_DIRECTORY_PATTERN); + mkdir($this->testDirectory); + + $this->omsConfigMock + ->method('getProcessCachePath') + ->willReturn($this->testDirectory); + + $this->processCacheReader = new ProcessCacheReader($this->omsConfigMock); + } + + /** + * @return void + */ + protected function _after(): void + { + parent::_after(); + + array_map('unlink', glob(sprintf('%s%s', $this->testDirectory, '*'))); + rmdir($this->testDirectory); + } + + /** + * @return void + */ + public function testHasProcessReturnsTrueIfProcessExists(): void + { + file_put_contents(sprintf('%s%s', $this->testDirectory, static::PROCESS_NAME), static::FILE_DATA); + + $this->assertTrue($this->processCacheReader->hasProcess(static::PROCESS_NAME)); + } + + /** + * @return void + */ + public function testHasProcessReturnsFalseIfProcessDoesNotExist(): void + { + $this->assertFalse($this->processCacheReader->hasProcess(static::NON_EXISTING_PROCESS_NAME)); + } + + /** + * @return void + */ + public function testGetProcessReturnsProcessInterfaceInstance(): void + { + $processMock = $this->createMock(ProcessInterface::class); + $serializedProcess = serialize($processMock); + file_put_contents(sprintf('%s%s', $this->testDirectory, static::PROCESS_NAME), $serializedProcess); + + $process = $this->processCacheReader->getProcess(static::PROCESS_NAME); + + $this->assertInstanceOf(ProcessInterface::class, $process); + } + + /** + * @return void + */ + public function testGetFullFilenameReturnsCorrectPath(): void + { + $expectedFullPath = sprintf('%s%s', $this->testDirectory, static::PROCESS_NAME); + + $this->assertSame($expectedFullPath, $this->processCacheReader->getFullFilename(static::PROCESS_NAME)); + } +} diff --git a/tests/SprykerTest/Zed/Oms/Business/Util/ActiveProcessFetcherTest.php b/tests/SprykerTest/Zed/Oms/Business/Util/ActiveProcessFetcherTest.php index 9660d87d..f6d993b1 100644 --- a/tests/SprykerTest/Zed/Oms/Business/Util/ActiveProcessFetcherTest.php +++ b/tests/SprykerTest/Zed/Oms/Business/Util/ActiveProcessFetcherTest.php @@ -19,6 +19,7 @@ use Spryker\Zed\Oms\Business\Util\ActiveProcessFetcherInterface; use Spryker\Zed\Oms\Business\Util\DrawerInterface; use Spryker\Zed\Oms\Business\Util\ReadOnlyArrayObject; +use SprykerTest\Zed\Oms\OmsBusinessTester; /** * Auto-generated group annotations @@ -46,6 +47,11 @@ class ActiveProcessFetcherTest extends Unit 'payment pending', ]; + /** + * @var \SprykerTest\Zed\Oms\OmsBusinessTester + */ + protected OmsBusinessTester $tester; + /** * @return void */ @@ -132,6 +138,8 @@ protected function createBuilder(DrawerInterface $drawerMock): BuilderInterface new Transition(), new Process($drawerMock), [$this->getProcessLocation()], + $this->tester->createProcessCacheReader(), + $this->tester->createProcessCacheWriter(), ); } diff --git a/tests/SprykerTest/Zed/Oms/Business/Writer/ProcessCacheWriterTest.php b/tests/SprykerTest/Zed/Oms/Business/Writer/ProcessCacheWriterTest.php new file mode 100644 index 00000000..d7375416 --- /dev/null +++ b/tests/SprykerTest/Zed/Oms/Business/Writer/ProcessCacheWriterTest.php @@ -0,0 +1,127 @@ +omsConfigMock = $this->createMock(OmsConfig::class); + $this->processCacheReaderMock = $this->createMock(ProcessCacheReaderInterface::class); + $this->testDirectory = sprintf('%s%s', sys_get_temp_dir(), static::TEST_DIRECTORY_PATTERN); + mkdir($this->testDirectory); + + $this->omsConfigMock + ->method('getProcessCachePath') + ->willReturn($this->testDirectory); + + $this->processCacheWriter = new ProcessCacheWriter($this->omsConfigMock, $this->processCacheReaderMock); + } + + /** + * @return void + */ + protected function _after(): void + { + parent::_after(); + + array_map('unlink', glob(sprintf('%s%s', $this->testDirectory, '*'))); + rmdir($this->testDirectory); + } + + /** + * @return void + */ + public function testCacheProcessCreatesCacheFileWithGivenProcessName(): void + { + $processMock = $this->createMock(ProcessInterface::class); + $processMock->method('getName')->willReturn(static::PROCESS_NAME); + + $this->processCacheReaderMock + ->method('getFullFilename') + ->with(static::PROCESS_NAME) + ->willReturn(sprintf('%s%s', $this->testDirectory, static::PROCESS_NAME)); + + $cachedFilePath = $this->processCacheWriter->cacheProcess($processMock, static::PROCESS_NAME); + + $this->assertFileExists($cachedFilePath); + $this->assertSame(sprintf('%s%s', $this->testDirectory, static::PROCESS_NAME), $cachedFilePath); + } + + /** + * @return void + */ + public function testCacheProcessCreatesCacheFileWithDefaultProcessName(): void + { + $processMock = $this->createMock(ProcessInterface::class); + $processMock->method('getName')->willReturn(static::PROCESS_NAME); + + $this->processCacheReaderMock + ->method('getFullFilename') + ->with(static::PROCESS_NAME) + ->willReturn(sprintf('%s%s', $this->testDirectory, static::PROCESS_NAME)); + + $cachedFilePath = $this->processCacheWriter->cacheProcess($processMock); + + $this->assertFileExists($cachedFilePath); + $this->assertSame(sprintf('%s%s', $this->testDirectory, static::PROCESS_NAME), $cachedFilePath); + } +} diff --git a/tests/SprykerTest/Zed/Oms/_support/OmsBusinessTester.php b/tests/SprykerTest/Zed/Oms/_support/OmsBusinessTester.php index cc2124e2..caaca2bd 100644 --- a/tests/SprykerTest/Zed/Oms/_support/OmsBusinessTester.php +++ b/tests/SprykerTest/Zed/Oms/_support/OmsBusinessTester.php @@ -33,7 +33,11 @@ use Spryker\Zed\Oms\Business\Lock\TriggerLocker; use Spryker\Zed\Oms\Business\OrderStateMachine\LockedOrderStateMachine; use Spryker\Zed\Oms\Business\OrderStateMachine\OrderStateMachineInterface; +use Spryker\Zed\Oms\Business\Reader\ProcessCacheReader; +use Spryker\Zed\Oms\Business\Reader\ProcessCacheReaderInterface; use Spryker\Zed\Oms\Business\Util\ActiveProcessFetcher; +use Spryker\Zed\Oms\Business\Writer\ProcessCacheWriter; +use Spryker\Zed\Oms\Business\Writer\ProcessCacheWriterInterface; use Spryker\Zed\Oms\Dependency\Facade\OmsToSalesInterface; use Spryker\Zed\Oms\OmsConfig; use Spryker\Zed\Oms\Persistence\OmsQueryContainer; @@ -474,4 +478,20 @@ public function getOrderByIdSalesOrder(int $idSalesOrder): OrderTransfer (new OrderFilterTransfer())->setSalesOrderId($idSalesOrder), ); } + + /** + * @return \Spryker\Zed\Oms\Business\Reader\ProcessCacheReaderInterface + */ + public function createProcessCacheReader(): ProcessCacheReaderInterface + { + return new ProcessCacheReader(new OmsConfig()); + } + + /** + * @return \Spryker\Zed\Oms\Business\Writer\ProcessCacheWriterInterface + */ + public function createProcessCacheWriter(): ProcessCacheWriterInterface + { + return new ProcessCacheWriter(new OmsConfig(), $this->createProcessCacheReader()); + } }