Skip to content

Commit 710ec25

Browse files
committed
Merge branch 'master' into security
2 parents 6d7280a + a4bec08 commit 710ec25

File tree

5 files changed

+176
-2
lines changed

5 files changed

+176
-2
lines changed

src/AsyncTask.php

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,21 @@ public function __construct(Closure|AsyncTaskInterface $theTask, string|null $ta
117117
$this->taskID = $taskID;
118118
}
119119

120+
/**
121+
* Returns an instance of a fake AsyncTask with the same task parameters and task ID.
122+
* @return FakeAsyncTask The fake AsyncTask object for testing.
123+
*/
124+
public function fake(): FakeAsyncTask
125+
{
126+
$fakeTask = new FakeAsyncTask($this->theTask, taskID: $this->taskID);
127+
if ($this->getTimeLimit() === null) {
128+
$fakeTask->withoutTimeLimit();
129+
} else {
130+
$fakeTask->withTimeLimit($this->timeLimit);
131+
}
132+
return $fakeTask;
133+
}
134+
120135
public function __serialize(): array
121136
{
122137
// serialize only the necessary info to reduce runner cmd length
@@ -154,6 +169,18 @@ public static function loadSecretKey(): void
154169
}
155170
}
156171

172+
/*
173+
* Returns a status object for the started AsyncTask.
174+
*
175+
* If this task does not have an explicit task ID, a new one will be generated on-the-fly.
176+
* @return AsyncTaskStatus The status object for the started AsyncTask.
177+
*/
178+
protected function getTaskStatusObject(): AsyncTaskStatus
179+
{
180+
$taskID = $this->taskID ?? Str::ulid()->toString();
181+
return new AsyncTaskStatus($taskID);
182+
}
183+
157184
/**
158185
* Inside an available PHP process, runs this AsyncTask instance.
159186
*
@@ -215,8 +242,7 @@ public function run(): void
215242
public function start(): AsyncTaskStatus
216243
{
217244
// prepare the task details
218-
$taskID = $this->taskID ?? Str::ulid()->toString();
219-
$taskStatus = new AsyncTaskStatus($taskID);
245+
$taskStatus = $this->getTaskStatusObject();
220246

221247
// prepare the runner command
222248
$serializedTask = $this->toBase64Serial();

src/AsyncTaskStatus.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ public function __construct(
5050
}
5151
}
5252

53+
/**
54+
* Returns an instance of a fake status object with the same task ID.
55+
* @return FakeAsyncTaskStatus The fake AsyncTaskStatus object for testing.
56+
*/
57+
public function fake(): FakeAsyncTaskStatus
58+
{
59+
return new FakeAsyncTaskStatus($this->taskID);
60+
}
61+
5362
/**
5463
* Returns the task ID encoded in base64, mainly for result checking.
5564
* @return string The encoded task ID.

src/FakeAsyncTask.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Vectorial1024\LaravelProcessAsync;
6+
7+
use Closure;
8+
9+
/**
10+
* The fake AsyncTask class for testing.
11+
*/
12+
class FakeAsyncTask extends AsyncTask
13+
{
14+
/**
15+
* Creates a FakeAsyncTask instance.
16+
*
17+
* @param \Closure|AsyncTaskInterface $theTask The task to be executed in the background.
18+
* @param string|null $taskID (optional) The user-specified task ID of this AsyncTask. Should be unique.
19+
* @see AsyncTask::fake() an alternative way of creating FakeAsyncTask instances.
20+
*/
21+
public function __construct(Closure|AsyncTaskInterface $theTask, string|null $taskID = null)
22+
{
23+
parent::__construct($theTask, taskID: $taskID);
24+
}
25+
26+
/**
27+
* Dummy overriding method to prevent the FakeAsyncTask object from actually running the specified background task.
28+
* @return void
29+
*/
30+
public function run(): void
31+
{
32+
// don't do anything!
33+
return;
34+
}
35+
36+
/**
37+
* Fakes the AsyncTask being started in the background, but does not actually start the task.
38+
* @return FakeAsyncTaskStatus The status object for the fake-started FakeAsyncTask.
39+
*/
40+
public function start(): FakeAsyncTaskStatus
41+
{
42+
return $this->getTaskStatusObject()->fake();
43+
}
44+
}

