Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/Settings/register.d/publication-field-rules.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@
}
},
"catalogService": {
"version": "0.2.2",
"version": "0.2.3",
"properties": {
"contactPerson": {
"authorization": {
Expand Down Expand Up @@ -477,7 +477,7 @@
}
},
"organization": {
"version": "0.5.3",
"version": "0.5.4",
"properties": {
"contactsUid": {
"authorization": {
Expand Down
4 changes: 2 additions & 2 deletions lib/Settings/register.d/topdesk-cmdb-import.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"components": {
"schemas": {
"module": {
"version": "0.3.8",
"version": "0.3.9",
"properties": {
"externalId": {
"type": "string",
Expand Down Expand Up @@ -72,7 +72,7 @@
}
},
"usage": {
"version": "1.5.6",
"version": "1.5.7",
"configuration": {
"x-openregister-lifecycle": {
"transitions": {
Expand Down
447 changes: 12 additions & 435 deletions lib/Settings/softwarecatalogus_register.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion tests/Integration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ composer install --dev

This installs:
- PHPUnit 10.5+ for test execution
- Guzzle HTTP Client 7.8+ for API requests
- Guzzle HTTP Client 8.2+ for API requests

## Running Tests

Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Settings/PublicationFieldRulesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public function testAFragmentNeverLowersAVersion(): void {
$this->assertSame('1.5.5', $merged['components']['schemas']['usage']['version']);

$schemas = $this->register()['components']['schemas'];
$this->assertSame('1.5.6', $schemas['usage']['version'], 'topdesk-cmdb-import.json bumps it past publication-field-rules.json; value-assessment.json, sorting last, does not lower it');
$this->assertSame('1.5.7', $schemas['usage']['version'], 'topdesk-cmdb-import.json bumps it past publication-field-rules.json; value-assessment.json, sorting last, does not lower it');
$this->assertSame('0.3.5', $schemas['connection']['version']);
$this->assertSame('0.1.6', $schemas['moduleVersion']['version']);
}//end testAFragmentNeverLowersAVersion()
Expand Down
90 changes: 90 additions & 0 deletions tests/Unit/Settings/RegisterNullKeywordsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

/**
* Guard: no register schema may carry a null JSON-Schema validation keyword.
*
* OpenRegister's validator (opis/json-schema) rejects a null where a keyword
* wants a number ("minimum must contain a valid number"), so a schema with
* hardValidation refuses every object. The register file once carried
* `"minimum": null` and similar on ~420 properties and the E2E seed failed.
*
* @category Tests
* @package OCA\Stackiq\Tests\Unit\Settings
* @author Conduction b.v. <info@conduction.nl>
* @copyright 2026 Conduction B.V.
* @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
* @link https://github.com/ConductionNL/stackiq
*/

declare(strict_types=1);

namespace OCA\Stackiq\Tests\Unit\Settings;

use PHPUnit\Framework\TestCase;

/**
* Scans the register file and its register.d fragments for null keywords.
*/
class RegisterNullKeywordsTest extends TestCase {
private const KEYWORDS = [
'minimum',
'maximum',
'exclusiveMinimum',
'exclusiveMaximum',
'multipleOf',
'minLength',
'maxLength',
'minItems',
'maxItems',
'minProperties',
'maxProperties',
];

/**
* Collect the paths of null validation keywords below a node.
*
* @param mixed $node The decoded JSON node.
* @param string $path The path to the node.
*
* @return array<int,string> The offending paths.
*/
private function findNullKeywords(mixed $node, string $path): array {
$found = [];
if (is_array($node) === false) {
return $found;
}

foreach ($node as $key => $value) {
$child = $path.'/'.$key;
if ($value === null && in_array($key, self::KEYWORDS, true) === true) {
$found[] = $child;
continue;
}

$found = array_merge($found, $this->findNullKeywords($value, $child));
}

return $found;
}//end findNullKeywords()

/**
* No schema in the register or its fragments carries a null keyword.
*
* @return void
*/
public function testNoSchemaCarriesNullValidationKeywords(): void {
$dir = __DIR__.'/../../../lib/Settings';
$files = array_merge([$dir.'/softwarecatalogus_register.json'], glob($dir.'/register.d/*.json') ?: []);

$found = [];
foreach ($files as $file) {
$this->assertFileExists($file);
$decoded = json_decode((string)file_get_contents($file), true);
$this->assertIsArray($decoded, basename($file).' must be valid JSON');
$schemas = $decoded['components']['schemas'] ?? [];
$found = array_merge($found, $this->findNullKeywords($schemas, basename($file)));
}

$this->assertSame([], array_slice($found, 0, 10), 'Null validation keywords make OpenRegister refuse the schema (showing first 10)');
}//end testNoSchemaCarriesNullValidationKeywords()
}//end class
10 changes: 5 additions & 5 deletions tests/Unit/Settings/TopdeskCmdbFragmentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ private function mergedRegister(): array {
}//end mergedRegister()

/**
* The merged module is 0.3.8, carries the six optional, titled properties and allows BBN2+.
* The merged module is 0.3.9, carries the six optional, titled properties and allows BBN2+.
*
* @return void
*/
public function testTheMergedModuleIsVersion038WithTheExternalIds(): void {
public function testTheMergedModuleIsVersion039WithTheExternalIds(): void {
$module = $this->mergedRegister()['components']['schemas']['module'];

$this->assertSame('0.3.8', $module['version'], 'a fragment sorting after topdesk-cmdb-import.json overwrote the bump');
$this->assertSame('0.3.9', $module['version'], 'a fragment sorting after topdesk-cmdb-import.json overwrote the bump');
Comment thread
WilcoLouwerse marked this conversation as resolved.
foreach (self::PROPERTIES as $property) {
$this->assertArrayHasKey($property, $module['properties']);
$this->assertNotEmpty($module['properties'][$property]['title'] ?? '', $property);
Expand All @@ -91,7 +91,7 @@ public function testTheMergedModuleIsVersion038WithTheExternalIds(): void {
$this->assertSame(['BBN1', 'BBN2', 'BBN3', 'BBN2+'], $module['properties']['bbnLevel']['enum'], 'the fragment adds BBN2+ to the BIO levels');
$this->assertArrayHasKey('roadmapStatement', $module['properties'], 'the 0.3.4 fragment still applies');
$this->assertSame(['name'], $module['required']);
}//end testTheMergedModuleIsVersion038WithTheExternalIds()
}//end testTheMergedModuleIsVersion039WithTheExternalIds()

/**
* A CMDB import sets the usage status TOPdesk records from any state; only an administrator may.
Expand All @@ -104,7 +104,7 @@ public function testTheMergedModuleIsVersion038WithTheExternalIds(): void {
*/
public function testAnAdministratorMayMoveAUsageToAnyStateTheSourceRecords(): void {
$usage = $this->mergedRegister()['components']['schemas']['usage'];
$this->assertSame('1.5.6', $usage['version'], 'a lifecycle-only edit deploys only with a version bump');
$this->assertSame('1.5.7', $usage['version'], 'a lifecycle-only edit deploys only with a version bump');

$lifecycle = $usage['configuration']['x-openregister-lifecycle'];
$states = $usage['properties']['status']['enum'];
Expand Down
Loading