Files
api/services/nginx/app/tests/Unit/Selfserve/SelfserveOpenApiSpecTest.php
T
Jeppe Bundgaard 8bf957b273 Add support for selfserve_enabled lanes and synchronize behavior across tasks, sessions, and projections
- Introduced `selfserve_enabled` property for `department_lanes` with schema update, object properties, and associated methods/tests.
- Enhanced `selfserve_wash_flow` and session logic to respect lane self-serve settings, including block handling and task filtering.
- Updated API routes and Studio Graph projections to include `selfserve_enabled` in payloads and progress callbacks.
- Added unit tests for session statuses, lane configuration, and blocking behavior due to disabled self-serve settings.
2026-04-29 17:28:42 +02:00

142 lines
7.1 KiB
PHP

<?php
function selfserve_openapi_content_or_skip(): string
{
$candidates = [
dirname(__DIR__, 6) . DIRECTORY_SEPARATOR . 'openapi.yaml',
dirname(__DIR__, 5) . DIRECTORY_SEPARATOR . 'openapi.yaml',
dirname(__DIR__, 4) . DIRECTORY_SEPARATOR . 'openapi.yaml',
dirname(__DIR__, 3) . DIRECTORY_SEPARATOR . 'openapi.yaml',
dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'openapi.yaml',
];
foreach ($candidates as $candidate) {
if (!is_file($candidate)) {
continue;
}
$content = file_get_contents($candidate);
if ($content !== false) {
return $content;
}
}
test()->markTestSkipped('openapi.yaml is not available in this runtime environment.');
}
function selfserve_openapi_path_block_or_fail(string $content, string $path): string
{
$path_marker = ' ' . $path . ':';
$start = strpos($content, $path_marker);
if ($start === false) {
throw new RuntimeException("OpenAPI path block not found: {$path}");
}
$rest = substr($content, $start + strlen($path_marker));
$next_path = strpos($rest, "\n /");
if ($next_path === false) {
return substr($content, $start);
}
return substr($content, $start, strlen($path_marker) + $next_path);
}
it('documents self-serve machine type, eligibility, summary, and webhook endpoints', function (): void {
$content = selfserve_openapi_content_or_skip();
$allowedPathBlock = selfserve_openapi_path_block_or_fail($content, '/department/selfserve/vehicle/allowed');
$summaryPathBlock = selfserve_openapi_path_block_or_fail($content, '/department/selfserve/washes/summary');
expect($content)->toContain('/department/selfserve/machine-types:');
expect($content)->toContain('/department/selfserve/vehicle/allowed:');
expect($content)->toContain('/department/selfserve/washes/summary:');
expect($content)->toContain('/relay/button/press/post:');
expect($content)->toContain('/relay/machine/on/post:');
expect($content)->toContain('/modules/self-serve/lane/wash/in-progress:');
expect($content)->toContain('/modules/self-serve/lane/relay/machine/status:');
expect($content)->toContain('/modules/self-serve/lane/relay/machine/set:');
expect($content)->toContain('/modules/self-serve/lane/gate/open:');
expect($content)->toContain('/modules/self-serve/lane/relay/machine_program_picker/status:');
expect($content)->toContain('/modules/self-serve/lane/relay/machine_program_picker/set:');
expect($content)->toContain('/modules/self-serve/lane/relay/machine_cleaner/status:');
expect($content)->toContain('/modules/self-serve/lane/relay/machine_cleaner/set:');
expect($allowedPathBlock)->toContain('name: vehicle_type_id');
expect($allowedPathBlock)->toContain('name: vehicle_type');
expect($allowedPathBlock)->toContain('may evaluate any registration plate');
expect($allowedPathBlock)->toContain('Persisted self-serve answers are only applied');
expect($summaryPathBlock)->toContain('name: vehicle_type_id');
expect($summaryPathBlock)->toContain('name: vehicle_type');
});
it('documents the all-in-one self-serve studio replacement API', function (): void {
$content = selfserve_openapi_content_or_skip();
expect($content)->toContain('/department/selfserve/studio/graph:');
expect($content)->toContain('/department/selfserve/studio/layout:');
expect($content)->toContain('/department/selfserve/studio/validate:');
expect($content)->toContain('/department/selfserve/studio/simulate:');
expect($content)->toContain('/department/selfserve/studio/path-outcomes:');
expect($content)->toContain('/department/selfserve/studio/path-outcomes/stream:');
expect($content)->toContain('/department/selfserve/studio/publish:');
expect($content)->toContain('/department/selfserve/studio/rollback:');
expect($content)->toContain('/department/selfserve/studio/gateway-action:');
expect($content)->toContain('SelfserveStudioGraph:');
expect($content)->toContain('SelfserveStudioGraphSaveRequest:');
expect($content)->toContain('SelfserveStudioLayout:');
expect($content)->toContain('SelfserveStudioPathOutcomesRequest:');
expect($content)->toContain('SelfserveStudioPathOutcomesResponse:');
expect($content)->toContain('SelfserveStudioPathResult:');
expect($content)->toContain('SelfserveStudioPathProgress:');
expect($content)->toContain('projectSelfserveStudioPathOutcomes');
expect($content)->toContain('streamSelfserveStudioPathOutcomes');
expect($content)->toContain('runSelfserveStudioGatewayAction');
});
it('defines reusable self-serve wash and machine type schemas', function (): void {
$content = selfserve_openapi_content_or_skip();
expect($content)->toContain('SelfserveMachineType:');
expect($content)->toContain('SelfserveVehicleAllowedResponse:');
expect($content)->toContain('SelfserveWashSummary:');
expect($content)->toContain('MachineButtonPressWebhookResponse:');
expect($content)->toContain('DepartmentSelfserveVehicleConditionMutationResponse:');
expect($content)->toContain('DepartmentLane:');
expect($content)->toContain('selfserve_enabled:');
expect($content)->toContain('blocked_reason:');
expect($content)->toContain('machine_type_id:');
expect($content)->toContain('SelfServeLaneMachineRelayStatus:');
expect($content)->toContain(' wash_started_at:');
});
it('documents in-progress self-serve wash start and machine relay fields', function (): void {
$content = selfserve_openapi_content_or_skip();
$inProgressPathBlock = selfserve_openapi_path_block_or_fail($content, '/modules/self-serve/lane/wash/in-progress');
expect($inProgressPathBlock)->toContain('included_minutes:');
expect($inProgressPathBlock)->toContain('machine_relay_enabled:');
expect($inProgressPathBlock)->toContain('machine_relay_enabled_at:');
expect($inProgressPathBlock)->toContain('machine_start_triggered_at:');
expect($inProgressPathBlock)->toContain('wash_started_at:');
});
it('documents self-serve machine wash included minutes in config schemas', function (): void {
$content = selfserve_openapi_content_or_skip();
expect($content)->toContain('SelfServeConfigEntry:');
expect($content)->toContain('machine_wash_minutes_included');
expect($content)->toContain('SelfServeConfig:');
});
it('documents property gate lane commands and sanitized gate failure responses', function (): void {
$content = selfserve_openapi_content_or_skip();
$commandPathBlock = selfserve_openapi_path_block_or_fail($content, '/modules/self-serve/lane/command');
$gateOpenPathBlock = selfserve_openapi_path_block_or_fail($content, '/modules/self-serve/lane/gate/open');
expect($commandPathBlock)->toContain('OPEN_PROPERTY_ACCESS_GATE');
expect($commandPathBlock)->toContain('OPEN_PROPERTY_EXIT_GATE');
expect($commandPathBlock)->toContain('Command execution failed');
expect($commandPathBlock)->toContain('Failed to execute command: Failed to open property access gate.');
expect($gateOpenPathBlock)->toContain('Gate open failed');
expect($gateOpenPathBlock)->toContain('Failed to open entrance gate.');
});