diff --git a/tests/Unit/ActivityTest.php b/tests/Unit/ActivityTest.php index e0ffd3eb..f4a63e2e 100644 --- a/tests/Unit/ActivityTest.php +++ b/tests/Unit/ActivityTest.php @@ -6,11 +6,13 @@ use BadMethodCallException; use Exception; +use Tests\Fixtures\NonRetryableTestExceptionActivity; use Tests\Fixtures\TestExceptionActivity; use Tests\Fixtures\TestInvalidActivity; use Tests\Fixtures\TestOtherActivity; use Tests\Fixtures\TestWorkflow; use Tests\TestCase; +use Workflow\Exceptions\NonRetryableException; use Workflow\Models\StoredWorkflow; use Workflow\Serializers\Serializer; use Workflow\States\WorkflowCreatedStatus; @@ -64,6 +66,24 @@ public function testExceptionActivity(): void $this->assertSame(WorkflowFailedStatus::class, $workflow->status()); } + public function testNonRetryableExceptionActivity(): void + { + $this->expectException(NonRetryableException::class); + + $workflow = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); + $activity = new NonRetryableTestExceptionActivity(0, now()->toDateTimeString(), StoredWorkflow::findOrFail( + $workflow->id() + )); + + $activity->handle(); + + $workflow->fresh(); + + $this->assertSame(1, $workflow->exceptions()->count()); + $this->assertSame(0, $workflow->logs()->count()); + $this->assertSame(WorkflowFailedStatus::class, $workflow->status()); + } + public function testFailedActivity(): void { $workflow = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); diff --git a/tests/Unit/ExceptionTest.php b/tests/Unit/ExceptionTest.php new file mode 100644 index 00000000..dac9eefd --- /dev/null +++ b/tests/Unit/ExceptionTest.php @@ -0,0 +1,46 @@ +toDateTimeString(), new StoredWorkflow(), new \Exception( + 'Test exception' + )); + + $middleware = collect($exception->middleware()) + ->map(static fn ($middleware) => is_object($middleware) ? get_class($middleware) : $middleware) + ->values(); + + $this->assertCount(1, $middleware); + $this->assertSame([WithoutOverlappingMiddleware::class], $middleware->all()); + } + + public function testExceptionWorkflowRunning(): void + { + $workflow = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); + $storedWorkflow = StoredWorkflow::findOrFail($workflow->id()); + $storedWorkflow->update([ + 'arguments' => Serializer::serialize([]), + 'status' => WorkflowRunningStatus::$name, + ]); + + $exception = new Exception(0, now()->toDateTimeString(), $storedWorkflow, new \Exception('Test exception')); + $exception->handle(); + + $this->assertSame(WorkflowRunningStatus::class, $workflow->status()); + } +} diff --git a/tests/Unit/SignalTest.php b/tests/Unit/SignalTest.php new file mode 100644 index 00000000..6470acc9 --- /dev/null +++ b/tests/Unit/SignalTest.php @@ -0,0 +1,44 @@ +middleware()) + ->map(static fn ($middleware) => is_object($middleware) ? get_class($middleware) : $middleware) + ->values(); + + $this->assertCount(1, $middleware); + $this->assertSame([WithoutOverlappingMiddleware::class], $middleware->all()); + } + + public function testSignalWorkflowRunning(): void + { + $workflow = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); + $storedWorkflow = StoredWorkflow::findOrFail($workflow->id()); + $storedWorkflow->update([ + 'arguments' => Serializer::serialize([]), + 'status' => WorkflowRunningStatus::$name, + ]); + + $signal = new Signal($storedWorkflow); + $signal->handle(); + + $this->assertSame(WorkflowRunningStatus::class, $workflow->status()); + } +} diff --git a/tests/Unit/WorkflowTest.php b/tests/Unit/WorkflowTest.php index 08eeaced..04d09982 100644 --- a/tests/Unit/WorkflowTest.php +++ b/tests/Unit/WorkflowTest.php @@ -5,21 +5,129 @@ namespace Tests\Unit; use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Event; use Tests\Fixtures\TestActivity; use Tests\Fixtures\TestChildWorkflow; use Tests\Fixtures\TestOtherActivity; use Tests\Fixtures\TestParentWorkflow; use Tests\Fixtures\TestWorkflow; use Tests\TestCase; +use Workflow\Events\WorkflowFailed; use Workflow\Exception; use Workflow\Models\StoredWorkflow; use Workflow\Serializers\Serializer; use Workflow\States\WorkflowCompletedStatus; +use Workflow\States\WorkflowFailedStatus; use Workflow\States\WorkflowPendingStatus; +use Workflow\Workflow; use Workflow\WorkflowStub; final class WorkflowTest extends TestCase { + public function testFailed(): void + { + Event::fake(); + + $parentWorkflow = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); + $storedParentWorkflow = StoredWorkflow::findOrFail($parentWorkflow->id()); + $storedParentWorkflow->update([ + 'arguments' => Serializer::serialize([]), + 'status' => WorkflowPendingStatus::$name, + ]); + + $stub = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); + $storedWorkflow = StoredWorkflow::findOrFail($stub->id()); + $storedWorkflow->update([ + 'arguments' => Serializer::serialize([]), + 'status' => WorkflowPendingStatus::class, + ]); + + $storedWorkflow->parents() + ->attach($storedParentWorkflow, [ + 'parent_index' => 0, + 'parent_now' => now(), + ]); + + $workflow = new Workflow($storedWorkflow); + + $workflow->failed(new \Exception('Test exception')); + + $this->assertSame(WorkflowFailedStatus::class, $stub->status()); + $this->assertSame( + 'Test exception', + Serializer::unserialize($stub->exceptions()->first()->exception)['message'] + ); + + Event::assertDispatched(WorkflowFailed::class, static function ($event) use ($stub) { + return $event->workflowId === $stub->id(); + }); + } + + public function testFailedTwice(): void + { + Event::fake(); + + $stub = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); + $storedWorkflow = StoredWorkflow::findOrFail($stub->id()); + $storedWorkflow->update([ + 'arguments' => Serializer::serialize([]), + 'status' => WorkflowFailedStatus::class, + ]); + + $workflow = new Workflow($storedWorkflow); + + $workflow->failed(new \Exception('Test exception')); + + $this->assertSame(WorkflowFailedStatus::class, $stub->status()); + $this->assertSame( + 'Test exception', + Serializer::unserialize($stub->exceptions()->first()->exception)['message'] + ); + + Event::assertNotDispatched(WorkflowFailed::class, static function ($event) use ($stub) { + return $event->workflowId === $stub->id(); + }); + } + + public function testFailedWithParentFailed(): void + { + Event::fake(); + + $parentWorkflow = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); + $storedParentWorkflow = StoredWorkflow::findOrFail($parentWorkflow->id()); + $storedParentWorkflow->update([ + 'arguments' => Serializer::serialize([]), + 'status' => WorkflowFailedStatus::$name, + ]); + + $stub = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); + $storedWorkflow = StoredWorkflow::findOrFail($stub->id()); + $storedWorkflow->update([ + 'arguments' => Serializer::serialize([]), + 'status' => WorkflowPendingStatus::class, + ]); + + $storedWorkflow->parents() + ->attach($storedParentWorkflow, [ + 'parent_index' => 0, + 'parent_now' => now(), + ]); + + $workflow = new Workflow($storedWorkflow); + + $workflow->failed(new \Exception('Test exception')); + + $this->assertSame(WorkflowFailedStatus::class, $stub->status()); + $this->assertSame( + 'Test exception', + Serializer::unserialize($stub->exceptions()->first()->exception)['message'] + ); + + Event::assertDispatched(WorkflowFailed::class, static function ($event) use ($stub) { + return $event->workflowId === $stub->id(); + }); + } + public function testException(): void { $exception = new \Exception('test');