Files
api/services/nginx/app/tests/Api/EdgeGatewayExpectedRelayStatesApiTest.php
T

172 lines
6.0 KiB
PHP

<?php
declare(strict_types=1);
usesApiSuite();
it('serves whole-department expected relay states and records successful physical completion only', function (): void {
$scenario = api_fixtures()->createSelfServeScenario([
'department' => [
'name' => 'Edge Expected State Department',
],
'relay_ids' => [
'entry' => 'expected-entry',
'exit' => 'expected-exit',
'machine' => 'expected-machine',
'program_picker' => 'expected-program',
'cleaner' => 'expected-cleaner',
],
]);
$departmentId = (int)$scenario['department']['id'];
$laneId = (int)$scenario['lane']['id'];
api_fixtures()->setDepartmentShellyTransportMode($departmentId, 'gateway');
$session = api_fixtures()->createEdgeOperatorSession($departmentId, [
'modules_selfserve_lane_relay_machine_status_set',
'modules_selfserve_lane_relay_machine_cleaner_status_set',
]);
$gateway = api_fixtures()->createClaimedEdgeGateway([
'department_id' => $departmentId,
'label' => 'Expected State Gateway',
]);
$relayIps = [
'expected-entry' => '10.41.0.11',
'expected-exit' => '10.41.0.12',
'expected-machine' => '10.41.0.13',
'expected-program' => '10.41.0.14',
'expected-cleaner' => '10.41.0.15',
];
foreach ($relayIps as $relayId => $ip) {
api_fixtures()->createEdgeRelayBinding([
'gateway_id' => (int)$gateway['id'],
'department_id' => $departmentId,
'relay_id' => $relayId,
'device_id' => 'device-' . $relayId,
'local_ip' => $ip,
'metadata' => [
'device_type' => 'SHELLY_SWITCH',
],
]);
}
$queueResponse = api_client()->post('/modules/self-serve/lane/hardware/batch/set', [
'lane_id' => $laneId,
'transport' => 'gateway',
'commands' => [
['target' => 'MACHINE', 'on' => true],
['target' => 'CLEANER', 'on' => false],
],
], $session['headers']);
$queueResponse
->assertStatus(202)
->assertEnvelope()
->assertSuccess();
$expectedResponse = api_client()->post('/edge-agent/gateways/' . (int)$gateway['id'] . '/expected-relay-states', [
'agent_token' => (string)$gateway['agent_token'],
'wait_seconds' => 0,
]);
$expectedResponse
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
$lanes = $expectedResponse->data()['lanes'] ?? [];
expect($lanes)->toHaveKey((string)$laneId);
$laneStates = $lanes[(string)$laneId];
expect(array_keys($laneStates))->toBe([
'ENTRANCE_GATE',
'EXIT_GATE',
'MACHINE',
'PROGRAM_PICKER',
'CLEANER',
])
->and($laneStates['MACHINE']['device'])->toBe([
'ip' => '10.41.0.13',
'id' => 'device-expected-machine',
'type' => 'SHELLY_SWITCH',
])
->and($laneStates['MACHINE']['state'])->toBeTrue()
->and($laneStates['MACHINE']['completed'])->toBeNull()
->and($laneStates['CLEANER']['state'])->toBeFalse()
->and($laneStates['CLEANER']['completed'])->toBeNull()
->and($laneStates['ENTRANCE_GATE']['completed'])->not->toBeNull();
expect($expectedResponse->data())->toHaveKey('CLEANER')
->and($expectedResponse->data()['MACHINE']['device'] ?? null)->toBe($laneStates['MACHINE']['device'])
->and($expectedResponse->data()['CLEANER']['completed'])->toBeNull();
$machineUpdated = (string)$laneStates['MACHINE']['updated'];
$cleanerUpdated = (string)$laneStates['CLEANER']['updated'];
$resultResponse = api_client()->post('/edge-agent/gateways/' . (int)$gateway['id'] . '/relay-state-results', [
'agent_token' => (string)$gateway['agent_token'],
'results' => [
[
'lane_id' => $laneId,
'role' => 'MACHINE',
'state' => true,
'updated' => $machineUpdated,
'ok' => true,
'completed' => '2026-07-01T09:10:00+00:00',
],
[
'lane_id' => $laneId,
'role' => 'CLEANER',
'state' => false,
'updated' => $cleanerUpdated,
'ok' => false,
'skipped' => true,
'error' => 'Relay offline',
],
],
]);
$resultResponse
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
expect($resultResponse->data()['summary'] ?? [])
->toHaveKey('completed', 1)
->toHaveKey('skipped', 1)
->toHaveKey('failed', 0);
$afterResult = api_client()->post('/edge-agent/gateways/' . (int)$gateway['id'] . '/expected-relay-states', [
'agent_token' => (string)$gateway['agent_token'],
'wait_seconds' => 0,
]);
$afterResult
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
$afterLaneStates = $afterResult->data()['lanes'][(string)$laneId] ?? [];
expect($afterLaneStates['MACHINE']['completed'] ?? null)->not->toBeNull()
->and($afterLaneStates['CLEANER']['completed'] ?? null)->toBeNull()
->and($afterLaneStates['CLEANER']['last_error'] ?? null)->toBe('Relay offline');
$staleResponse = api_client()->post('/edge-agent/gateways/' . (int)$gateway['id'] . '/relay-state-results', [
'agent_token' => (string)$gateway['agent_token'],
'results' => [[
'lane_id' => $laneId,
'role' => 'CLEANER',
'state' => false,
'updated' => '2000-01-01 00:00:00',
'ok' => true,
'completed' => '2026-07-01T09:11:00+00:00',
]],
]);
$staleResponse
->assertStatus(200)
->assertEnvelope()
->assertSuccess();
expect($staleResponse->data()['summary']['stale'] ?? null)->toBe(1)
->and($staleResponse->data()['rejected'][0]['reason'] ?? null)->toBe('STALE_STATE');
});