From 43071e43a0743ff8c7913bba7819952962124355 Mon Sep 17 00:00:00 2001 From: Valery Piashchynski Date: Mon, 25 Jan 2021 22:47:02 +0300 Subject: Initial commit of the Temporal plugins set --- tests/temporal/Activity/HeartBeatActivity.php | 58 ++++++++++++++++ tests/temporal/Activity/SimpleActivity.php | 63 +++++++++++++++++ tests/temporal/Client/StartNewWorkflow.php | 23 +++++++ tests/temporal/DTO/Message.php | 14 ++++ tests/temporal/DTO/User.php | 15 ++++ tests/temporal/Workflow/ActivityStubWorkflow.php | 39 +++++++++++ tests/temporal/Workflow/AggregatedWorkflow.php | 30 ++++++++ tests/temporal/Workflow/AsyncActivityWorkflow.php | 28 ++++++++ tests/temporal/Workflow/BinaryWorkflow.php | 21 ++++++ .../Workflow/CancelSignalledChildWorkflow.php | 57 ++++++++++++++++ .../Workflow/CanceledHeartbeatWorkflow.php | 29 ++++++++ .../Workflow/CancelledMidflightWorkflow.php | 47 +++++++++++++ .../temporal/Workflow/CancelledNestedWorkflow.php | 72 ++++++++++++++++++++ tests/temporal/Workflow/CancelledScopeWorkflow.php | 39 +++++++++++ .../Workflow/CancelledSingleScopeWorkflow.php | 55 +++++++++++++++ .../Workflow/CancelledWithCompensationWorkflow.php | 79 ++++++++++++++++++++++ tests/temporal/Workflow/CancelledWorkflow.php | 31 +++++++++ tests/temporal/Workflow/ChainedWorkflow.php | 31 +++++++++ tests/temporal/Workflow/ChildStubWorkflow.php | 30 ++++++++ .../Workflow/ComplexExceptionalWorkflow.php | 26 +++++++ tests/temporal/Workflow/ContinuableWorkflow.php | 38 +++++++++++ tests/temporal/Workflow/EmptyWorkflow.php | 16 +++++ .../Workflow/ExceptionalActivityWorkflow.php | 25 +++++++ tests/temporal/Workflow/ExceptionalWorkflow.php | 18 +++++ .../temporal/Workflow/FailedHeartbeatWorkflow.php | 30 ++++++++ .../Workflow/LoopWithSignalCoroutinesWorkflow.php | 55 +++++++++++++++ tests/temporal/Workflow/LoopWorkflow.php | 51 ++++++++++++++ tests/temporal/Workflow/ParallelScopesWorkflow.php | 36 ++++++++++ tests/temporal/Workflow/PeriodicWorkflow.php | 19 ++++++ tests/temporal/Workflow/ProtoPayloadWorkflow.php | 33 +++++++++ tests/temporal/Workflow/QueryWorkflow.php | 41 +++++++++++ tests/temporal/Workflow/RuntimeSignalWorkflow.php | 31 +++++++++ tests/temporal/Workflow/SagaWorkflow.php | 54 +++++++++++++++ tests/temporal/Workflow/SideEffectWorkflow.php | 30 ++++++++ .../Workflow/SignalChildViaStubWorkflow.php | 25 +++++++ tests/temporal/Workflow/SimpleDTOWorkflow.php | 35 ++++++++++ .../temporal/Workflow/SimpleHeartbeatWorkflow.php | 25 +++++++ .../temporal/Workflow/SimpleSignalledWorkflow.php | 30 ++++++++ .../Workflow/SimpleSignalledWorkflowWithSleep.php | 34 ++++++++++ tests/temporal/Workflow/SimpleWorkflow.php | 31 +++++++++ tests/temporal/Workflow/TimerWorkflow.php | 27 ++++++++ tests/temporal/Workflow/WaitWorkflow.php | 33 +++++++++ tests/temporal/Workflow/WithChildStubWorkflow.php | 20 ++++++ tests/temporal/Workflow/WithChildWorkflow.php | 25 +++++++ tests/temporal/Workflow/WorkflowWithSequence.php | 30 ++++++++ .../Workflow/WorkflowWithSignalledSteps.php | 51 ++++++++++++++ 46 files changed, 1630 insertions(+) create mode 100644 tests/temporal/Activity/HeartBeatActivity.php create mode 100644 tests/temporal/Activity/SimpleActivity.php create mode 100644 tests/temporal/Client/StartNewWorkflow.php create mode 100644 tests/temporal/DTO/Message.php create mode 100644 tests/temporal/DTO/User.php create mode 100644 tests/temporal/Workflow/ActivityStubWorkflow.php create mode 100644 tests/temporal/Workflow/AggregatedWorkflow.php create mode 100644 tests/temporal/Workflow/AsyncActivityWorkflow.php create mode 100644 tests/temporal/Workflow/BinaryWorkflow.php create mode 100644 tests/temporal/Workflow/CancelSignalledChildWorkflow.php create mode 100644 tests/temporal/Workflow/CanceledHeartbeatWorkflow.php create mode 100644 tests/temporal/Workflow/CancelledMidflightWorkflow.php create mode 100644 tests/temporal/Workflow/CancelledNestedWorkflow.php create mode 100644 tests/temporal/Workflow/CancelledScopeWorkflow.php create mode 100644 tests/temporal/Workflow/CancelledSingleScopeWorkflow.php create mode 100644 tests/temporal/Workflow/CancelledWithCompensationWorkflow.php create mode 100644 tests/temporal/Workflow/CancelledWorkflow.php create mode 100644 tests/temporal/Workflow/ChainedWorkflow.php create mode 100644 tests/temporal/Workflow/ChildStubWorkflow.php create mode 100644 tests/temporal/Workflow/ComplexExceptionalWorkflow.php create mode 100644 tests/temporal/Workflow/ContinuableWorkflow.php create mode 100644 tests/temporal/Workflow/EmptyWorkflow.php create mode 100644 tests/temporal/Workflow/ExceptionalActivityWorkflow.php create mode 100644 tests/temporal/Workflow/ExceptionalWorkflow.php create mode 100644 tests/temporal/Workflow/FailedHeartbeatWorkflow.php create mode 100644 tests/temporal/Workflow/LoopWithSignalCoroutinesWorkflow.php create mode 100644 tests/temporal/Workflow/LoopWorkflow.php create mode 100644 tests/temporal/Workflow/ParallelScopesWorkflow.php create mode 100644 tests/temporal/Workflow/PeriodicWorkflow.php create mode 100644 tests/temporal/Workflow/ProtoPayloadWorkflow.php create mode 100644 tests/temporal/Workflow/QueryWorkflow.php create mode 100644 tests/temporal/Workflow/RuntimeSignalWorkflow.php create mode 100644 tests/temporal/Workflow/SagaWorkflow.php create mode 100644 tests/temporal/Workflow/SideEffectWorkflow.php create mode 100644 tests/temporal/Workflow/SignalChildViaStubWorkflow.php create mode 100644 tests/temporal/Workflow/SimpleDTOWorkflow.php create mode 100644 tests/temporal/Workflow/SimpleHeartbeatWorkflow.php create mode 100644 tests/temporal/Workflow/SimpleSignalledWorkflow.php create mode 100644 tests/temporal/Workflow/SimpleSignalledWorkflowWithSleep.php create mode 100644 tests/temporal/Workflow/SimpleWorkflow.php create mode 100644 tests/temporal/Workflow/TimerWorkflow.php create mode 100644 tests/temporal/Workflow/WaitWorkflow.php create mode 100644 tests/temporal/Workflow/WithChildStubWorkflow.php create mode 100644 tests/temporal/Workflow/WithChildWorkflow.php create mode 100644 tests/temporal/Workflow/WorkflowWithSequence.php create mode 100644 tests/temporal/Workflow/WorkflowWithSignalledSteps.php (limited to 'tests/temporal') diff --git a/tests/temporal/Activity/HeartBeatActivity.php b/tests/temporal/Activity/HeartBeatActivity.php new file mode 100644 index 00000000..acf4a451 --- /dev/null +++ b/tests/temporal/Activity/HeartBeatActivity.php @@ -0,0 +1,58 @@ + $value]); + sleep($value); + return 'OK'; + } + + #[ActivityMethod] + public function slow( + string $value + ): string { + for ($i = 0; $i < 5; $i++) { + Activity::heartbeat(['value' => $i]); + sleep(1); + } + + return 'OK'; + } + + #[ActivityMethod] + public function something( + string $value + ): string { + Activity::heartbeat(['value' => $value]); + sleep($value); + return 'OK'; + } + + #[ActivityMethod] + public function failedActivity( + int $value + ): string { + Activity::heartbeat(['value' => $value]); + if (Activity::getInfo()->attempt === 1) { + throw new \Error("failed"); + } + + if (!is_array(Activity::getHeartbeatDetails())) { + throw new \Error("no heartbeat details"); + } + + return 'OK!'; + } +} \ No newline at end of file diff --git a/tests/temporal/Activity/SimpleActivity.php b/tests/temporal/Activity/SimpleActivity.php new file mode 100644 index 00000000..576b126e --- /dev/null +++ b/tests/temporal/Activity/SimpleActivity.php @@ -0,0 +1,63 @@ +", $user->name, $user->email)); + } + + #[ActivityMethod] + public function slow( + string $input + ): string { + sleep(2); + + return strtolower($input); + } + + #[ActivityMethod] + public function sha512( + Bytes $input + ): string { + return hash("sha512", ($input->getData())); + } + + public function updateRunID(WorkflowExecution $e): WorkflowExecution + { + $e->setRunId('updated'); + return $e; + } + + #[ActivityMethod] + public function fail() + { + throw new \Error("failed activity"); + } +} \ No newline at end of file diff --git a/tests/temporal/Client/StartNewWorkflow.php b/tests/temporal/Client/StartNewWorkflow.php new file mode 100644 index 00000000..67bc1d01 --- /dev/null +++ b/tests/temporal/Client/StartNewWorkflow.php @@ -0,0 +1,23 @@ +stub = $client->newWorkflowStub(SimpleDTOWorkflow::class); + } + + public function __invoke() + { + } +} diff --git a/tests/temporal/DTO/Message.php b/tests/temporal/DTO/Message.php new file mode 100644 index 00000000..61703fe8 --- /dev/null +++ b/tests/temporal/DTO/Message.php @@ -0,0 +1,14 @@ +message = $message; + } +} \ No newline at end of file diff --git a/tests/temporal/DTO/User.php b/tests/temporal/DTO/User.php new file mode 100644 index 00000000..cefea137 --- /dev/null +++ b/tests/temporal/DTO/User.php @@ -0,0 +1,15 @@ +withStartToCloseTimeout(5) + ); + + $result = []; + $result[] = yield $simple->echo($input); + + try { + $simple->undefined($input); + } catch (\BadMethodCallException $e) { + $result[] = 'invalid method call'; + } + + // untyped stub + $untyped = Workflow::newUntypedActivityStub(ActivityOptions::new()->withStartToCloseTimeout(1)); + + $result[] = yield $untyped->execute('SimpleActivity.echo', ['untyped']); + + return $result; + } +} diff --git a/tests/temporal/Workflow/AggregatedWorkflow.php b/tests/temporal/Workflow/AggregatedWorkflow.php new file mode 100644 index 00000000..3299179e --- /dev/null +++ b/tests/temporal/Workflow/AggregatedWorkflow.php @@ -0,0 +1,30 @@ +values[] = $value; + } + + #[WorkflowMethod(name: 'AggregatedWorkflow')] + public function run( + int $count + ) { + yield Workflow::await(fn() => count($this->values) === $count); + + return $this->values; + } +} diff --git a/tests/temporal/Workflow/AsyncActivityWorkflow.php b/tests/temporal/Workflow/AsyncActivityWorkflow.php new file mode 100644 index 00000000..79e45dfb --- /dev/null +++ b/tests/temporal/Workflow/AsyncActivityWorkflow.php @@ -0,0 +1,28 @@ +withStartToCloseTimeout(20) + ->withCancellationType(ActivityCancellationType::WAIT_CANCELLATION_COMPLETED) + ); + + return yield $simple->external(); + } +} diff --git a/tests/temporal/Workflow/BinaryWorkflow.php b/tests/temporal/Workflow/BinaryWorkflow.php new file mode 100644 index 00000000..ed1952ad --- /dev/null +++ b/tests/temporal/Workflow/BinaryWorkflow.php @@ -0,0 +1,21 @@ +withStartToCloseTimeout(5); + + return yield Workflow::executeActivity('SimpleActivity.sha512', [$input], $opts); + } +} diff --git a/tests/temporal/Workflow/CancelSignalledChildWorkflow.php b/tests/temporal/Workflow/CancelSignalledChildWorkflow.php new file mode 100644 index 00000000..e2e43efa --- /dev/null +++ b/tests/temporal/Workflow/CancelSignalledChildWorkflow.php @@ -0,0 +1,57 @@ +status; + } + + #[WorkflowMethod(name: 'CancelSignalledChildWorkflow')] + public function handler() + { + // typed stub + $simple = Workflow::newChildWorkflowStub(SimpleSignalledWorkflow::class); + + $waitSignalled = new Deferred(); + + $this->status[] = 'start'; + + // start execution + $scope = Workflow::newCancellationScope( + function () use ($simple, $waitSignalled) { + $call = $simple->handler(); + $this->status[] = 'child started'; + + yield $simple->add(8); + $this->status[] = 'child signalled'; + $waitSignalled->resolve(); + + return yield $call; + } + ); + + // only cancel scope when signal dispatched + yield $waitSignalled; + $scope->cancel(); + $this->status[] = 'scope cancelled'; + + try { + return yield $scope; + } catch (\Throwable $e) { + $this->status[] = 'process done'; + + return 'cancelled ok'; + } + } +} diff --git a/tests/temporal/Workflow/CanceledHeartbeatWorkflow.php b/tests/temporal/Workflow/CanceledHeartbeatWorkflow.php new file mode 100644 index 00000000..6b463192 --- /dev/null +++ b/tests/temporal/Workflow/CanceledHeartbeatWorkflow.php @@ -0,0 +1,29 @@ +withStartToCloseTimeout(50) + ->withCancellationType(ActivityCancellationType::WAIT_CANCELLATION_COMPLETED) + ->withHeartbeatTimeout(1) + ); + + return yield $act->slow('test'); + } +} diff --git a/tests/temporal/Workflow/CancelledMidflightWorkflow.php b/tests/temporal/Workflow/CancelledMidflightWorkflow.php new file mode 100644 index 00000000..ea799ce1 --- /dev/null +++ b/tests/temporal/Workflow/CancelledMidflightWorkflow.php @@ -0,0 +1,47 @@ +status; + } + + #[WorkflowMethod(name: 'CancelledMidflightWorkflow')] + public function handler() + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + $this->status[] = 'start'; + + $scope = Workflow::newCancellationScope( + function () use ($simple) { + $this->status[] = 'in scope'; + $simple->slow('1'); + } + )->onCancel( + function () { + $this->status[] = 'on cancel'; + } + ); + + $scope->cancel(); + $this->status[] = 'done cancel'; + + return 'OK'; + } +} diff --git a/tests/temporal/Workflow/CancelledNestedWorkflow.php b/tests/temporal/Workflow/CancelledNestedWorkflow.php new file mode 100644 index 00000000..0c82f761 --- /dev/null +++ b/tests/temporal/Workflow/CancelledNestedWorkflow.php @@ -0,0 +1,72 @@ +status; + } + + #[WorkflowMethod(name: 'CancelledNestedWorkflow')] + public function handler() + { + $this->status[] = 'begin'; + try { + yield Workflow::newCancellationScope( + function () { + $this->status[] = 'first scope'; + + $scope = Workflow::newCancellationScope( + function () { + $this->status[] = 'second scope'; + + try { + yield Workflow::timer(2); + } catch (CanceledFailure $e) { + $this->status[] = 'second scope cancelled'; + throw $e; + } + + $this->status[] = 'second scope done'; + } + )->onCancel( + function () { + $this->status[] = 'close second scope'; + } + ); + + try { + yield Workflow::timer(1); + } catch (CanceledFailure $e) { + $this->status[] = 'first scope cancelled'; + throw $e; + } + + $this->status[] = 'first scope done'; + + yield $scope; + } + )->onCancel( + function () { + $this->status[] = 'close first scope'; + } + ); + } catch (CanceledFailure $e) { + $this->status[] = 'close process'; + + return 'CANCELLED'; + } + + return 'OK'; + } +} diff --git a/tests/temporal/Workflow/CancelledScopeWorkflow.php b/tests/temporal/Workflow/CancelledScopeWorkflow.php new file mode 100644 index 00000000..50e0992f --- /dev/null +++ b/tests/temporal/Workflow/CancelledScopeWorkflow.php @@ -0,0 +1,39 @@ +withStartToCloseTimeout(5) + ); + + $cancelled = 'not'; + + $scope = Workflow::newCancellationScope( + function () use ($simple) { + yield Workflow::timer(2); + yield $simple->slow('hello'); + } + )->onCancel( + function () use (&$cancelled) { + $cancelled = 'yes'; + } + ); + + yield Workflow::timer(1); + $scope->cancel(); + + return $cancelled; + } +} diff --git a/tests/temporal/Workflow/CancelledSingleScopeWorkflow.php b/tests/temporal/Workflow/CancelledSingleScopeWorkflow.php new file mode 100644 index 00000000..5fe8d3d8 --- /dev/null +++ b/tests/temporal/Workflow/CancelledSingleScopeWorkflow.php @@ -0,0 +1,55 @@ +status; + } + + #[WorkflowMethod(name: 'CancelledSingleScopeWorkflow')] + public function handler() + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new() + ->withStartToCloseTimeout(5) + ); + + $this->status[] = 'start'; + try { + yield Workflow::newCancellationScope( + function () use ($simple) { + try { + $this->status[] = 'in scope'; + yield $simple->slow('1'); + } catch (CanceledFailure $e) { + // after process is complete, do not use for business logic + $this->status[] = 'captured in scope'; + throw $e; + } + } + )->onCancel( + function () { + $this->status[] = 'on cancel'; + } + ); + } catch (CanceledFailure $e) { + $this->status[] = 'captured in process'; + } + + return 'OK'; + } +} diff --git a/tests/temporal/Workflow/CancelledWithCompensationWorkflow.php b/tests/temporal/Workflow/CancelledWithCompensationWorkflow.php new file mode 100644 index 00000000..2074aac1 --- /dev/null +++ b/tests/temporal/Workflow/CancelledWithCompensationWorkflow.php @@ -0,0 +1,79 @@ +status; + } + + #[WorkflowMethod(name: 'CancelledWithCompensationWorkflow')] + public function handler() + { + $simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + + // waits for 2 seconds + $slow = $simple->slow('DOING SLOW ACTIVITY'); + + try { + $this->status[] = 'yield'; + $result = yield $slow; + } catch (CanceledFailure $e) { + $this->status[] = 'rollback'; + + try { + // must fail again + $result = yield $slow; + } catch (CanceledFailure $e) { + $this->status[] = 'captured retry'; + } + + try { + // fail since on cancelled context + $result = yield $simple->echo('echo must fail'); + } catch (CanceledFailure $e) { + $this->status[] = 'captured promise on cancelled'; + } + + $scope = Workflow::newDetachedCancellationScope( + function () use ($simple) { + $this->status[] = 'START rollback'; + + $second = yield $simple->echo('rollback'); + + $this->status[] = sprintf("RESULT (%s)", $second); + + if ($second !== 'ROLLBACK') { + $this->status[] = 'FAIL rollback'; + return 'failed to compensate ' . $second; + } + $this->status[] = 'DONE rollback'; + + return 'OK'; + } + ); + + $this->status[] = 'WAIT ROLLBACK'; + $result = yield $scope; + $this->status[] = 'COMPLETE rollback'; + } + + $this->status[] = 'result: ' . $result; + return $result; + } +} diff --git a/tests/temporal/Workflow/CancelledWorkflow.php b/tests/temporal/Workflow/CancelledWorkflow.php new file mode 100644 index 00000000..be9f7542 --- /dev/null +++ b/tests/temporal/Workflow/CancelledWorkflow.php @@ -0,0 +1,31 @@ +withStartToCloseTimeout(5) + ); + + // waits for 2 seconds + $slow = $simple->slow('DOING SLOW ACTIVITY'); + + try { + return yield $slow; + } catch (CanceledFailure $e) { + return "CANCELLED"; + } + } +} diff --git a/tests/temporal/Workflow/ChainedWorkflow.php b/tests/temporal/Workflow/ChainedWorkflow.php new file mode 100644 index 00000000..ba9c8f96 --- /dev/null +++ b/tests/temporal/Workflow/ChainedWorkflow.php @@ -0,0 +1,31 @@ +withStartToCloseTimeout(5); + + return yield Workflow::executeActivity( + 'SimpleActivity.echo', + [$input], + $opts + )->then(function ($result) use ($opts) { + return Workflow::executeActivity( + 'SimpleActivity.lower', + ['Result:' . $result], + $opts + ); + }); + } +} diff --git a/tests/temporal/Workflow/ChildStubWorkflow.php b/tests/temporal/Workflow/ChildStubWorkflow.php new file mode 100644 index 00000000..608962c2 --- /dev/null +++ b/tests/temporal/Workflow/ChildStubWorkflow.php @@ -0,0 +1,30 @@ +handler($input); + + // untyped + $untyped = Workflow::newUntypedChildWorkflowStub('SimpleWorkflow'); + $result[] = yield $untyped->execute(['untyped']); + + $execution = yield $untyped->getExecution(); + assert($execution instanceof Workflow\WorkflowExecution); + + return $result; + } +} diff --git a/tests/temporal/Workflow/ComplexExceptionalWorkflow.php b/tests/temporal/Workflow/ComplexExceptionalWorkflow.php new file mode 100644 index 00000000..bf65ccb2 --- /dev/null +++ b/tests/temporal/Workflow/ComplexExceptionalWorkflow.php @@ -0,0 +1,26 @@ +withRetryOptions( + (new RetryOptions())->withMaximumAttempts(1) + ) + ); + + return yield $child->handler(); + } +} diff --git a/tests/temporal/Workflow/ContinuableWorkflow.php b/tests/temporal/Workflow/ContinuableWorkflow.php new file mode 100644 index 00000000..78411414 --- /dev/null +++ b/tests/temporal/Workflow/ContinuableWorkflow.php @@ -0,0 +1,38 @@ +withStartToCloseTimeout(5) + ); + + if ($generation > 5) { + // complete + return "OK" . $generation; + } + + if ($generation !== 1) { + assert(!empty(Workflow::getInfo()->continuedExecutionRunId)); + } + + for ($i = 0; $i < $generation; $i++) { + yield $simple->echo((string)$generation); + } + + return Workflow::continueAsNew('ContinuableWorkflow', [++$generation]); + } +} diff --git a/tests/temporal/Workflow/EmptyWorkflow.php b/tests/temporal/Workflow/EmptyWorkflow.php new file mode 100644 index 00000000..57fb5e65 --- /dev/null +++ b/tests/temporal/Workflow/EmptyWorkflow.php @@ -0,0 +1,16 @@ +withStartToCloseTimeout(5) + ->withRetryOptions((new RetryOptions())->withMaximumAttempts(1)) + ); + + return yield $simple->fail(); + } +} diff --git a/tests/temporal/Workflow/ExceptionalWorkflow.php b/tests/temporal/Workflow/ExceptionalWorkflow.php new file mode 100644 index 00000000..9a3e907f --- /dev/null +++ b/tests/temporal/Workflow/ExceptionalWorkflow.php @@ -0,0 +1,18 @@ +withStartToCloseTimeout(50) + // will fail on first attempt + ->withRetryOptions(RetryOptions::new()->withMaximumAttempts(2)) + ); + + return yield $act->failedActivity($iterations); + } +} diff --git a/tests/temporal/Workflow/LoopWithSignalCoroutinesWorkflow.php b/tests/temporal/Workflow/LoopWithSignalCoroutinesWorkflow.php new file mode 100644 index 00000000..c389fd78 --- /dev/null +++ b/tests/temporal/Workflow/LoopWithSignalCoroutinesWorkflow.php @@ -0,0 +1,55 @@ +simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + } + + #[SignalMethod] + public function addValue( + string $value + ) { + $value = yield $this->simple->prefix('in signal ', $value); + $value = yield $this->simple->prefix('in signal 2 ', $value); + + $this->values[] = $value; + } + + #[WorkflowMethod(name: 'LoopWithSignalCoroutinesWorkflow')] + public function run( + int $count + ) { + while (true) { + yield Workflow::await(fn() => $this->values !== []); + $value = array_shift($this->values); + + // uppercases + $this->result[] = yield $this->simple->echo($value); + + if (count($this->result) === $count) { + break; + } + } + + asort($this->result); + return array_values($this->result); + } +} diff --git a/tests/temporal/Workflow/LoopWorkflow.php b/tests/temporal/Workflow/LoopWorkflow.php new file mode 100644 index 00000000..97d7a3aa --- /dev/null +++ b/tests/temporal/Workflow/LoopWorkflow.php @@ -0,0 +1,51 @@ +simple = Workflow::newActivityStub( + SimpleActivity::class, + ActivityOptions::new()->withStartToCloseTimeout(5) + ); + } + + #[SignalMethod] + public function addValue( + string $value + ) { + $this->values[] = $value; + } + + #[WorkflowMethod(name: 'LoopWorkflow')] + public function run( + int $count + ) { + while (true) { + yield Workflow::await(fn() => $this->values !== []); + $value = array_shift($this->values); + + $this->result[] = yield $this->simple->echo($value); + + if (count($this->result) === $count) { + break; + } + } + + return $this->result; + } +} diff --git a/tests/temporal/Workflow/ParallelScopesWorkflow.php b/tests/temporal/Workflow/ParallelScopesWorkflow.php new file mode 100644 index 00000000..8a2303f4 --- /dev/null +++ b/tests/temporal/Workflow/ParallelScopesWorkflow.php @@ -0,0 +1,36 @@ +withStartToCloseTimeout(5) + ); + + $a = Workflow::newCancellationScope(function () use ($simple, $input) { + return yield $simple->echo($input); + }); + + $b = Workflow::newCancellationScope(function () use ($simple, $input) { + return yield $simple->lower($input); + }); + + [$ra, $rb] = yield Promise::all([$a, $b]); + + return sprintf('%s|%s|%s', $ra, $input, $rb); + } +} diff --git a/tests/temporal/Workflow/PeriodicWorkflow.php b/tests/temporal/Workflow/PeriodicWorkflow.php new file mode 100644 index 00000000..08f5f2fa --- /dev/null +++ b/tests/temporal/Workflow/PeriodicWorkflow.php @@ -0,0 +1,19 @@ +withStartToCloseTimeout(5) + ); + + $e = new WorkflowExecution(); + $e->setWorkflowId('workflow id'); + $e->setRunId('run id'); + + /** @var WorkflowExecution $e2 */ + $e2 = yield $simple->updateRunID($e); + assert($e2->getWorkflowId() === $e->getWorkflowId()); + assert($e2->getRunId() === 'updated'); + + return $e2; + } +} diff --git a/tests/temporal/Workflow/QueryWorkflow.php b/tests/temporal/Workflow/QueryWorkflow.php new file mode 100644 index 00000000..96e41582 --- /dev/null +++ b/tests/temporal/Workflow/QueryWorkflow.php @@ -0,0 +1,41 @@ +counter += $value; + } + + #[Workflow\QueryMethod(name: "get")] + public function get(): int + { + return $this->counter; + } + + #[WorkflowMethod] + public function handler() + { + // collect signals during one second + yield Workflow::timer(1); + + return $this->counter; + } +} diff --git a/tests/temporal/Workflow/RuntimeSignalWorkflow.php b/tests/temporal/Workflow/RuntimeSignalWorkflow.php new file mode 100644 index 00000000..f700af72 --- /dev/null +++ b/tests/temporal/Workflow/RuntimeSignalWorkflow.php @@ -0,0 +1,31 @@ +resolve($value); + $wait2->resolve($value); + }); + + yield $wait1; + yield $wait2; + + return $counter; + } +} diff --git a/tests/temporal/Workflow/SagaWorkflow.php b/tests/temporal/Workflow/SagaWorkflow.php new file mode 100644 index 00000000..e47c0203 --- /dev/null +++ b/tests/temporal/Workflow/SagaWorkflow.php @@ -0,0 +1,54 @@ +withStartToCloseTimeout(60) + ->withRetryOptions(RetryOptions::new()->withMaximumAttempts(1)) + ); + + $saga = new Workflow\Saga(); + $saga->setParallelCompensation(true); + + try { + yield $simple->echo('test'); + $saga->addCompensation( + function () use ($simple) { + yield $simple->echo('compensate echo'); + } + ); + + yield $simple->lower('TEST'); + $saga->addCompensation( + function () use ($simple) { + yield $simple->lower('COMPENSATE LOWER'); + } + ); + + yield $simple->fail(); + } catch (\Throwable $e) { + yield $saga->compensate(); + throw $e; + } + } +} diff --git a/tests/temporal/Workflow/SideEffectWorkflow.php b/tests/temporal/Workflow/SideEffectWorkflow.php new file mode 100644 index 00000000..95d396e4 --- /dev/null +++ b/tests/temporal/Workflow/SideEffectWorkflow.php @@ -0,0 +1,30 @@ +withStartToCloseTimeout(5) + ); + + $result = yield Workflow::sideEffect( + function () use ($input) { + return $input . '-42'; + } + ); + + return yield $simple->lower($result); + } +} diff --git a/tests/temporal/Workflow/SignalChildViaStubWorkflow.php b/tests/temporal/Workflow/SignalChildViaStubWorkflow.php new file mode 100644 index 00000000..828086fc --- /dev/null +++ b/tests/temporal/Workflow/SignalChildViaStubWorkflow.php @@ -0,0 +1,25 @@ +handler(); + + yield $simple->add(8); + + // expects 8 + return yield $call; + } +} diff --git a/tests/temporal/Workflow/SimpleDTOWorkflow.php b/tests/temporal/Workflow/SimpleDTOWorkflow.php new file mode 100644 index 00000000..bd39a0a0 --- /dev/null +++ b/tests/temporal/Workflow/SimpleDTOWorkflow.php @@ -0,0 +1,35 @@ +withStartToCloseTimeout(5) + ); + + $value = yield $simple->greet($user); + + if (!$value instanceof Message) { + return "FAIL"; + } + + return $value; + } +} diff --git a/tests/temporal/Workflow/SimpleHeartbeatWorkflow.php b/tests/temporal/Workflow/SimpleHeartbeatWorkflow.php new file mode 100644 index 00000000..c9999cd1 --- /dev/null +++ b/tests/temporal/Workflow/SimpleHeartbeatWorkflow.php @@ -0,0 +1,25 @@ +withStartToCloseTimeout(50) + ); + + return yield $act->doSomething($iterations); + } +} diff --git a/tests/temporal/Workflow/SimpleSignalledWorkflow.php b/tests/temporal/Workflow/SimpleSignalledWorkflow.php new file mode 100644 index 00000000..0df25a65 --- /dev/null +++ b/tests/temporal/Workflow/SimpleSignalledWorkflow.php @@ -0,0 +1,30 @@ +counter += $value; + } + + #[WorkflowMethod(name: 'SimpleSignalledWorkflow')] + public function handler(): iterable + { + // collect signals during one second + yield Workflow::timer(1); + + return $this->counter; + } +} diff --git a/tests/temporal/Workflow/SimpleSignalledWorkflowWithSleep.php b/tests/temporal/Workflow/SimpleSignalledWorkflowWithSleep.php new file mode 100644 index 00000000..d10ba04a --- /dev/null +++ b/tests/temporal/Workflow/SimpleSignalledWorkflowWithSleep.php @@ -0,0 +1,34 @@ +counter += $value; + } + + #[WorkflowMethod(name: 'SimpleSignalledWorkflowWithSleep')] + public function handler(): iterable + { + // collect signals during one second + yield Workflow::timer(1); + + if (!Workflow::isReplaying()) { + sleep(1); + } + + return $this->counter; + } +} diff --git a/tests/temporal/Workflow/SimpleWorkflow.php b/tests/temporal/Workflow/SimpleWorkflow.php new file mode 100644 index 00000000..36e12f69 --- /dev/null +++ b/tests/temporal/Workflow/SimpleWorkflow.php @@ -0,0 +1,31 @@ +withStartToCloseTimeout(5) + ->withRetryOptions( + RetryOptions::new()->withMaximumAttempts(2) + ) + ); + + return yield $simple->echo($input); + } +} diff --git a/tests/temporal/Workflow/TimerWorkflow.php b/tests/temporal/Workflow/TimerWorkflow.php new file mode 100644 index 00000000..ab60d6c9 --- /dev/null +++ b/tests/temporal/Workflow/TimerWorkflow.php @@ -0,0 +1,27 @@ +withStartToCloseTimeout(5) + ); + + yield Workflow::timer(1); + + return yield $simple->lower($input); + } +} diff --git a/tests/temporal/Workflow/WaitWorkflow.php b/tests/temporal/Workflow/WaitWorkflow.php new file mode 100644 index 00000000..826952c1 --- /dev/null +++ b/tests/temporal/Workflow/WaitWorkflow.php @@ -0,0 +1,33 @@ +ready = true; + $this->value = $value; + } + + #[WorkflowMethod(name: 'WaitWorkflow')] + public function run() + { + yield Workflow::await(fn() => $this->ready); + + return $this->value; + } +} diff --git a/tests/temporal/Workflow/WithChildStubWorkflow.php b/tests/temporal/Workflow/WithChildStubWorkflow.php new file mode 100644 index 00000000..cdebe3d8 --- /dev/null +++ b/tests/temporal/Workflow/WithChildStubWorkflow.php @@ -0,0 +1,20 @@ +handler('child ' . $input)); + } +} diff --git a/tests/temporal/Workflow/WithChildWorkflow.php b/tests/temporal/Workflow/WithChildWorkflow.php new file mode 100644 index 00000000..aac0979b --- /dev/null +++ b/tests/temporal/Workflow/WithChildWorkflow.php @@ -0,0 +1,25 @@ +withStartToCloseTimeout(5) + ); + + $a = $simple->echo('a'); + $b = $simple->echo('b'); + + yield $a; + yield $b; + + return 'OK'; + } +} diff --git a/tests/temporal/Workflow/WorkflowWithSignalledSteps.php b/tests/temporal/Workflow/WorkflowWithSignalledSteps.php new file mode 100644 index 00000000..5f1af766 --- /dev/null +++ b/tests/temporal/Workflow/WorkflowWithSignalledSteps.php @@ -0,0 +1,51 @@ +withStartToCloseTimeout(5) + ); + + $value = 0; + Workflow::registerQuery('value', function () use (&$value) { + return $value; + }); + + yield $this->promiseSignal('begin'); + $value++; + + yield $this->promiseSignal('next1'); + $value++; + + yield $this->promiseSignal('next2'); + $value++; + + return $value; + } + + // is this correct? + private function promiseSignal(string $name): PromiseInterface + { + $signal = new Deferred(); + Workflow::registerSignal($name, function ($value) use ($signal) { + $signal->resolve($value); + }); + + return $signal->promise(); + } +} -- cgit v1.2.3