From c8d5a790057cd07eaddae9bc31d9b1d53fae7caf Mon Sep 17 00:00:00 2001 From: Vincent Wong Date: Thu, 3 Apr 2025 18:03:45 +0800 Subject: [PATCH 1/6] Create the FakeAsyncTask class --- src/AsyncTask.php | 2 +- src/FakeAsyncTask.php | 55 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/FakeAsyncTask.php diff --git a/src/AsyncTask.php b/src/AsyncTask.php index 4b24ee5..146bec4 100644 --- a/src/AsyncTask.php +++ b/src/AsyncTask.php @@ -32,7 +32,7 @@ class AsyncTask * If null, the task will generate an unsaved random ID when it is started. * @var string|null */ - private string|null $taskID; + protected string|null $taskID; /** * The process that is actually running this task. Tasks that are not started will have null here. diff --git a/src/FakeAsyncTask.php b/src/FakeAsyncTask.php new file mode 100644 index 0000000..30b063f --- /dev/null +++ b/src/FakeAsyncTask.php @@ -0,0 +1,55 @@ +taskID ?? Str::ulid()->toString(); + return new AsyncTaskStatus($taskID); + } +} From dac44e97d9d1a743475635d4164e11ff32f8b95f Mon Sep 17 00:00:00 2001 From: Vincent Wong Date: Thu, 3 Apr 2025 18:09:34 +0800 Subject: [PATCH 2/6] Extract task status generation to a new method --- src/AsyncTask.php | 17 ++++++++++++++--- src/FakeAsyncTask.php | 3 +-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/AsyncTask.php b/src/AsyncTask.php index 146bec4..441dba9 100644 --- a/src/AsyncTask.php +++ b/src/AsyncTask.php @@ -32,7 +32,7 @@ class AsyncTask * If null, the task will generate an unsaved random ID when it is started. * @var string|null */ - protected string|null $taskID; + private string|null $taskID; /** * The process that is actually running this task. Tasks that are not started will have null here. @@ -131,6 +131,18 @@ public function __unserialize($data): void ] = $data; } + /** + * Returns a status object for the started AsyncTask. + * + * If this task does not have an explicit task ID, a new one will be generated on-the-fly. + * @return AsyncTaskStatus The status object for the started AsyncTask. + */ + protected function getTaskStatusObject(): AsyncTaskStatus + { + $taskID = $this->taskID ?? Str::ulid()->toString(); + return new AsyncTaskStatus($taskID); + } + /** * Inside an available PHP process, runs this AsyncTask instance. * @@ -192,8 +204,7 @@ public function run(): void public function start(): AsyncTaskStatus { // prepare the task details - $taskID = $this->taskID ?? Str::ulid()->toString(); - $taskStatus = new AsyncTaskStatus($taskID); + $taskStatus = $this->getTaskStatusObject(); // prepare the runner command $serializedTask = $this->toBase64Serial(); diff --git a/src/FakeAsyncTask.php b/src/FakeAsyncTask.php index 30b063f..0a81922 100644 --- a/src/FakeAsyncTask.php +++ b/src/FakeAsyncTask.php @@ -49,7 +49,6 @@ public function run(): void public function start(): AsyncTaskStatus { // todo fake version - $taskID = $this->taskID ?? Str::ulid()->toString(); - return new AsyncTaskStatus($taskID); + return $this->getTaskStatusObject(); } } From 3af4ca26d8557afcb43981d34ceb8ba83bc35026 Mon Sep 17 00:00:00 2001 From: Vincent Wong Date: Thu, 3 Apr 2025 18:18:38 +0800 Subject: [PATCH 3/6] Create the FakeAsyncTaskStatus class --- src/FakeAsyncTaskStatus.php | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/FakeAsyncTaskStatus.php diff --git a/src/FakeAsyncTaskStatus.php b/src/FakeAsyncTaskStatus.php new file mode 100644 index 0000000..d27efce --- /dev/null +++ b/src/FakeAsyncTaskStatus.php @@ -0,0 +1,36 @@ +fakeIsRunning; + } + + +} From 45953e90806dbc870979dfaab80fbff7aecdf876 Mon Sep 17 00:00:00 2001 From: Vincent Wong Date: Thu, 3 Apr 2025 18:25:51 +0800 Subject: [PATCH 4/6] Allow converting real objects to fake objects --- src/AsyncTask.php | 15 +++++++++++++++ src/AsyncTaskStatus.php | 9 +++++++++ src/FakeAsyncTask.php | 7 +++---- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/AsyncTask.php b/src/AsyncTask.php index 441dba9..a2abd6a 100644 --- a/src/AsyncTask.php +++ b/src/AsyncTask.php @@ -114,6 +114,21 @@ public function __construct(Closure|AsyncTaskInterface $theTask, string|null $ta $this->taskID = $taskID; } + /** + * Returns an instance of a fake AsyncTask with the same task parameters and task ID. + * @return FakeAsyncTask The fake AsyncTask object for testing. + */ + public function fake(): FakeAsyncTask + { + $fakeTask = new FakeAsyncTask($this->theTask, taskID: $this->taskID); + if ($this->getTimeLimit() === null) { + $fakeTask->withoutTimeLimit(); + } else { + $fakeTask->withTimeLimit($this->timeLimit); + } + return $fakeTask; + } + public function __serialize(): array { // serialize only the necessary info to reduce runner cmd length diff --git a/src/AsyncTaskStatus.php b/src/AsyncTaskStatus.php index c1c6699..c1862e1 100644 --- a/src/AsyncTaskStatus.php +++ b/src/AsyncTaskStatus.php @@ -50,6 +50,15 @@ public function __construct( } } + /** + * Returns an instance of a fake status object with the same task ID. + * @return FakeAsyncTaskStatus The fake AsyncTaskStatus object for testing. + */ + public function fake(): FakeAsyncTaskStatus + { + return new FakeAsyncTaskStatus($this->taskID); + } + /** * Returns the task ID encoded in base64, mainly for result checking. * @return string The encoded task ID. diff --git a/src/FakeAsyncTask.php b/src/FakeAsyncTask.php index 0a81922..eca22b7 100644 --- a/src/FakeAsyncTask.php +++ b/src/FakeAsyncTask.php @@ -44,11 +44,10 @@ public function run(): void /** * Fakes the AsyncTask being started in the background, but does not actually start the task. - * @return AsyncTaskStatus The status object for the fake-started FakeAsyncTask. + * @return FakeAsyncTaskStatus The status object for the fake-started FakeAsyncTask. */ - public function start(): AsyncTaskStatus + public function start(): FakeAsyncTaskStatus { - // todo fake version - return $this->getTaskStatusObject(); + return $this->getTaskStatusObject()->fake(); } } From a144ceb21c3bcc165335ef8bb10c7016d13bcdb1 Mon Sep 17 00:00:00 2001 From: Vincent Wong Date: Thu, 3 Apr 2025 18:42:57 +0800 Subject: [PATCH 5/6] Create test cases for the fake objects --- tests/FakeAsyncTaskTest.php | 62 +++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 tests/FakeAsyncTaskTest.php diff --git a/tests/FakeAsyncTaskTest.php b/tests/FakeAsyncTaskTest.php new file mode 100644 index 0000000..fcf74bc --- /dev/null +++ b/tests/FakeAsyncTaskTest.php @@ -0,0 +1,62 @@ +getStoragePath("testFakeTaskDoesNotRun.txt"); + $task = new AsyncTask(new DummyAsyncTask("Hello world!", $testFileName)); + $fakeTask = $task->fake(); + + // fake start it + $fakeTask->start(); + sleep(1); + // there should have no file outputs + $this->assertFileDoesNotExist($testFileName); + } + + public function testFakeTaskSameParams() + { + // the fake task should preserve its parameters + $testFileName = $this->getStoragePath("testFakeTaskSameDetails.txt"); + $task = new AsyncTask(new DummyAsyncTask("Hello world!", $testFileName)); + $randomDuration = rand(1, 10); + $task->withTimeLimit($randomDuration); + + // fake it... + $fakeTask = $task->fake(); + // ...and the parameters stay the same + $this->assertEquals($task->getTimeLimit(), $fakeTask->getTimeLimit()); + + // it is difficult to test the task ID since it would be exposing something that should not be exposed, so we will just have to believe it. + } + + public function testFakeTaskStatus() + { + $taskID = "testFakeTaskStatus"; + $taskStatus = new AsyncTaskStatus($taskID); + $fakeTaskStatusFromFake = $taskStatus->fake(); + $fakeTaskStatusFromNew = new FakeAsyncTaskStatus($taskID); + + // should have same task ID + $this->assertEquals($taskStatus->getEncodedTaskID(), $fakeTaskStatusFromFake->getEncodedTaskID()); + $this->assertEquals($taskStatus->getEncodedTaskID(), $fakeTaskStatusFromNew->getEncodedTaskID()); + } +} From 7e5a336d466a0b1d914cff36a1f113ead391f8ad Mon Sep 17 00:00:00 2001 From: Vincent Wong Date: Thu, 3 Apr 2025 18:44:14 +0800 Subject: [PATCH 6/6] Code cleanup --- src/FakeAsyncTask.php | 9 --------- src/FakeAsyncTaskStatus.php | 15 ++++++++++----- tests/FakeAsyncTaskTest.php | 10 +--------- 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/src/FakeAsyncTask.php b/src/FakeAsyncTask.php index eca22b7..090e91b 100644 --- a/src/FakeAsyncTask.php +++ b/src/FakeAsyncTask.php @@ -5,15 +5,6 @@ namespace Vectorial1024\LaravelProcessAsync; use Closure; -use Illuminate\Process\InvokedProcess; -use Illuminate\Support\Facades\Process; -use Illuminate\Support\Str; -use InvalidArgumentException; -use LogicException; -use loophp\phposinfo\OsInfo; -use RuntimeException; - -use function Opis\Closure\{serialize, unserialize}; /** * The fake AsyncTask class for testing. diff --git a/src/FakeAsyncTaskStatus.php b/src/FakeAsyncTaskStatus.php index d27efce..94e6b16 100644 --- a/src/FakeAsyncTaskStatus.php +++ b/src/FakeAsyncTaskStatus.php @@ -4,10 +4,6 @@ namespace Vectorial1024\LaravelProcessAsync; -use InvalidArgumentException; -use loophp\phposinfo\OsInfo; -use RuntimeException; - /** * The fake AsyncTaskStatus class for testing. Fake async tasks are presumed to be running by default. */ @@ -32,5 +28,14 @@ public function isRunning(): bool return $this->fakeIsRunning; } - + /** + * Force the fake task to become stopped. + * + * Note: once stopped, the fake async task cannot be made running again. Use a new status object if the fake task needs to be restarted. + * @return void + */ + public function fakeStopRunning(): void + { + $this->fakeIsRunning = false; + } } diff --git a/tests/FakeAsyncTaskTest.php b/tests/FakeAsyncTaskTest.php index fcf74bc..a95125e 100644 --- a/tests/FakeAsyncTaskTest.php +++ b/tests/FakeAsyncTaskTest.php @@ -2,18 +2,10 @@ namespace Vectorial1024\LaravelProcessAsync\Tests; -use InvalidArgumentException; -use LogicException; -use RuntimeException; use Vectorial1024\LaravelProcessAsync\AsyncTask; use Vectorial1024\LaravelProcessAsync\AsyncTaskStatus; -use Vectorial1024\LaravelProcessAsync\FakeAsyncTaskStatus; use Vectorial1024\LaravelProcessAsync\Tests\Tasks\DummyAsyncTask; -use Vectorial1024\LaravelProcessAsync\Tests\Tasks\SleepingAsyncTask; -use Vectorial1024\LaravelProcessAsync\Tests\Tasks\TestTimeoutENoticeTask; -use Vectorial1024\LaravelProcessAsync\Tests\Tasks\TestTimeoutErrorTask; -use Vectorial1024\LaravelProcessAsync\Tests\Tasks\TestTimeoutNoOpTask; -use Vectorial1024\LaravelProcessAsync\Tests\Tasks\TestTimeoutNormalTask; +use Vectorial1024\LaravelProcessAsync\FakeAsyncTaskStatus; // a series of tests that ensure the fake tasks are indeed fake while still look like the same class FakeAsyncTaskTest extends BaseTestCase