Skip to content

Commit e7c64bc

Browse files
committed
Add test coverage for schedule execution
1 parent c1ee0ac commit e7c64bc

File tree

4 files changed

+106
-5
lines changed

4 files changed

+106
-5
lines changed

app/Http/Requests/Api/Client/Servers/Schedules/TriggerScheduleRequest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
namespace Pterodactyl\Http\Requests\Api\Client\Servers\Schedules;
44

55
use Pterodactyl\Models\Permission;
6-
use Illuminate\Foundation\Http\FormRequest;
6+
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
77

8-
class TriggerScheduleRequest extends FormRequest
8+
class TriggerScheduleRequest extends ClientApiRequest
99
{
1010
/**
1111
* @return string
@@ -18,7 +18,7 @@ public function permission(): string
1818
/**
1919
* @return array
2020
*/
21-
public function rules()
21+
public function rules(): array
2222
{
2323
return [];
2424
}

app/Services/Schedules/ProcessScheduleService.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Illuminate\Contracts\Bus\Dispatcher;
77
use Pterodactyl\Jobs\Schedule\RunTaskJob;
88
use Illuminate\Database\ConnectionInterface;
9+
use Pterodactyl\Exceptions\DisplayException;
910

1011
class ProcessScheduleService
1112
{
@@ -42,7 +43,13 @@ public function __construct(ConnectionInterface $connection, Dispatcher $dispatc
4243
public function handle(Schedule $schedule, bool $now = false)
4344
{
4445
/** @var \Pterodactyl\Models\Task $task */
45-
$task = $schedule->tasks()->where('sequence_id', 1)->firstOrFail();
46+
$task = $schedule->tasks()->where('sequence_id', 1)->first();
47+
48+
if (is_null($task)) {
49+
throw new DisplayException(
50+
'Cannot process schedule for task execution: no tasks are registered.'
51+
);
52+
}
4653

4754
$this->connection->transaction(function () use ($schedule, $task) {
4855
$schedule->forceFill([

resources/scripts/components/server/schedules/ScheduleEditContainer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ export default ({ match, history, location: { state } }: RouteComponentProps<Par
146146
onDeleted={() => history.push(`/server/${id}/schedules`)}
147147
/>
148148
</Can>
149-
{schedule.isActive &&
149+
{schedule.isActive && schedule.tasks.length > 0 &&
150150
<Can action={'schedule.update'}>
151151
<RunScheduleButton schedule={schedule}/>
152152
</Can>
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
3+
namespace Pterodactyl\Tests\Integration\Api\Client\Server\Schedule;
4+
5+
use Pterodactyl\Models\Task;
6+
use Illuminate\Http\Response;
7+
use Pterodactyl\Models\Schedule;
8+
use Pterodactyl\Models\Permission;
9+
use Illuminate\Support\Facades\Bus;
10+
use Pterodactyl\Jobs\Schedule\RunTaskJob;
11+
use Pterodactyl\Tests\Integration\Api\Client\ClientApiIntegrationTestCase;
12+
13+
class ExecuteScheduleTest extends ClientApiIntegrationTestCase
14+
{
15+
/**
16+
* Test that a schedule can be executed and is updated in the database correctly.
17+
*
18+
* @param array $permissions
19+
* @dataProvider permissionsDataProvider
20+
*/
21+
public function testScheduleIsExecutedRightAway(array $permissions)
22+
{
23+
[$user, $server] = $this->generateTestAccount($permissions);
24+
25+
Bus::fake();
26+
27+
/** @var \Pterodactyl\Models\Schedule $schedule */
28+
$schedule = factory(Schedule::class)->create([
29+
'server_id' => $server->id,
30+
]);
31+
32+
$response = $this->actingAs($user)->postJson($this->link($schedule, '/execute'));
33+
$response->assertStatus(Response::HTTP_BAD_REQUEST);
34+
$response->assertJsonPath('errors.0.code', 'DisplayException');
35+
$response->assertJsonPath('errors.0.detail', 'Cannot process schedule for task execution: no tasks are registered.');
36+
37+
/** @var \Pterodactyl\Models\Task $task */
38+
$task = factory(Task::class)->create([
39+
'schedule_id' => $schedule->id,
40+
'sequence_id' => 1,
41+
'time_offset' => 2,
42+
]);
43+
44+
$this->actingAs($user)->postJson($this->link($schedule, '/execute'))->assertStatus(Response::HTTP_ACCEPTED);
45+
46+
Bus::assertDispatched(function (RunTaskJob $job) use ($task) {
47+
$this->assertSame($task->time_offset, $job->delay);
48+
$this->assertSame($task->id, $job->task->id);
49+
50+
return true;
51+
});
52+
}
53+
54+
/**
55+
* Test that the schedule is not executed if it is not currently active.
56+
*/
57+
public function testScheduleIsNotExecutedIfNotActive()
58+
{
59+
[$user, $server] = $this->generateTestAccount();
60+
61+
/** @var \Pterodactyl\Models\Schedule $schedule */
62+
$schedule = factory(Schedule::class)->create([
63+
'server_id' => $server->id,
64+
'is_active' => false,
65+
]);
66+
67+
$response = $this->actingAs($user)->postJson($this->link($schedule, "/execute"));
68+
69+
$response->assertStatus(Response::HTTP_BAD_REQUEST);
70+
$response->assertJsonPath('errors.0.code', 'BadRequestHttpException');
71+
$response->assertJsonPath('errors.0.detail', 'Cannot trigger schedule exection for a schedule that is not currently active.');
72+
}
73+
74+
/**
75+
* Test that a user without the schedule update permission cannot execute it.
76+
*/
77+
public function testUserWithoutScheduleUpdatePermissionCannotExecute()
78+
{
79+
[$user, $server] = $this->generateTestAccount([Permission::ACTION_SCHEDULE_CREATE]);
80+
81+
/** @var \Pterodactyl\Models\Schedule $schedule */
82+
$schedule = factory(Schedule::class)->create(['server_id' => $server->id]);
83+
84+
$this->actingAs($user)->postJson($this->link($schedule, '/execute'))->assertForbidden();
85+
}
86+
87+
/**
88+
* @return array
89+
*/
90+
public function permissionsDataProvider(): array
91+
{
92+
return [[[]], [[Permission::ACTION_SCHEDULE_UPDATE]]];
93+
}
94+
}

0 commit comments

Comments
 (0)