|
5 | 5 | namespace Tests\Unit; |
6 | 6 |
|
7 | 7 | use Exception as BaseException; |
| 8 | +use Illuminate\Contracts\Queue\Job as JobContract; |
| 9 | +use Illuminate\Support\Facades\Cache; |
8 | 10 | use InvalidArgumentException; |
| 11 | +use Mockery; |
| 12 | +use ReflectionMethod; |
9 | 13 | use RuntimeException; |
10 | 14 | use Tests\Fixtures\TestActivity; |
11 | 15 | use Tests\Fixtures\TestProbeBackToBackWorkflow; |
@@ -54,6 +58,98 @@ public function testExceptionWorkflowRunning(): void |
54 | 58 | $this->assertSame(WorkflowRunningStatus::class, $workflow->status()); |
55 | 59 | } |
56 | 60 |
|
| 61 | + public function testHandleResumesWorkflowWhenLogAlreadyExists(): void |
| 62 | + { |
| 63 | + $lock = Mockery::mock(); |
| 64 | + $lock->shouldReceive('get') |
| 65 | + ->once() |
| 66 | + ->andReturn(true); |
| 67 | + $lock->shouldReceive('release') |
| 68 | + ->once(); |
| 69 | + |
| 70 | + Cache::shouldReceive('lock') |
| 71 | + ->once() |
| 72 | + ->with('laravel-workflow-exception:123', 15) |
| 73 | + ->andReturn($lock); |
| 74 | + |
| 75 | + $workflow = Mockery::mock(); |
| 76 | + $workflow->shouldReceive('resume') |
| 77 | + ->once(); |
| 78 | + |
| 79 | + $storedWorkflow = Mockery::mock(StoredWorkflow::class) |
| 80 | + ->makePartial(); |
| 81 | + $storedWorkflow->id = 123; |
| 82 | + $storedWorkflow->shouldReceive('effectiveConnection') |
| 83 | + ->andReturn(null); |
| 84 | + $storedWorkflow->shouldReceive('effectiveQueue') |
| 85 | + ->andReturn(null); |
| 86 | + $storedWorkflow->shouldReceive('toWorkflow') |
| 87 | + ->once() |
| 88 | + ->andReturn($workflow); |
| 89 | + $storedWorkflow->shouldReceive('hasLogByIndex') |
| 90 | + ->once() |
| 91 | + ->with(0) |
| 92 | + ->andReturn(true); |
| 93 | + |
| 94 | + $exception = new Exception(0, now()->toDateTimeString(), $storedWorkflow, new BaseException('existing log')); |
| 95 | + $exception->handle(); |
| 96 | + |
| 97 | + $this->assertSame(123, $storedWorkflow->id); |
| 98 | + |
| 99 | + Mockery::close(); |
| 100 | + } |
| 101 | + |
| 102 | + public function testHandleReleasesWhenExceptionLockUnavailable(): void |
| 103 | + { |
| 104 | + $workflow = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); |
| 105 | + $storedWorkflow = StoredWorkflow::findOrFail($workflow->id()); |
| 106 | + |
| 107 | + $lock = Mockery::mock(); |
| 108 | + $lock->shouldReceive('get') |
| 109 | + ->once() |
| 110 | + ->andReturn(false); |
| 111 | + |
| 112 | + Cache::shouldReceive('lock') |
| 113 | + ->once() |
| 114 | + ->with('laravel-workflow-exception:' . $storedWorkflow->id, 15) |
| 115 | + ->andReturn($lock); |
| 116 | + |
| 117 | + $job = Mockery::mock(JobContract::class); |
| 118 | + $job->shouldReceive('release') |
| 119 | + ->once() |
| 120 | + ->with(0); |
| 121 | + |
| 122 | + $exception = new Exception(0, now()->toDateTimeString(), $storedWorkflow, [ |
| 123 | + 'class' => BaseException::class, |
| 124 | + 'message' => 'locked', |
| 125 | + 'code' => 0, |
| 126 | + ]); |
| 127 | + $exception->setJob($job); |
| 128 | + $exception->handle(); |
| 129 | + |
| 130 | + $this->assertFalse($storedWorkflow->hasLogByIndex(0)); |
| 131 | + |
| 132 | + Mockery::close(); |
| 133 | + } |
| 134 | + |
| 135 | + public function testProbeReplayShortCircuitsWhenWorkflowClassIsInvalid(): void |
| 136 | + { |
| 137 | + $workflow = WorkflowStub::load(WorkflowStub::make(TestWorkflow::class)->id()); |
| 138 | + $storedWorkflow = StoredWorkflow::findOrFail($workflow->id()); |
| 139 | + $storedWorkflow->class = ''; |
| 140 | + |
| 141 | + $exception = new Exception(0, now()->toDateTimeString(), $storedWorkflow, [ |
| 142 | + 'class' => BaseException::class, |
| 143 | + 'message' => 'invalid workflow class', |
| 144 | + 'code' => 0, |
| 145 | + ]); |
| 146 | + |
| 147 | + $method = new ReflectionMethod(Exception::class, 'shouldPersistAfterProbeReplay'); |
| 148 | + $method->setAccessible(true); |
| 149 | + |
| 150 | + $this->assertTrue($method->invoke($exception)); |
| 151 | + } |
| 152 | + |
57 | 153 | public function testSkipsWriteWhenProbeDoesNotReachCandidateException(): void |
58 | 154 | { |
59 | 155 | $workflow = WorkflowStub::load(WorkflowStub::make(TestProbeParallelChildWorkflow::class)->id()); |
@@ -116,7 +212,13 @@ public function testPersistsWriteWhenProbeReachesCandidateException(): void |
116 | 212 | ], sourceClass: TestProbeRetryActivity::class); |
117 | 213 | $exception->handle(); |
118 | 214 |
|
| 215 | + $log = $storedWorkflow->fresh() |
| 216 | + ->logs() |
| 217 | + ->firstWhere('index', 1); |
| 218 | + |
| 219 | + $this->assertNotNull($log); |
119 | 220 | $this->assertTrue($storedWorkflow->fresh()->hasLogByIndex(1)); |
| 221 | + $this->assertSame(TestProbeRetryActivity::class, Serializer::unserialize($log->result)['sourceClass']); |
120 | 222 | } |
121 | 223 |
|
122 | 224 | public function testSkipsWriteWhenProbeReachesDifferentActivityClassAtSameIndex(): void |
|
0 commit comments