180 lines
8.9 KiB
PHP
180 lines
8.9 KiB
PHP
<?php
|
|
|
|
app_require('classes/edge_gateway_manager.php');
|
|
app_require('modules/edgegateway/config/edgegateway_public_broker_url_c.php');
|
|
|
|
use classes\edge_gateway_manager;
|
|
use modules\edgegateway\config\edgegateway_public_broker_url_c;
|
|
|
|
class EdgeGatewayManagerUrlHarness extends edge_gateway_manager
|
|
{
|
|
public function __construct()
|
|
{
|
|
}
|
|
}
|
|
|
|
function with_edge_gateway_server_state(array $server, callable $callback): void
|
|
{
|
|
$originalServer = $_SERVER;
|
|
$originalPublicApiUrl = getenv('EDGE_PUBLIC_API_URL');
|
|
$originalPublicBrokerUrl = getenv('EDGE_PUBLIC_BROKER_URL');
|
|
$publicBrokerConfig = null;
|
|
$originalPublicBrokerConfig = null;
|
|
|
|
$_SERVER = $server;
|
|
putenv('EDGE_PUBLIC_BROKER_URL');
|
|
try {
|
|
$publicBrokerConfig = new edgegateway_public_broker_url_c();
|
|
$originalPublicBrokerConfig = $publicBrokerConfig->getVariableValue();
|
|
$publicBrokerConfig->setVariableValue('');
|
|
} catch (Throwable) {
|
|
$publicBrokerConfig = null;
|
|
}
|
|
|
|
try {
|
|
$callback();
|
|
} finally {
|
|
$_SERVER = $originalServer;
|
|
if ($originalPublicApiUrl === false) {
|
|
putenv('EDGE_PUBLIC_API_URL');
|
|
} else {
|
|
putenv('EDGE_PUBLIC_API_URL=' . $originalPublicApiUrl);
|
|
}
|
|
if ($originalPublicBrokerUrl === false) {
|
|
putenv('EDGE_PUBLIC_BROKER_URL');
|
|
} else {
|
|
putenv('EDGE_PUBLIC_BROKER_URL=' . $originalPublicBrokerUrl);
|
|
}
|
|
if ($publicBrokerConfig !== null && $originalPublicBrokerConfig !== null) {
|
|
try {
|
|
$publicBrokerConfig->setVariableValue($originalPublicBrokerConfig);
|
|
} catch (Throwable) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function invoke_edge_gateway_private(object $instance, string $method, mixed ...$arguments): mixed
|
|
{
|
|
$reflection = new ReflectionMethod($instance, $method);
|
|
$reflection->setAccessible(true);
|
|
return $reflection->invokeArgs($instance, $arguments);
|
|
}
|
|
|
|
it('builds install script urls with the compose edge gateway artifacts and forwarded https scheme', function (): void {
|
|
with_edge_gateway_server_state([
|
|
'HTTP_HOST' => 'api.truckwash.io:4433',
|
|
'HTTP_X_FORWARDED_PROTO' => 'https',
|
|
], function (): void {
|
|
$manager = new EdgeGatewayManagerUrlHarness();
|
|
$script = $manager->buildInstallScript('abc123');
|
|
|
|
expect($manager->getApiBaseUrl())->toBe('https://api.truckwash.io:4433');
|
|
expect($manager->buildInstallTokenVerifyUrl('abc123'))->toBe('https://api.truckwash.io:4433/edge-agent/install-token/verify?token=abc123');
|
|
expect($manager->buildInstallScriptUrl('abc123'))->toBe('https://api.truckwash.io:4433/edge-agent/install.sh?token=abc123');
|
|
expect($manager->buildInstallCommand('abc123'))->toContain("https://api.truckwash.io:4433/edge-agent/install.sh?token=abc123");
|
|
expect($script)->toContain('fetch_http "Verify install token" "https://api.truckwash.io:4433/edge-agent/install-token/verify?token=abc123"');
|
|
expect($script)->toContain('INSTALL_STATUS_URL="https://api.truckwash.io:4433/edge-agent/install-token/status"');
|
|
expect($script)->toContain('fetch_http "Download PHP edge agent" "https://api.truckwash.io:4433/edge-agent/artifacts/agent.php" "$INSTALL_DIR/agent.php"');
|
|
expect($script)->toContain('fetch_http "Download LAN worker" "https://api.truckwash.io:4433/edge-agent/artifacts/lan-worker.php" "$INSTALL_DIR/lan-worker.php"');
|
|
expect($script)->toContain('fetch_http "Download compose stack" "https://api.truckwash.io:4433/edge-agent/artifacts/docker-compose.gateway.yml" "$INSTALL_DIR/docker-compose.gateway.yml"');
|
|
expect($script)->toContain('fetch_http "Download compose stack service unit" "https://api.truckwash.io:4433/edge-agent/artifacts/truckwash-edge-gateway-stack.service" "$INSTALL_DIR/truckwash-edge-gateway-stack.service"');
|
|
expect($script)->toContain('report_install_status() {');
|
|
expect($script)->toContain('begin_install_phase "VERIFY_TOKEN" "Verifying install token"');
|
|
expect($script)->toContain('begin_install_phase "WAIT_FOR_CLAIM" "Waiting for gateway heartbeat and claim"');
|
|
expect($script)->toContain('report_install_status "FAILED" "FAILED" "$failure_message" "$diagnostics_json" "$gateway_id"');
|
|
expect($script)->toContain('report_install_status "CLAIMED" "CLAIMED"');
|
|
expect($script)->toContain('Installer failed during step ${CURRENT_STEP_CODE:-FAILED}: ${CURRENT_STEP:-unknown}');
|
|
expect($script)->toContain('Last request: ${CURRENT_METHOD} ${CURRENT_URL}');
|
|
expect($script)->toContain('Response body preview (first 400 bytes):');
|
|
expect($script)->toContain('wait_for_gateway_claim "$CONFIG_PATH" "$HEARTBEAT_MARKER_PATH" "$INSTALL_STARTED_AT" 180');
|
|
expect($script)->toContain('wait_for_post_restart_heartbeat "$HEARTBEAT_MARKER_PATH" "$INSTALL_STARTED_AT" 180');
|
|
expect($script)->toContain('"apiUrl":"https://api.truckwash.io:4433"');
|
|
expect($script)->toContain('"serviceName":"truckwash-edge-agent.service"');
|
|
expect($script)->toContain('"stackServiceName":"truckwash-edge-gateway-stack.service"');
|
|
expect($script)->toContain('"composeFileName":"docker-compose.gateway.yml"');
|
|
expect($script)->toContain('"stateDatabasePath":"/opt/truckwash-edge-agent/runtime/gateway-state.sqlite"');
|
|
expect($script)->toContain('"operationPollTimeoutSeconds":20');
|
|
expect($script)->toContain('"brokerUrl":"https://api.truckwash.io:4433/edge-broker"');
|
|
expect($script)->not->toContain('"shellActionPollTimeoutSeconds"');
|
|
});
|
|
});
|
|
|
|
it('appends forwarded ports when the forwarded host omits them', function (): void {
|
|
with_edge_gateway_server_state([
|
|
'HTTP_X_FORWARDED_PROTO' => 'https',
|
|
'HTTP_X_FORWARDED_HOST' => 'api.truckwash.io',
|
|
'HTTP_X_FORWARDED_PORT' => '4433',
|
|
], function (): void {
|
|
$manager = new EdgeGatewayManagerUrlHarness();
|
|
|
|
expect($manager->getApiBaseUrl())->toBe('https://api.truckwash.io:4433');
|
|
});
|
|
});
|
|
|
|
it('prefers EDGE_PUBLIC_API_URL when explicitly configured', function (): void {
|
|
with_edge_gateway_server_state([
|
|
'HTTP_HOST' => 'localhost',
|
|
'HTTP_X_FORWARDED_PROTO' => 'http',
|
|
'HTTP_X_FORWARDED_PREFIX' => '/api',
|
|
], function (): void {
|
|
putenv('EDGE_PUBLIC_API_URL=https://edge.example.test/api');
|
|
|
|
$manager = new EdgeGatewayManagerUrlHarness();
|
|
$script = $manager->buildInstallScript('token-1');
|
|
|
|
expect($manager->getApiBaseUrl())->toBe('https://edge.example.test/api');
|
|
expect($manager->buildInstallScriptUrl('token-1'))->toBe('https://edge.example.test/api/edge-agent/install.sh?token=token-1');
|
|
expect($script)->toContain('"apiUrl":"https://edge.example.test/api"');
|
|
expect($script)->toContain('"brokerUrl":"https://edge.example.test/api/edge-broker"');
|
|
});
|
|
});
|
|
|
|
it('builds websocket broker urls on the traefik broker path', function (): void {
|
|
with_edge_gateway_server_state([
|
|
'HTTP_HOST' => 'api.truckwash.io:4433',
|
|
'HTTP_X_FORWARDED_PROTO' => 'https',
|
|
], function (): void {
|
|
$manager = new EdgeGatewayManagerUrlHarness();
|
|
|
|
expect(invoke_edge_gateway_private($manager, 'buildBrokerPublicUrl'))
|
|
->toBe('https://api.truckwash.io:4433/edge-broker');
|
|
expect(invoke_edge_gateway_private($manager, 'buildBrokerPublicWebSocketUrl', '/ws/browser-shell'))
|
|
->toBe('wss://api.truckwash.io:4433/edge-broker/ws/browser-shell');
|
|
});
|
|
});
|
|
|
|
it('builds localhost websocket broker urls on the local traefik api prefix', function (): void {
|
|
with_edge_gateway_server_state([
|
|
'HTTP_HOST' => 'localhost',
|
|
'HTTP_X_FORWARDED_PROTO' => 'http',
|
|
'HTTP_X_FORWARDED_PREFIX' => '/api',
|
|
], function (): void {
|
|
$manager = new EdgeGatewayManagerUrlHarness();
|
|
|
|
expect($manager->getApiBaseUrl())
|
|
->toBe('http://localhost/api');
|
|
expect(invoke_edge_gateway_private($manager, 'buildBrokerPublicUrl'))
|
|
->toBe('http://localhost/api/edge-broker');
|
|
expect(invoke_edge_gateway_private($manager, 'buildBrokerPublicWebSocketUrl', '/ws/browser-gateway-stream'))
|
|
->toBe('ws://localhost/api/edge-broker/ws/browser-gateway-stream');
|
|
expect(invoke_edge_gateway_private($manager, 'buildBrokerPublicWebSocketUrl', '/ws/browser-shell'))
|
|
->toBe('ws://localhost/api/edge-broker/ws/browser-shell');
|
|
});
|
|
});
|
|
|
|
it('keeps root-host api urls unprefixed when the request is not under the local api alias', function (): void {
|
|
with_edge_gateway_server_state([
|
|
'HTTP_HOST' => 'localhost',
|
|
'HTTP_X_FORWARDED_PROTO' => 'http',
|
|
'REQUEST_URI' => '/edge-gateways/84/stream-session',
|
|
], function (): void {
|
|
$manager = new EdgeGatewayManagerUrlHarness();
|
|
|
|
expect($manager->getApiBaseUrl())
|
|
->toBe('http://localhost');
|
|
expect(invoke_edge_gateway_private($manager, 'buildBrokerPublicUrl'))
|
|
->toBe('http://localhost/edge-broker');
|
|
});
|
|
});
|