Skip to content

Commit 4e5398f

Browse files
committed
Add tests for schedule stuff
1 parent a8c4d6a commit 4e5398f

File tree

6 files changed

+424
-5
lines changed

6 files changed

+424
-5
lines changed

app/Services/Schedules/ScheduleCreationService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public function __construct(
7777
*/
7878
public function handle($server, array $data, array $tasks = [])
7979
{
80-
Assert::true(($server instanceof Server || is_numeric($server)),
80+
Assert::true(($server instanceof Server || is_digit($server)),
8181
'First argument passed to handle must be numeric or instance of \Pterodactyl\Models\Server, received %s.'
8282
);
8383

app/Services/Schedules/Tasks/TaskCreationService.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,16 @@ public function __construct(TaskRepositoryInterface $repository)
5959
*/
6060
public function handle($schedule, array $data, $returnModel = true)
6161
{
62-
Assert::true(($schedule instanceof Schedule || is_numeric($schedule)),
62+
Assert::true(($schedule instanceof Schedule || is_digit($schedule)),
6363
'First argument passed to handle must be numeric or instance of \Pterodactyl\Models\Schedule, received %s.'
6464
);
6565

6666
$schedule = ($schedule instanceof Schedule) ? $schedule->id : $schedule;
67-
if ($data['time_interval'] === 'm' && $data['time_value'] > 15) {
67+
$delay = $data['time_interval'] === 'm' ? $data['time_value'] * 60 : $data['time_value'];
68+
if ($delay > 900) {
6869
throw new TaskIntervalTooLongException(trans('exceptions.tasks.chain_interval_too_long'));
6970
}
7071

71-
$delay = $data['time_interval'] === 'm' ? $data['time_value'] * 60 : $data['time_value'];
72-
7372
$repository = ($returnModel) ? $this->repository : $this->repository->withoutFresh();
7473
$task = $repository->create([
7574
'schedule_id' => $schedule,

app/helpers.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,17 @@ function human_readable($path, $precision = 2)
4545
return app('file')->humanReadableSize($path, $precision);
4646
}
4747
}
48+
49+
if (! function_exists('is_digit')) {
50+
/**
51+
* Deal with normal (and irritating) PHP behavior to determine if
52+
* a value is a non-float positive integer.
53+
*
54+
* @param mixed $value
55+
* @return bool
56+
*/
57+
function is_digit($value)
58+
{
59+
return is_bool($value) ? false : ctype_digit(strval($value));
60+
}
61+
}

database/factories/ModelFactory.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,23 @@
177177
'node_id' => $faker->randomNumber(),
178178
];
179179
});
180+
181+
$factory->define(Pterodactyl\Models\Schedule::class, function (Faker\Generator $faker) {
182+
return [
183+
'id' => $faker->unique()->randomNumber(),
184+
'server_id' => $faker->randomNumber(),
185+
'name' => $faker->firstName(),
186+
];
187+
});
188+
189+
$factory->define(Pterodactyl\Models\Task::class, function (Faker\Generator $faker) {
190+
return [
191+
'id' => $faker->unique()->randomNumber(),
192+
'schedule_id' => $faker->randomNumber(),
193+
'sequence_id' => $faker->randomNumber(1),
194+
'action' => 'command',
195+
'payload' => 'test command',
196+
'time_offset' => 120,
197+
'is_queued' => false,
198+
];
199+
});
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
<?php
2+
/*
3+
* Pterodactyl - Panel
4+
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
namespace Tests\Unit\Services\Schedules;
26+
27+
use Mockery as m;
28+
use Tests\TestCase;
29+
use Pterodactyl\Models\Node;
30+
use Pterodactyl\Models\Server;
31+
use Pterodactyl\Models\Schedule;
32+
use Illuminate\Database\ConnectionInterface;
33+
use Pterodactyl\Services\Schedules\ScheduleCreationService;
34+
use Pterodactyl\Services\Schedules\Tasks\TaskCreationService;
35+
use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
36+
37+
class ScheduleCreationServiceTest extends TestCase
38+
{
39+
/**
40+
* @var \Illuminate\Database\ConnectionInterface
41+
*/
42+
protected $connection;
43+
44+
/**
45+
* @var \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface
46+
*/
47+
protected $repository;
48+
49+
/**
50+
* @var \Pterodactyl\Services\Schedules\ScheduleCreationService
51+
*/
52+
protected $service;
53+
54+
/**
55+
* @var \Pterodactyl\Services\Schedules\Tasks\TaskCreationService
56+
*/
57+
protected $taskCreationService;
58+
59+
/**
60+
* Setup tests.
61+
*/
62+
public function setUp()
63+
{
64+
parent::setUp();
65+
66+
$this->connection = m::mock(ConnectionInterface::class);
67+
$this->repository = m::mock(ScheduleRepositoryInterface::class);
68+
$this->taskCreationService = m::mock(TaskCreationService::class);
69+
70+
$this->service = new ScheduleCreationService($this->connection, $this->repository, $this->taskCreationService);
71+
}
72+
73+
/**
74+
* Test that a schedule with no tasks can be created.
75+
*/
76+
public function testScheduleWithNoTasksIsCreated()
77+
{
78+
$schedule = factory(Schedule::class)->make();
79+
$server = factory(Server::class)->make();
80+
81+
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
82+
$this->repository->shouldReceive('create')->with(['server_id' => $server->id, 'test_data' => 'test_value'])->once()->andReturn($schedule);
83+
$this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
84+
85+
$response = $this->service->handle($server, ['test_data' => 'test_value']);
86+
$this->assertNotEmpty($response);
87+
$this->assertInstanceOf(Schedule::class, $response);
88+
$this->assertEquals($schedule, $response);
89+
}
90+
91+
/**
92+
* Test that a schedule with at least one task can be created.
93+
*/
94+
public function testScheduleWithTasksIsCreated()
95+
{
96+
$schedule = factory(Schedule::class)->make();
97+
$server = factory(Server::class)->make();
98+
99+
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
100+
$this->repository->shouldReceive('create')->with(['server_id' => $server->id, 'test_data' => 'test_value'])->once()->andReturn($schedule);
101+
$this->taskCreationService->shouldReceive('handle')->with($schedule, [
102+
'time_interval' => 'm',
103+
'time_value' => 10,
104+
'sequence_id' => 1,
105+
'action' => 'test',
106+
'payload' => 'testpayload',
107+
], false)->once()->andReturnNull();
108+
109+
$this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
110+
111+
$response = $this->service->handle($server, ['test_data' => 'test_value'], [
112+
['time_interval' => 'm', 'time_value' => 10, 'action' => 'test', 'payload' => 'testpayload'],
113+
]);
114+
$this->assertNotEmpty($response);
115+
$this->assertInstanceOf(Schedule::class, $response);
116+
$this->assertEquals($schedule, $response);
117+
}
118+
119+
/**
120+
* Test that an ID can be passed in place of the server model.
121+
*/
122+
public function testIdCanBePassedInPlaceOfServerModel()
123+
{
124+
$schedule = factory(Schedule::class)->make();
125+
126+
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
127+
$this->repository->shouldReceive('create')->with(['server_id' => 1234, 'test_data' => 'test_value'])->once()->andReturn($schedule);
128+
$this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
129+
130+
$response = $this->service->handle(1234, ['test_data' => 'test_value']);
131+
$this->assertNotEmpty($response);
132+
$this->assertInstanceOf(Schedule::class, $response);
133+
$this->assertEquals($schedule, $response);
134+
}
135+
136+
/**
137+
* Test that an exception is raised if invalid data is passed.
138+
*
139+
* @dataProvider invalidServerArgumentProvider
140+
* @expectedException \InvalidArgumentException
141+
*/
142+
public function testExceptionIsThrownIfServerIsInvalid($attribute)
143+
{
144+
$this->service->handle($attribute, []);
145+
}
146+
147+
/**
148+
* Return an array of invalid server data to test aganist.
149+
*
150+
* @return array
151+
*/
152+
public function invalidServerArgumentProvider()
153+
{
154+
return [
155+
[123.456],
156+
['server'],
157+
['abc123'],
158+
['123_test'],
159+
[new Node()],
160+
[Server::class],
161+
];
162+
}
163+
}

0 commit comments

Comments
 (0)