src/FakeAsyncTaskStatus.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Vectorial1024\LaravelProcessAsync;
6+
7+
/**
8+
* The fake AsyncTaskStatus class for testing. Fake async tasks are presumed to be running by default.
9+
*/
10+
class FakeAsyncTaskStatus extends AsyncTaskStatus
11+
{
12+
private bool $fakeIsRunning = true;
13+
14+
/**
15+
* Constructs a fake status object. Fake async tasks are presumed to be running by default.
16+
* @param string $fakeTaskID The task ID of the fake async task.
17+
*/
18+
public function __construct(string $fakeTaskID) {
19+
parent::__construct($fakeTaskID);
20+
}
21+
22+
/**
23+
* Returns whether the fake task is currently "running".
24+
* @return bool The faked "task is running" status.
25+
*/
26+
public function isRunning(): bool
27+
{
28+
return $this->fakeIsRunning;
29+
}
30+
31+
/**
32+
* Force the fake task to become stopped.
33+
*
34+
* 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.
35+
* @return void
36+
*/
37+
public function fakeStopRunning(): void
38+
{
39+
$this->fakeIsRunning = false;
40+
}
41+
}

tests/FakeAsyncTaskTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace Vectorial1024\LaravelProcessAsync\Tests;
4+
5+
use Vectorial1024\LaravelProcessAsync\AsyncTask;
6+
use Vectorial1024\LaravelProcessAsync\AsyncTaskStatus;
7+
use Vectorial1024\LaravelProcessAsync\Tests\Tasks\DummyAsyncTask;
8+
use Vectorial1024\LaravelProcessAsync\FakeAsyncTaskStatus;
9+
10+
// a series of tests that ensure the fake tasks are indeed fake while still look like the same
11+
class FakeAsyncTaskTest extends BaseTestCase
12+
{
13+
public function testFakeTaskDoesNotRun()
14+
{
15+
// the fake task should not even run
16+
$testFileName = $this->getStoragePath("testFakeTaskDoesNotRun.txt");
17+
$task = new AsyncTask(new DummyAsyncTask("Hello world!", $testFileName));
18+
$fakeTask = $task->fake();
19+
20+
// fake start it
21+
$fakeTask->start();
22+
sleep(1);
23+
// there should have no file outputs
24+
$this->assertFileDoesNotExist($testFileName);
25+
}
26+
27+
public function testFakeTaskSameParams()
28+
{
29+
// the fake task should preserve its parameters
30+
$testFileName = $this->getStoragePath("testFakeTaskSameDetails.txt");
31+
$task = new AsyncTask(new DummyAsyncTask("Hello world!", $testFileName));
32+
$randomDuration = rand(1, 10);
33+
$task->withTimeLimit($randomDuration);
34+
35+
// fake it...
36+
$fakeTask = $task->fake();
37+
// ...and the parameters stay the same
38+
$this->assertEquals($task->getTimeLimit(), $fakeTask->getTimeLimit());
39+
40+
// 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.
41+
}
42+
43+
public function testFakeTaskStatus()
44+
{
45+
$taskID = "testFakeTaskStatus";
46+
$taskStatus = new AsyncTaskStatus($taskID);
47+
$fakeTaskStatusFromFake = $taskStatus->fake();
48+
$fakeTaskStatusFromNew = new FakeAsyncTaskStatus($taskID);
49+
50+
// should have same task ID
51+
$this->assertEquals($taskStatus->getEncodedTaskID(), $fakeTaskStatusFromFake->getEncodedTaskID());
52+
$this->assertEquals($taskStatus->getEncodedTaskID(), $fakeTaskStatusFromNew->getEncodedTaskID());
53+
}
54+
}

0 commit comments

Comments
 (0)