Skip to content

Commit 53d1182

Browse files
committed
Add unit tests for API key controller
1 parent cb62e6a commit 53d1182

File tree

3 files changed

+225
-6
lines changed

3 files changed

+225
-6
lines changed

app/Http/Controllers/Base/APIController.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public function create(Request $request)
9393
return view('base.api.new', [
9494
'permissions' => [
9595
'user' => collect(APIPermission::CONST_PERMISSIONS)->pull('_user'),
96-
'admin' => ! $request->user()->root_admin ?: collect(APIPermission::CONST_PERMISSIONS)->except('_user')->toArray(),
96+
'admin' => ! $request->user()->root_admin ? null : collect(APIPermission::CONST_PERMISSIONS)->except('_user')->toArray(),
9797
],
9898
]);
9999
}
@@ -103,14 +103,15 @@ public function create(Request $request)
103103
*
104104
* @param \Pterodactyl\Http\Requests\Base\ApiKeyFormRequest $request
105105
* @return \Illuminate\Http\RedirectResponse
106+
*
106107
* @throws \Exception
107108
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
108109
*/
109110
public function store(ApiKeyFormRequest $request)
110111
{
111112
$adminPermissions = [];
112113
if ($request->user()->root_admin) {
113-
$adminPermissions = $request->input('admin_permissions') ?? [];
114+
$adminPermissions = $request->input('admin_permissions', []);
114115
}
115116

116117
$secret = $this->keyService->handle([

tests/Assertions/ControllerAssertionsTrait.php

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424

2525
namespace Tests\Assertions;
2626

27+
use Illuminate\View\View;
2728
use PHPUnit_Framework_Assert;
29+
use Illuminate\Http\RedirectResponse;
2830

2931
trait ControllerAssertionsTrait
3032
{
@@ -36,6 +38,7 @@ trait ControllerAssertionsTrait
3638
*/
3739
public function assertViewNameEquals($name, $view)
3840
{
41+
PHPUnit_Framework_Assert::assertInstanceOf(View::class, $view);
3942
PHPUnit_Framework_Assert::assertEquals($name, $view->getName());
4043
}
4144

@@ -47,6 +50,7 @@ public function assertViewNameEquals($name, $view)
4750
*/
4851
public function assertViewNameNotEquals($name, $view)
4952
{
53+
PHPUnit_Framework_Assert::assertInstanceOf(View::class, $view);
5054
PHPUnit_Framework_Assert::assertNotEquals($name, $view->getName());
5155
}
5256

@@ -58,7 +62,16 @@ public function assertViewNameNotEquals($name, $view)
5862
*/
5963
public function assertViewHasKey($attribute, $view)
6064
{
61-
PHPUnit_Framework_Assert::assertArrayHasKey($attribute, $view->getData());
65+
PHPUnit_Framework_Assert::assertInstanceOf(View::class, $view);
66+
67+
if (str_contains($attribute, '.')) {
68+
PHPUnit_Framework_Assert::assertNotEquals(
69+
'__TEST__FAIL',
70+
array_get($view->getData(), $attribute, '__TEST__FAIL')
71+
);
72+
} else {
73+
PHPUnit_Framework_Assert::assertArrayHasKey($attribute, $view->getData());
74+
}
6275
}
6376

6477
/**
@@ -69,7 +82,16 @@ public function assertViewHasKey($attribute, $view)
6982
*/
7083
public function assertViewNotHasKey($attribute, $view)
7184
{
72-
PHPUnit_Framework_Assert::assertArrayNotHasKey($attribute, $view->getData());
85+
PHPUnit_Framework_Assert::assertInstanceOf(View::class, $view);
86+
87+
if (str_contains($attribute, '.')) {
88+
PHPUnit_Framework_Assert::assertEquals(
89+
'__TEST__PASS',
90+
array_get($view->getData(), $attribute, '__TEST__PASS')
91+
);
92+
} else {
93+
PHPUnit_Framework_Assert::assertArrayNotHasKey($attribute, $view->getData());
94+
}
7395
}
7496

7597
/**
@@ -81,15 +103,30 @@ public function assertViewNotHasKey($attribute, $view)
81103
*/
82104
public function assertViewKeyEquals($attribute, $value, $view)
83105
{
84-
PHPUnit_Framework_Assert::assertEquals($value, array_get($view->getData(), $attribute));
106+
PHPUnit_Framework_Assert::assertInstanceOf(View::class, $view);
107+
PHPUnit_Framework_Assert::assertEquals($value, array_get($view->getData(), $attribute, '__TEST__FAIL'));
108+
}
109+
110+
/**
111+
* Assert that a view attribute does not equal a given parameter.
112+
*
113+
* @param string $attribute
114+
* @param mixed $value
115+
* @param \Illuminate\View\View $view
116+
*/
117+
public function assertViewKeyNotEquals($attribute, $value, $view)
118+
{
119+
PHPUnit_Framework_Assert::assertInstanceOf(View::class, $view);
120+
PHPUnit_Framework_Assert::assertNotEquals($value, array_get($view->getData(), $attribute, '__TEST__FAIL'));
85121
}
86122

87123
/**
88-
* @param string $route
124+
* @param string $route
89125
* @param \Illuminate\Http\RedirectResponse $response
90126
*/
91127
public function assertRouteRedirectEquals($route, $response)
92128
{
129+
PHPUnit_Framework_Assert::assertInstanceOf(RedirectResponse::class, $response);
93130
PHPUnit_Framework_Assert::assertEquals(route($route), $response->getTargetUrl());
94131
}
95132
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
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\Http\Controllers\Base;
26+
27+
use Mockery as m;
28+
use Tests\TestCase;
29+
use Illuminate\Http\Request;
30+
use Pterodactyl\Models\User;
31+
use Illuminate\Http\Response;
32+
use Prologue\Alerts\AlertsMessageBag;
33+
use Tests\Assertions\ControllerAssertionsTrait;
34+
use Pterodactyl\Services\Api\KeyCreationService;
35+
use Pterodactyl\Http\Controllers\Base\APIController;
36+
use Pterodactyl\Http\Requests\Base\ApiKeyFormRequest;
37+
use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface;
38+
39+
class APIControllerTest extends TestCase
40+
{
41+
use ControllerAssertionsTrait;
42+
43+
/**
44+
* @var \Prologue\Alerts\AlertsMessageBag
45+
*/
46+
protected $alert;
47+
48+
/**
49+
* @var \Pterodactyl\Http\Controllers\Base\APIController
50+
*/
51+
protected $controller;
52+
53+
/**
54+
* @var \Pterodactyl\Services\Api\KeyCreationService
55+
*/
56+
protected $keyService;
57+
58+
/**
59+
* @var \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface
60+
*/
61+
protected $repository;
62+
63+
/**
64+
* @var \Illuminate\Http\Request
65+
*/
66+
protected $request;
67+
68+
/**
69+
* Setup tests.
70+
*/
71+
public function setUp()
72+
{
73+
parent::setUp();
74+
75+
$this->alert = m::mock(AlertsMessageBag::class);
76+
$this->keyService = m::mock(KeyCreationService::class);
77+
$this->repository = m::mock(ApiKeyRepositoryInterface::class);
78+
$this->request = m::mock(Request::class);
79+
80+
$this->controller = new APIController($this->alert, $this->repository, $this->keyService);
81+
}
82+
83+
/**
84+
* Test the index controller.
85+
*/
86+
public function testIndexController()
87+
{
88+
$model = factory(User::class)->make();
89+
90+
$this->request->shouldReceive('user')->withNoArgs()->once()->andReturn($model);
91+
$this->repository->shouldReceive('findWhere')->with([['user_id', '=', $model->id]])->once()->andReturn(['testkeys']);
92+
93+
$response = $this->controller->index($this->request);
94+
$this->assertViewNameEquals('base.api.index', $response);
95+
$this->assertViewHasKey('keys', $response);
96+
$this->assertViewKeyEquals('keys', ['testkeys'], $response);
97+
}
98+
99+
/**
100+
* Test the create API view controller.
101+
*
102+
* @dataProvider rootAdminDataProvider
103+
*/
104+
public function testCreateController($admin)
105+
{
106+
$model = factory(User::class)->make(['root_admin' => $admin]);
107+
$this->request->shouldReceive('user')->withNoArgs()->once()->andReturn($model);
108+
109+
$response = $this->controller->create($this->request);
110+
$this->assertViewNameEquals('base.api.new', $response);
111+
$this->assertViewHasKey('permissions.user', $response);
112+
$this->assertViewHasKey('permissions.admin', $response);
113+
114+
if ($admin) {
115+
$this->assertViewKeyNotEquals('permissions.admin', null, $response);
116+
} else {
117+
$this->assertViewKeyEquals('permissions.admin', null, $response);
118+
}
119+
}
120+
121+
/**
122+
* Test the store functionality for a non-admin user.
123+
*
124+
* @dataProvider rootAdminDataProvider
125+
*/
126+
public function testStoreController($admin)
127+
{
128+
$this->request = m::mock(ApiKeyFormRequest::class);
129+
$model = factory(User::class)->make(['root_admin' => $admin]);
130+
131+
if ($admin) {
132+
$this->request->shouldReceive('input')->with('admin_permissions', [])->once()->andReturn(['admin.permission']);
133+
}
134+
135+
$this->request->shouldReceive('user')->withNoArgs()->andReturn($model);
136+
$this->request->shouldReceive('input')->with('allowed_ips')->once()->andReturnNull();
137+
$this->request->shouldReceive('input')->with('memo')->once()->andReturnNull();
138+
$this->request->shouldReceive('input')->with('permissions', [])->once()->andReturn(['test.permission']);
139+
140+
$this->keyService->shouldReceive('handle')->with([
141+
'user_id' => $model->id,
142+
'allowed_ips' => null,
143+
'memo' => null,
144+
], ['test.permission'], ($admin) ? ['admin.permission'] : [])->once()->andReturn('testToken');
145+
146+
$this->alert->shouldReceive('success')->with(trans('base.api.index.keypair_created', ['token' => 'testToken']))->once()->andReturnSelf()
147+
->shouldReceive('flash')->withNoArgs()->once()->andReturnNull();
148+
149+
$response = $this->controller->store($this->request);
150+
$this->assertRouteRedirectEquals('account.api', $response);
151+
}
152+
153+
/**
154+
* Test the API key revocation controller.
155+
*/
156+
public function testRevokeController()
157+
{
158+
$model = factory(User::class)->make();
159+
$this->request->shouldReceive('user')->withNoArgs()->once()->andReturn($model);
160+
161+
$this->repository->shouldReceive('deleteWhere')->with([
162+
['user_id', '=', $model->id],
163+
['public', '=', 'testKey123'],
164+
])->once()->andReturnNull();
165+
166+
$response = $this->controller->revoke($this->request, 'testKey123');
167+
$this->assertInstanceOf(Response::class, $response);
168+
$this->assertEmpty($response->getContent());
169+
$this->assertEquals(204, $response->getStatusCode());
170+
}
171+
172+
/**
173+
* Data provider to determine if a user is a root admin.
174+
*
175+
* @return array
176+
*/
177+
public function rootAdminDataProvider()
178+
{
179+
return [[0], [1]];
180+
}
181+
}

0 commit comments

Comments
 (0)