Skip to content

Provide fake objects for external testing #19

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions src/AsyncTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -131,6 +146,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.
*
Expand Down Expand Up @@ -192,8 +219,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();
Expand Down
9 changes: 9 additions & 0 deletions src/AsyncTaskStatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
44 changes: 44 additions & 0 deletions src/FakeAsyncTask.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace Vectorial1024\LaravelProcessAsync;

use Closure;

/**
* The fake AsyncTask class for testing.
*/
class FakeAsyncTask extends AsyncTask
{
/**
* Creates a FakeAsyncTask instance.
*
* @param \Closure|AsyncTaskInterface $theTask The task to be executed in the background.
* @param string|null $taskID (optional) The user-specified task ID of this AsyncTask. Should be unique.
* @see AsyncTask::fake() an alternative way of creating FakeAsyncTask instances.
*/
public function __construct(Closure|AsyncTaskInterface $theTask, string|null $taskID = null)
{
parent::__construct($theTask, taskID: $taskID);
}

/**
* Dummy overriding method to prevent the FakeAsyncTask object from actually running the specified background task.
* @return void
*/
public function run(): void
{
// don't do anything!
return;
}

/**
* Fakes the AsyncTask being started in the background, but does not actually start the task.
* @return FakeAsyncTaskStatus The status object for the fake-started FakeAsyncTask.
*/
public function start(): FakeAsyncTaskStatus
{
return $this->getTaskStatusObject()->fake();
}
}
41 changes: 41 additions & 0 deletions src/FakeAsyncTaskStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace Vectorial1024\LaravelProcessAsync;

/**
* The fake AsyncTaskStatus class for testing. Fake async tasks are presumed to be running by default.
*/
class FakeAsyncTaskStatus extends AsyncTaskStatus
{
private bool $fakeIsRunning = true;

/**
* Constructs a fake status object. Fake async tasks are presumed to be running by default.
* @param string $fakeTaskID The task ID of the fake async task.
*/
public function __construct(string $fakeTaskID) {
parent::__construct($fakeTaskID);
}

/**
* Returns whether the fake task is currently "running".
* @return bool The faked "task is running" status.
*/
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;
}
}
54 changes: 54 additions & 0 deletions tests/FakeAsyncTaskTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Vectorial1024\LaravelProcessAsync\Tests;

use Vectorial1024\LaravelProcessAsync\AsyncTask;
use Vectorial1024\LaravelProcessAsync\AsyncTaskStatus;
use Vectorial1024\LaravelProcessAsync\Tests\Tasks\DummyAsyncTask;
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
{
public function testFakeTaskDoesNotRun()
{
// the fake task should not even run
$testFileName = $this->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());
}
}