Skip to content

Commit b2ec996

Browse files
committed
Unit tests for pack service
1 parent 2e34762 commit b2ec996

File tree

5 files changed

+718
-1
lines changed

5 files changed

+718
-1
lines changed

app/Services/Packs/PackDeletionService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public function handle($pack)
8787
$pack = $this->repository->withColumns(['id', 'uuid'])->find($pack);
8888
}
8989

90-
$count = $this->serverRepository->findCountWhere([['pack_id', '=', $pack]]);
90+
$count = $this->serverRepository->findCountWhere([['pack_id', '=', $pack->id]]);
9191
if ($count !== 0) {
9292
throw new HasActiveServersException(trans('admin/exceptions.packs.delete_has_servers'));
9393
}
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
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\Packs;
26+
27+
use Exception;
28+
use Illuminate\Contracts\Filesystem\Factory;
29+
use Illuminate\Http\UploadedFile;
30+
use Mockery as m;
31+
use Illuminate\Database\ConnectionInterface;
32+
use Pterodactyl\Contracts\Repository\PackRepositoryInterface;
33+
use Pterodactyl\Exceptions\Service\Pack\InvalidFileMimeTypeException;
34+
use Pterodactyl\Exceptions\Service\Pack\InvalidFileUploadException;
35+
use Pterodactyl\Models\Pack;
36+
use Pterodactyl\Services\Packs\PackCreationService;
37+
use Tests\TestCase;
38+
39+
class PackCreationServiceTest extends TestCase
40+
{
41+
/**
42+
* @var \Illuminate\Database\ConnectionInterface
43+
*/
44+
protected $connection;
45+
46+
/**
47+
* @var \Illuminate\Http\UploadedFile
48+
*/
49+
protected $file;
50+
51+
/**
52+
* @var \Pterodactyl\Contracts\Repository\PackRepositoryInterface
53+
*/
54+
protected $repository;
55+
56+
/**
57+
* @var \Pterodactyl\Services\Packs\PackCreationService
58+
*/
59+
protected $service;
60+
61+
/**
62+
* @var \Illuminate\Contracts\Filesystem\Factory
63+
*/
64+
protected $storage;
65+
66+
/**
67+
* @var \Ramsey\Uuid\Uuid
68+
*/
69+
protected $uuid;
70+
71+
/**
72+
* Setup tests.
73+
*/
74+
public function setUp()
75+
{
76+
parent::setUp();
77+
78+
$this->connection = m::mock(ConnectionInterface::class);
79+
$this->file = m::mock(UploadedFile::class);
80+
$this->repository = m::mock(PackRepositoryInterface::class);
81+
$this->storage = m::mock(Factory::class);
82+
$this->uuid = m::mock('overload:\Ramsey\Uuid\Uuid');
83+
84+
$this->service = new PackCreationService($this->connection, $this->storage, $this->repository);
85+
}
86+
87+
/**
88+
* Test that a pack is created when no file upload is provided.
89+
*/
90+
public function testPackIsCreatedWhenNoUploadedFileIsPassed()
91+
{
92+
$model = factory(Pack::class)->make();
93+
94+
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
95+
$this->uuid->shouldReceive('uuid4')->withNoArgs()->once()->andReturn($model->uuid);
96+
$this->repository->shouldReceive('create')->with([
97+
'uuid' => $model->uuid,
98+
'selectable' => false,
99+
'visible' => false,
100+
'locked' => false,
101+
'test-data' => 'value',
102+
])->once()->andReturn($model);
103+
104+
$this->storage->shouldReceive('disk')->withNoArgs()->once()->andReturnSelf()
105+
->shouldReceive('makeDirectory')->with('packs/' . $model->uuid)->once()->andReturnNull();
106+
$this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
107+
108+
$response = $this->service->handle(['test-data' => 'value']);
109+
$this->assertInstanceOf(Pack::class, $response);
110+
$this->assertEquals($model, $response);
111+
}
112+
113+
/**
114+
* Test that a pack can be created when an uploaded file is provided.
115+
*
116+
* @dataProvider mimetypeProvider
117+
*/
118+
public function testPackIsCreatedWhenUploadedFileIsProvided($mime)
119+
{
120+
$model = factory(Pack::class)->make();
121+
122+
$this->file->shouldReceive('isValid')->withNoArgs()->once()->andReturn(true);
123+
$this->file->shouldReceive('getMimeType')->withNoArgs()->once()->andReturn($mime);
124+
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
125+
$this->uuid->shouldReceive('uuid4')->withNoArgs()->once()->andReturn($model->uuid);
126+
$this->repository->shouldReceive('create')->with([
127+
'uuid' => $model->uuid,
128+
'selectable' => false,
129+
'visible' => false,
130+
'locked' => false,
131+
'test-data' => 'value',
132+
])->once()->andReturn($model);
133+
134+
$this->storage->shouldReceive('disk')->withNoArgs()->once()->andReturnSelf()
135+
->shouldReceive('makeDirectory')->with('packs/' . $model->uuid)->once()->andReturnNull();
136+
$this->file->shouldReceive('storeAs')->with('packs/' . $model->uuid, 'archive.tar.gz')->once()->andReturnNull();
137+
$this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
138+
139+
$response = $this->service->handle(['test-data' => 'value'], $this->file);
140+
$this->assertInstanceOf(Pack::class, $response);
141+
$this->assertEquals($model, $response);
142+
}
143+
144+
/**
145+
* Test that an exception is thrown if the file upload is not valid.
146+
*/
147+
public function testExceptionIsThrownIfInvalidUploadIsProvided()
148+
{
149+
$this->file->shouldReceive('isValid')->withNoArgs()->once()->andReturn(false);
150+
151+
try {
152+
$this->service->handle([], $this->file);
153+
} catch (Exception $exception) {
154+
$this->assertInstanceOf(InvalidFileUploadException::class, $exception);
155+
$this->assertEquals(trans('admin/exceptions.packs.invalid_upload'), $exception->getMessage());
156+
}
157+
}
158+
159+
/**
160+
* Test that an exception is thrown when an invalid mimetype is provided.
161+
*
162+
* @dataProvider invalidMimetypeProvider
163+
*/
164+
public function testExceptionIsThrownIfInvalidMimetypeIsFound($mime)
165+
{
166+
$this->file->shouldReceive('isValid')->withNoArgs()->once()->andReturn(true);
167+
$this->file->shouldReceive('getMimeType')->withNoArgs()->once()->andReturn($mime);
168+
169+
try {
170+
$this->service->handle([], $this->file);
171+
} catch (InvalidFileMimeTypeException $exception) {
172+
$this->assertEquals(trans('admin/exceptions.packs.invalid_mime', [
173+
'type' => implode(', ', PackCreationService::VALID_UPLOAD_TYPES),
174+
]), $exception->getMessage());
175+
}
176+
}
177+
178+
/**
179+
* Return an array of valid mimetypes to test aganist.
180+
*
181+
* @return array
182+
*/
183+
public function mimetypeProvider()
184+
{
185+
return [
186+
['application/gzip'],
187+
['application/x-gzip'],
188+
];
189+
}
190+
191+
/**
192+
* Provide invalid mimetypes to test exceptions aganist.
193+
*
194+
* @return array
195+
*/
196+
public function invalidMimetypeProvider()
197+
{
198+
return [
199+
['application/zip'],
200+
['text/plain'],
201+
['image/jpeg'],
202+
];
203+
}
204+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
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\Packs;
26+
27+
use Exception;
28+
use Illuminate\Contracts\Filesystem\Factory;
29+
use Illuminate\Database\ConnectionInterface;
30+
use Mockery as m;
31+
use Pterodactyl\Contracts\Repository\PackRepositoryInterface;
32+
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
33+
use Pterodactyl\Exceptions\Service\HasActiveServersException;
34+
use Pterodactyl\Models\Pack;
35+
use Pterodactyl\Services\Packs\PackDeletionService;
36+
use Tests\TestCase;
37+
38+
class PackDeletionServiceTest extends TestCase
39+
{
40+
/**
41+
* @var \Illuminate\Database\ConnectionInterface
42+
*/
43+
protected $connection;
44+
45+
/**
46+
* @var \Pterodactyl\Contracts\Repository\PackRepositoryInterface
47+
*/
48+
protected $repository;
49+
50+
/**
51+
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
52+
*/
53+
protected $serverRepository;
54+
55+
/**
56+
* @var \Pterodactyl\Services\Packs\PackDeletionService
57+
*/
58+
protected $service;
59+
60+
/**
61+
* @var \Illuminate\Contracts\Filesystem\Factory
62+
*/
63+
protected $storage;
64+
65+
/**
66+
* Setup tests.
67+
*/
68+
public function setUp()
69+
{
70+
parent::setUp();
71+
72+
$this->connection = m::mock(ConnectionInterface::class);
73+
$this->repository = m::mock(PackRepositoryInterface::class);
74+
$this->serverRepository = m::mock(ServerRepositoryInterface::class);
75+
$this->storage = m::mock(Factory::class);
76+
77+
$this->service = new PackDeletionService(
78+
$this->connection,
79+
$this->storage,
80+
$this->repository,
81+
$this->serverRepository
82+
);
83+
}
84+
85+
/**
86+
* Test that a pack is deleted.
87+
*/
88+
public function testPackIsDeleted()
89+
{
90+
$model = factory(Pack::class)->make();
91+
92+
$this->serverRepository->shouldReceive('findCountWhere')->with([['pack_id', '=', $model->id]])->once()->andReturn(0);
93+
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
94+
$this->repository->shouldReceive('delete')->with($model->id)->once()->andReturnNull();
95+
$this->storage->shouldReceive('disk')->withNoArgs()->once()->andReturnSelf()
96+
->shouldReceive('deleteDirectory')->with('packs/' . $model->uuid)->once()->andReturnNull();
97+
$this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
98+
99+
$this->service->handle($model);
100+
}
101+
102+
/**
103+
* Test that a pack ID can be passed in place of the model.
104+
*/
105+
public function testPackIdCanBePassedInPlaceOfModel()
106+
{
107+
$model = factory(Pack::class)->make();
108+
109+
$this->repository->shouldReceive('withColumns')->with(['id', 'uuid'])->once()->andReturnSelf()
110+
->shouldReceive('find')->with($model->id)->once()->andReturn($model);
111+
$this->serverRepository->shouldReceive('findCountWhere')->with([['pack_id', '=', $model->id]])->once()->andReturn(0);
112+
$this->connection->shouldReceive('beginTransaction')->withNoArgs()->once()->andReturnNull();
113+
$this->repository->shouldReceive('delete')->with($model->id)->once()->andReturnNull();
114+
$this->storage->shouldReceive('disk')->withNoArgs()->once()->andReturnSelf()
115+
->shouldReceive('deleteDirectory')->with('packs/' . $model->uuid)->once()->andReturnNull();
116+
$this->connection->shouldReceive('commit')->withNoArgs()->once()->andReturnNull();
117+
118+
$this->service->handle($model->id);
119+
}
120+
121+
/**
122+
* Test that an exception gets thrown if a server is attached to a pack.
123+
*/
124+
public function testExceptionIsThrownIfServerIsAttachedToPack()
125+
{
126+
$model = factory(Pack::class)->make();
127+
128+
$this->serverRepository->shouldReceive('findCountWhere')->with([['pack_id', '=', $model->id]])->once()->andReturn(1);
129+
130+
try {
131+
$this->service->handle($model);
132+
} catch (HasActiveServersException $exception) {
133+
$this->assertEquals(trans('admin/exceptions.packs.delete_has_servers'), $exception->getMessage());
134+
}
135+
}
136+
}

0 commit comments

Comments
 (0)