206 lines
7.8 KiB
PHP
206 lines
7.8 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace MintyPHP\Tests\Module\Security\Service;
|
||
|
|
|
||
|
|
use MintyPHP\Module\Security\Repository\SecurityCheckTemplateRepository;
|
||
|
|
use MintyPHP\Module\Security\Service\SecurityCheckTemplateService;
|
||
|
|
use PHPUnit\Framework\TestCase;
|
||
|
|
|
||
|
|
class SecurityCheckTemplateServiceTest extends TestCase
|
||
|
|
{
|
||
|
|
private const TENANT_ID = 1;
|
||
|
|
|
||
|
|
public function testCreateRejectsEmptyCode(): void
|
||
|
|
{
|
||
|
|
$repo = $this->createMock(SecurityCheckTemplateRepository::class);
|
||
|
|
$repo->expects($this->never())->method('insert');
|
||
|
|
$service = new SecurityCheckTemplateService($repo);
|
||
|
|
|
||
|
|
$result = $service->create(self::TENANT_ID, '', 'Name', 1);
|
||
|
|
|
||
|
|
$this->assertFalse($result['ok']);
|
||
|
|
$this->assertArrayHasKey('product_code', $result['errors']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testCreateRejectsInvalidCode(): void
|
||
|
|
{
|
||
|
|
$repo = $this->createMock(SecurityCheckTemplateRepository::class);
|
||
|
|
$service = new SecurityCheckTemplateService($repo);
|
||
|
|
|
||
|
|
$result = $service->create(self::TENANT_ID, 'has spaces!', 'Name', 1);
|
||
|
|
|
||
|
|
$this->assertFalse($result['ok']);
|
||
|
|
$this->assertArrayHasKey('product_code', $result['errors']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testCreateRejectsDuplicateCode(): void
|
||
|
|
{
|
||
|
|
$repo = $this->createMock(SecurityCheckTemplateRepository::class);
|
||
|
|
$repo->method('codeExists')->willReturn(true);
|
||
|
|
$service = new SecurityCheckTemplateService($repo);
|
||
|
|
|
||
|
|
$result = $service->create(self::TENANT_ID, 'intranet', 'Intranet', 1);
|
||
|
|
|
||
|
|
$this->assertFalse($result['ok']);
|
||
|
|
$this->assertArrayHasKey('product_code', $result['errors']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testCreateSucceeds(): void
|
||
|
|
{
|
||
|
|
$repo = $this->createMock(SecurityCheckTemplateRepository::class);
|
||
|
|
$repo->method('codeExists')->willReturn(false);
|
||
|
|
$repo->method('insert')->willReturn(12);
|
||
|
|
$service = new SecurityCheckTemplateService($repo);
|
||
|
|
|
||
|
|
$result = $service->create(self::TENANT_ID, 'intranet', 'Intranet', 1);
|
||
|
|
|
||
|
|
$this->assertTrue($result['ok']);
|
||
|
|
$this->assertSame(12, $result['id']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testSaveTechSchemaRejectsMissingTemplate(): void
|
||
|
|
{
|
||
|
|
$repo = $this->createMock(SecurityCheckTemplateRepository::class);
|
||
|
|
$repo->method('findById')->willReturn(null);
|
||
|
|
$repo->expects($this->never())->method('updateSchema');
|
||
|
|
$service = new SecurityCheckTemplateService($repo);
|
||
|
|
|
||
|
|
$result = $service->saveTechSchema(self::TENANT_ID, 99, [['type' => 'check', 'label' => 'X']], 1);
|
||
|
|
|
||
|
|
$this->assertFalse($result['ok']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testSaveTechSchemaSlugifiesKeysBumpsVersionAndKeepsSections(): void
|
||
|
|
{
|
||
|
|
$repo = $this->createMock(SecurityCheckTemplateRepository::class);
|
||
|
|
$repo->method('findById')->willReturn(['id' => 1, 'version' => 3]);
|
||
|
|
|
||
|
|
$capturedJson = null;
|
||
|
|
$capturedVersion = null;
|
||
|
|
$repo->method('updateSchema')->willReturnCallback(function (int $t, int $id, string $json, int $version) use (&$capturedJson, &$capturedVersion) {
|
||
|
|
$capturedJson = $json;
|
||
|
|
$capturedVersion = $version;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
});
|
||
|
|
|
||
|
|
$service = new SecurityCheckTemplateService($repo);
|
||
|
|
$result = $service->saveTechSchema(self::TENANT_ID, 1, [
|
||
|
|
['type' => 'section', 'label' => 'Intranet'],
|
||
|
|
['type' => 'check', 'label' => 'TLS überall erzwungen', 'hint' => 'check certs'],
|
||
|
|
], 1);
|
||
|
|
|
||
|
|
$this->assertTrue($result['ok']);
|
||
|
|
$this->assertSame(4, $capturedVersion);
|
||
|
|
|
||
|
|
$data = json_decode((string) $capturedJson, true);
|
||
|
|
$this->assertSame(4, $data['version']);
|
||
|
|
$this->assertSame('section', $data['items'][0]['type']);
|
||
|
|
$this->assertSame('check', $data['items'][1]['type']);
|
||
|
|
$this->assertSame('tls_ueberall_erzwungen', $data['items'][1]['key']);
|
||
|
|
$this->assertSame('check certs', $data['items'][1]['hint']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testSaveTechSchemaPersistsMarkdownAndOmitsEmpty(): void
|
||
|
|
{
|
||
|
|
$repo = $this->createMock(SecurityCheckTemplateRepository::class);
|
||
|
|
$repo->method('findById')->willReturn(['id' => 1, 'version' => 1]);
|
||
|
|
|
||
|
|
$capturedJson = null;
|
||
|
|
$repo->method('updateSchema')->willReturnCallback(function (int $t, int $id, string $json) use (&$capturedJson) {
|
||
|
|
$capturedJson = $json;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
});
|
||
|
|
|
||
|
|
$service = new SecurityCheckTemplateService($repo);
|
||
|
|
$service->saveTechSchema(self::TENANT_ID, 1, [
|
||
|
|
['type' => 'check', 'label' => 'TLS', 'markdown' => '**Verify** the certificate chain.'],
|
||
|
|
['type' => 'check', 'label' => 'Backup', 'markdown' => ' '],
|
||
|
|
], 1);
|
||
|
|
|
||
|
|
$data = json_decode((string) $capturedJson, true);
|
||
|
|
$this->assertSame('**Verify** the certificate chain.', $data['items'][0]['markdown']);
|
||
|
|
$this->assertArrayNotHasKey('markdown', $data['items'][1]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testSaveTechSchemaDeduplicatesKeys(): void
|
||
|
|
{
|
||
|
|
$repo = $this->createMock(SecurityCheckTemplateRepository::class);
|
||
|
|
$repo->method('findById')->willReturn(['id' => 1, 'version' => 1]);
|
||
|
|
|
||
|
|
$capturedJson = null;
|
||
|
|
$repo->method('updateSchema')->willReturnCallback(function (int $t, int $id, string $json) use (&$capturedJson) {
|
||
|
|
$capturedJson = $json;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
});
|
||
|
|
|
||
|
|
$service = new SecurityCheckTemplateService($repo);
|
||
|
|
$service->saveTechSchema(self::TENANT_ID, 1, [
|
||
|
|
['type' => 'check', 'label' => 'Backup'],
|
||
|
|
['type' => 'check', 'label' => 'Backup'],
|
||
|
|
], 1);
|
||
|
|
|
||
|
|
$data = json_decode((string) $capturedJson, true);
|
||
|
|
$this->assertSame('backup', $data['items'][0]['key']);
|
||
|
|
$this->assertSame('backup_2', $data['items'][1]['key']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testSaveTechSchemaRejectsItemWithoutLabel(): void
|
||
|
|
{
|
||
|
|
$repo = $this->createMock(SecurityCheckTemplateRepository::class);
|
||
|
|
$repo->method('findById')->willReturn(['id' => 1, 'version' => 1]);
|
||
|
|
$repo->expects($this->never())->method('updateSchema');
|
||
|
|
|
||
|
|
$service = new SecurityCheckTemplateService($repo);
|
||
|
|
$result = $service->saveTechSchema(self::TENANT_ID, 1, [['type' => 'check', 'label' => '']], 1);
|
||
|
|
|
||
|
|
$this->assertFalse($result['ok']);
|
||
|
|
$this->assertArrayHasKey('schema', $result['errors']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testSaveTechSchemaRejectsTooManyItems(): void
|
||
|
|
{
|
||
|
|
$repo = $this->createMock(SecurityCheckTemplateRepository::class);
|
||
|
|
$repo->method('findById')->willReturn(['id' => 1, 'version' => 1]);
|
||
|
|
|
||
|
|
$items = [];
|
||
|
|
for ($i = 0; $i <= SecurityCheckTemplateService::MAX_ITEMS; $i++) {
|
||
|
|
$items[] = ['type' => 'check', 'label' => 'Item ' . $i];
|
||
|
|
}
|
||
|
|
|
||
|
|
$service = new SecurityCheckTemplateService($repo);
|
||
|
|
$result = $service->saveTechSchema(self::TENANT_ID, 1, $items, 1);
|
||
|
|
|
||
|
|
$this->assertFalse($result['ok']);
|
||
|
|
$this->assertArrayHasKey('schema', $result['errors']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testUpdateMetaRejectsEmptyName(): void
|
||
|
|
{
|
||
|
|
$repo = $this->createMock(SecurityCheckTemplateRepository::class);
|
||
|
|
$repo->expects($this->never())->method('updateMeta');
|
||
|
|
$service = new SecurityCheckTemplateService($repo);
|
||
|
|
|
||
|
|
$result = $service->updateMeta(self::TENANT_ID, 1, '', true, 1);
|
||
|
|
|
||
|
|
$this->assertFalse($result['ok']);
|
||
|
|
$this->assertArrayHasKey('product_name', $result['errors']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testDecodeSchemaReturnsItems(): void
|
||
|
|
{
|
||
|
|
$repo = $this->createMock(SecurityCheckTemplateRepository::class);
|
||
|
|
$service = new SecurityCheckTemplateService($repo);
|
||
|
|
|
||
|
|
$decoded = $service->decodeSchema([
|
||
|
|
'version' => 5,
|
||
|
|
'tech_schema_json' => json_encode(['version' => 5, 'items' => [['type' => 'check', 'key' => 'a', 'label' => 'A']]]),
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->assertSame(5, $decoded['version']);
|
||
|
|
$this->assertCount(1, $decoded['items']);
|
||
|
|
}
|
||
|
|
}
|