Add Edge Gateway tests for unit, API, and integration scenarios

This commit is contained in:
Jeppe Bundgaard
2026-04-23 15:48:51 +02:00
parent c38a4379bd
commit b9ddc585db
23 changed files with 3579 additions and 117 deletions
@@ -3959,11 +3959,19 @@ BASH;
$channelStatus = self::deriveChannelStatus($gateway, $effectiveStatus, $now);
$relayHealth = self::buildRelayHealth($gateway, $effectiveStatus, $now);
$fallbackSummary = self::buildFallbackSummary($relayHealth);
$gateway['outbox_status'] = self::buildOutboxStatusSummary($gateway, $now);
$lastSyncAt = self::resolveLastSyncAt($gateway);
$gateway['channel_status'] = $channelStatus;
$gateway['relay_health'] = $relayHealth;
$gateway['fallback_summary'] = $fallbackSummary;
$gateway['transport_health'] = self::deriveTransportHealth($effectiveStatus, $channelStatus, $fallbackSummary);
$gateway['transport_health'] = self::deriveTransportHealth(
$gateway,
$effectiveStatus,
$channelStatus,
$fallbackSummary,
$lastSyncAt
);
$gateway['last_successful_command_at'] = $gateway['operational_snapshot']['last_successful_command_at']
?? self::findLatestCompletionTimestamp((array)($gateway['recent_commands'] ?? []), null);
$gateway['last_successful_discovery_at'] = $gateway['operational_snapshot']['last_successful_discovery_at']
@@ -3976,8 +3984,7 @@ BASH;
$gateway['version_drift'] = self::buildVersionDriftSummary($gateway);
$gateway['credential_freshness'] = self::buildCredentialFreshnessSummary($gateway, $now);
$gateway['container_health'] = self::buildContainerHealthSummary($gateway, $effectiveStatus);
$gateway['outbox_status'] = self::buildOutboxStatusSummary($gateway, $now);
$gateway['last_sync_at'] = self::resolveLastSyncAt($gateway);
$gateway['last_sync_at'] = $lastSyncAt;
$gateway['update_window'] = self::buildUpdateWindowSummary($gateway);
$gateway['staged_version'] = self::buildStagedVersionSummary($gateway);
$gateway['rollback_status'] = self::buildRollbackStatusSummary($gateway);
@@ -4150,8 +4157,18 @@ BASH;
return $summary;
}
private static function deriveTransportHealth(string $effectiveStatus, array $channelStatus, array $fallbackSummary): array
private static function deriveTransportHealth(
array $gateway,
string $effectiveStatus,
array $channelStatus,
array $fallbackSummary,
?string $lastSyncAt
): array
{
$metadata = isset($gateway['metadata']) && is_array($gateway['metadata']) ? (array)$gateway['metadata'] : [];
$controlPlaneStatus = isset($metadata['control_plane_status']) && is_array($metadata['control_plane_status'])
? (array)$metadata['control_plane_status']
: [];
$brokerState = (string)($channelStatus['broker']['state'] ?? self::STATUS_OFFLINE);
$affectedRelayCount = count((array)($fallbackSummary['affected_relays'] ?? []));
$transportState = $effectiveStatus;
@@ -4169,6 +4186,13 @@ BASH;
? 'Broker fast path er aktiv med API polling som fallback'
: 'API polling er aktiv som primær kontrolkanal'),
'recommended_action' => $fallbackSummary['recommended_action'] ?? ($channelStatus['broker']['last_error'] ?? null),
'last_successful_sync_at' => $lastSyncAt,
'last_transport_failure_at' => isset($controlPlaneStatus['last_transport_failure_at'])
? (string)$controlPlaneStatus['last_transport_failure_at']
: null,
'last_transport_error' => isset($controlPlaneStatus['last_transport_error'])
? (string)$controlPlaneStatus['last_transport_error']
: null,
];
}
@@ -4320,17 +4344,23 @@ BASH;
private static function resolveLastSyncAt(array $gateway): ?string
{
$metadata = isset($gateway['metadata']) && is_array($gateway['metadata']) ? (array)$gateway['metadata'] : [];
if (!empty($metadata['last_sync_at'])) {
return (string)$metadata['last_sync_at'];
}
$controlPlaneStatus = isset($metadata['control_plane_status']) && is_array($metadata['control_plane_status'])
? (array)$metadata['control_plane_status']
: [];
$outbox = isset($gateway['outbox_status']) && is_array($gateway['outbox_status'])
? (array)$gateway['outbox_status']
: [];
$outboxMetadata = isset($metadata['outbox_status']) && is_array($metadata['outbox_status'])
? (array)$metadata['outbox_status']
: [];
return isset($outbox['last_replayed_at']) && $outbox['last_replayed_at'] !== null
? (string)$outbox['last_replayed_at']
: null;
return self::latestTimestamp([
$controlPlaneStatus['last_successful_sync_at'] ?? null,
$metadata['last_sync_at'] ?? null,
$outbox['last_replayed_at'] ?? null,
$outboxMetadata['last_replayed_at'] ?? null,
$gateway['last_heartbeat_at'] ?? null,
]);
}
private static function buildUpdateWindowSummary(array $gateway): array
@@ -4551,6 +4581,33 @@ BASH;
return null;
}
/**
* @param array<int,mixed> $timestamps
*/
private static function latestTimestamp(array $timestamps): ?string
{
$latestValue = null;
$latestEpoch = 0;
foreach ($timestamps as $timestamp) {
if (!is_string($timestamp) || trim($timestamp) === '') {
continue;
}
$epoch = strtotime($timestamp);
if ($epoch === false) {
continue;
}
if ($latestValue === null || $epoch >= $latestEpoch) {
$latestValue = $timestamp;
$latestEpoch = $epoch;
}
}
return $latestValue;
}
private static function normalizeFallbackMode(?string $fallbackMode): string
{
$normalized = strtoupper(trim((string)$fallbackMode));