Skip to content

Commit 388965e

Browse files
committed
Feat: ConfigController tests
1 parent edb22e4 commit 388965e

6 files changed

Lines changed: 596 additions & 18 deletions

File tree

src/Configuration/Controller/ConfigController.php

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use PhpList\Core\Security\Authentication;
1414
use PhpList\RestBundle\Common\Controller\BaseController;
1515
use PhpList\RestBundle\Common\Validator\RequestValidator;
16-
use PhpList\RestBundle\Configuration\Request\ConfigRequest;
16+
use PhpList\RestBundle\Configuration\Request\CreateConfigRequest;
1717
use PhpList\RestBundle\Configuration\Request\UpdateConfigRequest;
1818
use PhpList\RestBundle\Configuration\Serializer\ConfigNormalizer;
1919
use Symfony\Bridge\Doctrine\Attribute\MapEntity;
@@ -37,11 +37,11 @@ public function __construct(
3737

3838
#[Route('', name: 'get_list', methods: ['GET'])]
3939
#[OA\Get(
40-
path: '/api/v2/config',
40+
path: '/api/v2/configs',
4141
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
4242
'Returns all configuration items.',
4343
summary: 'Gets all configuration items.',
44-
tags: ['config'],
44+
tags: ['configs'],
4545
parameters: [
4646
new OA\Parameter(
4747
name: 'php-auth-pw',
@@ -105,11 +105,11 @@ public function list(Request $request): JsonResponse
105105

106106
#[Route('/{key}', name: 'get_one', requirements: ['key' => '[A-Za-z0-9_.:-]+'], methods: ['GET'])]
107107
#[OA\Get(
108-
path: '/api/v2/config/{key}',
108+
path: '/api/v2/configs/{key}',
109109
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
110110
'Returns one configuration item by key.',
111111
summary: 'Gets a configuration item.',
112-
tags: ['config'],
112+
tags: ['configs'],
113113
parameters: [
114114
new OA\Parameter(
115115
name: 'php-auth-pw',
@@ -158,7 +158,7 @@ public function getOne(
158158

159159
#[Route('', name: 'create', methods: ['POST'])]
160160
#[OA\Post(
161-
path: '/api/v2/config',
161+
path: '/api/v2/configs',
162162
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
163163
'Creates a configuration item.',
164164
summary: 'Creates a configuration item.',
@@ -167,7 +167,7 @@ public function getOne(
167167
required: true,
168168
content: new OA\JsonContent(ref: '#/components/schemas/ConfigRequest')
169169
),
170-
tags: ['config'],
170+
tags: ['configs'],
171171
parameters: [
172172
new OA\Parameter(
173173
name: 'php-auth-pw',
@@ -203,8 +203,8 @@ public function getOne(
203203
public function create(Request $request): JsonResponse
204204
{
205205
$this->denyUnlessSettingsAdmin($request, 'You are not allowed to create configuration.');
206-
/* @var ConfigRequest $configRequest */
207-
$configRequest = $this->validator->validate($request, ConfigRequest::class);
206+
/* @var CreateConfigRequest $configRequest */
207+
$configRequest = $this->validator->validate($request, CreateConfigRequest::class);
208208

209209
$config = $this->manager->create($configRequest->getDto());
210210
$this->entityManager->flush();
@@ -214,7 +214,7 @@ public function create(Request $request): JsonResponse
214214

215215
#[Route('/{key}', name: 'update', requirements: ['key' => '[A-Za-z0-9_.:-]+'], methods: ['PUT'])]
216216
#[OA\Put(
217-
path: '/api/v2/config/{key}',
217+
path: '/api/v2/configs/{key}',
218218
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
219219
'Updates a configuration item value.',
220220
summary: 'Updates a configuration item.',
@@ -223,7 +223,7 @@ public function create(Request $request): JsonResponse
223223
required: true,
224224
content: new OA\JsonContent(ref: '#/components/schemas/ConfigUpdateRequest')
225225
),
226-
tags: ['config'],
226+
tags: ['configs'],
227227
parameters: [
228228
new OA\Parameter(
229229
name: 'php-auth-pw',
@@ -286,11 +286,11 @@ public function update(
286286

287287
#[Route('/{key}', name: 'delete', requirements: ['key' => '[A-Za-z0-9_.:-]+'], methods: ['DELETE'])]
288288
#[OA\Delete(
289-
path: '/api/v2/config/{key}',
289+
path: '/api/v2/configs/{key}',
290290
description: '🚧 **Status: Beta** – This method is under development. Avoid using in production. ' .
291291
'Deletes a configuration item.',
292292
summary: 'Deletes a configuration item.',
293-
tags: ['config'],
293+
tags: ['configs'],
294294
parameters: [
295295
new OA\Parameter(
296296
name: 'php-auth-pw',

src/Configuration/Request/ConfigRequest.php renamed to src/Configuration/Request/CreateConfigRequest.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
],
2222
type: 'object'
2323
)]
24-
class ConfigRequest implements RequestInterface
24+
class CreateConfigRequest implements RequestInterface
2525
{
2626
#[Assert\NotBlank]
2727
#[Assert\Type('string')]
@@ -44,10 +44,10 @@ class ConfigRequest implements RequestInterface
4444
public function getDto(): CreateConfigDto
4545
{
4646
return new CreateConfigDto(
47-
$this->key,
48-
$this->value,
49-
$this->editable,
50-
$this->type
47+
key: $this->key,
48+
value: $this->value,
49+
editable: $this->editable,
50+
type: $this->type
5151
);
5252
}
5353
}
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\RestBundle\Tests\Integration\Configuration\Controller;
6+
7+
use PhpList\Core\Domain\Configuration\Model\Config;
8+
use PhpList\RestBundle\Configuration\Controller\ConfigController;
9+
use PhpList\RestBundle\Tests\Integration\Common\AbstractTestController;
10+
use PhpList\RestBundle\Tests\Integration\Identity\Fixtures\AdministratorFixture;
11+
use PhpList\RestBundle\Tests\Integration\Identity\Fixtures\AdministratorTokenFixture;
12+
13+
class ConfigControllerTest extends AbstractTestController
14+
{
15+
public function testControllerIsAvailableViaContainer(): void
16+
{
17+
self::assertInstanceOf(ConfigController::class, self::getContainer()->get(ConfigController::class));
18+
}
19+
20+
public function testListWithoutSessionKeyReturnsForbidden(): void
21+
{
22+
self::getClient()->request('GET', '/api/v2/configs');
23+
$this->assertHttpForbidden();
24+
}
25+
26+
public function testListWithExpiredSessionKeyReturnsForbidden(): void
27+
{
28+
$this->loadFixtures([AdministratorFixture::class, AdministratorTokenFixture::class]);
29+
30+
self::getClient()->request(
31+
'GET',
32+
'/api/v2/configs',
33+
[],
34+
[],
35+
['PHP_AUTH_USER' => 'unused', 'PHP_AUTH_PW' => 'expiredtoken']
36+
);
37+
38+
$this->assertHttpForbidden();
39+
}
40+
41+
public function testListWithValidSessionKeyReturnsOkayWithPaginationStructure(): void
42+
{
43+
$this->authenticatedJsonRequest('GET', '/api/v2/configs');
44+
$this->assertHttpOkay();
45+
46+
$response = $this->getDecodedJsonResponseContent();
47+
self::assertIsArray($response);
48+
self::assertArrayHasKey('items', $response);
49+
self::assertArrayHasKey('pagination', $response);
50+
}
51+
52+
public function testListReturnsCreatedConfigData(): void
53+
{
54+
$config = new Config();
55+
$config->setKey('organisation_name');
56+
$config->setValue('Example Organisation');
57+
$config->setEditable(true);
58+
$config->setType('text');
59+
60+
$this->entityManager->persist($config);
61+
$this->entityManager->flush();
62+
63+
$this->authenticatedJsonRequest('GET', '/api/v2/configs');
64+
$this->assertHttpOkay();
65+
66+
$response = $this->getDecodedJsonResponseContent();
67+
self::assertNotEmpty($response['items']);
68+
69+
$found = false;
70+
foreach ($response['items'] as $item) {
71+
if ($item['key'] === 'organisation_name') {
72+
$found = true;
73+
self::assertSame('Example Organisation', $item['value']);
74+
self::assertTrue($item['editable']);
75+
self::assertSame('text', $item['type']);
76+
}
77+
}
78+
79+
self::assertTrue($found, 'Created config item not found in list response.');
80+
}
81+
82+
public function testGetOneWithoutSessionKeyReturnsForbidden(): void
83+
{
84+
self::getClient()->request('GET', '/api/v2/configs/organisation_name');
85+
$this->assertHttpForbidden();
86+
}
87+
88+
public function testGetOneWithValidSessionReturnsOkayAndData(): void
89+
{
90+
$config = new Config();
91+
$config->setKey('site_title');
92+
$config->setValue('My Site');
93+
$config->setEditable(true);
94+
95+
$this->entityManager->persist($config);
96+
$this->entityManager->flush();
97+
98+
$this->authenticatedJsonRequest('GET', '/api/v2/configs/site_title');
99+
$this->assertHttpOkay();
100+
101+
$response = $this->getDecodedJsonResponseContent();
102+
self::assertSame('site_title', $response['key']);
103+
self::assertSame('My Site', $response['value']);
104+
self::assertTrue($response['editable']);
105+
}
106+
107+
public function testGetOneWithInvalidKeyReturnsNotFound(): void
108+
{
109+
$this->authenticatedJsonRequest('GET', '/api/v2/configs/nonexistent_key');
110+
$this->assertHttpNotFound();
111+
}
112+
113+
public function testCreateWithoutSessionKeyReturnsForbidden(): void
114+
{
115+
$json = json_encode(['key' => 'new_key', 'value' => 'val']);
116+
$this->jsonRequest('POST', '/api/v2/configs', [], [], [], $json);
117+
$this->assertHttpForbidden();
118+
}
119+
120+
public function testCreateWithValidSessionCreatesConfig(): void
121+
{
122+
$json = json_encode(['key' => 'new_key', 'value' => 'val', 'editable' => true, 'type' => 'text']);
123+
$this->authenticatedJsonRequest('POST', '/api/v2/configs', [], [], [], $json);
124+
125+
$this->assertHttpCreated();
126+
$response = $this->getDecodedJsonResponseContent();
127+
self::assertSame('new_key', $response['key']);
128+
self::assertSame('val', $response['value']);
129+
self::assertTrue($response['editable']);
130+
self::assertSame('text', $response['type']);
131+
}
132+
133+
public function testCreateWithDuplicateKeyReturnsConflict(): void
134+
{
135+
$config = new Config();
136+
$config->setKey('dup_key');
137+
$config->setValue('first');
138+
$this->entityManager->persist($config);
139+
$this->entityManager->flush();
140+
141+
$json = json_encode(['key' => 'dup_key', 'value' => 'second']);
142+
$this->authenticatedJsonRequest('POST', '/api/v2/configs', [], [], [], $json);
143+
144+
$this->assertHttpConflict();
145+
}
146+
147+
public function testUpdateWithoutSessionKeyReturnsForbidden(): void
148+
{
149+
$this->jsonRequest('PUT', '/api/v2/configs/some_key', [], [], [], json_encode(['value' => 'x']));
150+
$this->assertHttpForbidden();
151+
}
152+
153+
public function testUpdateWithValidSessionUpdatesValue(): void
154+
{
155+
$config = new Config();
156+
$config->setKey('up_key');
157+
$config->setValue('old');
158+
$config->setEditable(true);
159+
$this->entityManager->persist($config);
160+
$this->entityManager->flush();
161+
162+
$this->authenticatedJsonRequest('PUT', '/api/v2/configs/up_key', [], [], [], json_encode(['value' => 'new']));
163+
164+
$this->assertHttpOkay();
165+
$response = $this->getDecodedJsonResponseContent();
166+
self::assertSame('new', $response['value']);
167+
}
168+
169+
public function testUpdateForNonexistentKeyReturnsNotFound(): void
170+
{
171+
$this->authenticatedJsonRequest(
172+
'PUT',
173+
'/api/v2/configs/does_not_exist',
174+
[],
175+
[],
176+
[],
177+
json_encode(['value' => 'x'])
178+
);
179+
$this->assertHttpNotFound();
180+
}
181+
182+
public function testUpdateNonEditableReturnsForbidden(): void
183+
{
184+
$config = new Config();
185+
$config->setKey('locked_key');
186+
$config->setValue('orig');
187+
$config->setEditable(false);
188+
$this->entityManager->persist($config);
189+
$this->entityManager->flush();
190+
191+
$this->authenticatedJsonRequest(
192+
'PUT',
193+
'/api/v2/configs/locked_key',
194+
[],
195+
[],
196+
[],
197+
json_encode(['value' => 'changed'])
198+
);
199+
200+
$this->assertHttpForbidden();
201+
}
202+
203+
public function testDeleteWithoutSessionKeyReturnsForbidden(): void
204+
{
205+
self::getClient()->request('DELETE', '/api/v2/configs/some_key');
206+
$this->assertHttpForbidden();
207+
}
208+
209+
public function testDeleteWithValidSessionDeletesConfig(): void
210+
{
211+
$config = new Config();
212+
$config->setKey('del_key');
213+
$config->setValue('to delete');
214+
$this->entityManager->persist($config);
215+
$this->entityManager->flush();
216+
217+
$this->authenticatedJsonRequest('DELETE', '/api/v2/configs/del_key');
218+
$this->assertHttpNoContent();
219+
220+
$this->entityManager->clear();
221+
self::assertNull($this->entityManager->getRepository(Config::class)->find('del_key'));
222+
}
223+
224+
public function testDeleteNonexistentReturnsNotFound(): void
225+
{
226+
$this->authenticatedJsonRequest('DELETE', '/api/v2/configs/unknown_key');
227+
$this->assertHttpNotFound();
228+
}
229+
}

0 commit comments

Comments
 (0)