Skip to content
Merged
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
13 changes: 7 additions & 6 deletions test/e2e/fixtures/compatible-anthropic-switch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ function readOwnedGatewayStateFile(filePath: string, currentUid: number): string
}
}

function managedOpenShellGatewayPid(): number | null {
const stateDirectory = resolveDockerDriverGatewayStateDir(process.env, os.homedir());
function managedOpenShellGatewayPid(homeDir: string): number | null {
const stateDirectory = resolveDockerDriverGatewayStateDir(process.env, homeDir);
const pidPath = path.join(stateDirectory, "openshell-gateway.pid");
const markerPath = path.join(stateDirectory, "runtime.json");
const pidPathExists = pathExists(pidPath);
Expand Down Expand Up @@ -186,8 +186,8 @@ function managedOpenShellGatewayPid(): number | null {
return pid;
}

async function activeOpenShellGatewayPid(host: HostCliClient): Promise<number> {
const managedPid = managedOpenShellGatewayPid();
async function activeOpenShellGatewayPid(host: HostCliClient, homeDir: string): Promise<number> {
const managedPid = managedOpenShellGatewayPid(homeDir);
if (managedPid !== null) return managedPid;
for (const serviceName of GATEWAY_SERVICE_NAMES) {
const result = await host.command(
Expand Down Expand Up @@ -219,11 +219,12 @@ async function activeOpenShellGatewayPid(host: HostCliClient): Promise<number> {
export async function installGatewayHostVerificationAlias(
host: HostCliClient,
cleanup: { add(name: string, run: () => Promise<void> | void): void },
homeDir: string = os.homedir(),
): Promise<void> {
const gatewayPid = await activeOpenShellGatewayPid(host);
const gatewayPid = await activeOpenShellGatewayPid(host, homeDir);
const ownerToken = randomBytes(16).toString("hex");
const fixtureDirectory = fs.mkdtempSync(
path.join(os.homedir(), ".nemoclaw-gateway-resolver-"),
path.join(homeDir, ".nemoclaw-gateway-resolver-"),
);
const resolverSource = path.join(fixtureDirectory, "hosts");
const ownedLine = `127.0.0.1 ${OPENSHELL_HOST_ALIAS} # nemoclaw-gateway-host-verifier:${ownerToken}`;
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/live/openclaw-inference-switch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1093,7 +1093,7 @@ test("openclaw-inference-switch: switches route and preserves live OpenClaw beha

if (SWITCH_PROVIDER === "compatible-anthropic-endpoint" && SWITCH_MOCK_ANTHROPIC === "1") {
mockProvider = await startMockAnthropicProvider();
await installGatewayHostVerificationAlias(host, cleanup);
await installGatewayHostVerificationAlias(host, cleanup, home);
await artifacts.writeJson("mock-anthropic-provider.json", {
endpointUrl: mockProvider.endpointUrl,
});
Expand Down
49 changes: 37 additions & 12 deletions test/e2e/support/compatible-anthropic-switch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ const INVALID_MANAGED_GATEWAY_STATE_CASES = [
},
] as const;

function mockGatewayProcess(pid: number, gatewayBin: string): void {
const statSync = fs.statSync;
vi.spyOn(fs, "statSync").mockImplementation(((target) =>
String(target) === `/proc/${pid}`
? ({ uid: process.getuid?.() ?? 0 } as fs.Stats)
: statSync(target)) as typeof fs.statSync);
const realpathSync = fs.realpathSync;
const gatewayExecutablePaths = new Set([`/proc/${pid}/exe`, gatewayBin]);
vi.spyOn(fs, "realpathSync").mockImplementation(((target) =>
gatewayExecutablePaths.has(String(target))
? gatewayBin
: realpathSync(target)) as typeof fs.realpathSync);
}

describe("compatible Anthropic inference switch setup", () => {
afterEach(() => {
vi.unstubAllEnvs();
Expand Down Expand Up @@ -99,29 +113,36 @@ describe("compatible Anthropic inference switch setup", () => {
expect(rewrite).not.toHaveBeenCalled();
});

it("uses the managed Docker-driver gateway before the user service (#9166)", async () => {
const stateDirectory = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-managed-gateway-test-"));
it("uses managed Docker-driver gateway state from the target home before the user service (#9166)", async () => {
const home = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-target-home-gateway-test-"));
const stateDirectory = path.join(
home,
".local",
"state",
"nemoclaw",
"openshell-docker-gateway",
);
const pid = process.pid;
const gatewayBin = "/usr/bin/openshell-gateway";
vi.stubEnv("NEMOCLAW_OPENSHELL_GATEWAY_STATE_DIR", stateDirectory);
fs.mkdirSync(stateDirectory, { recursive: true });
vi.stubEnv("NEMOCLAW_OPENSHELL_GATEWAY_STATE_DIR", "");
writeDockerDriverGatewayPidFile(path.join(stateDirectory, "openshell-gateway.pid"), pid);
writeDockerDriverGatewayRuntimeMarkerForStateDir(stateDirectory, {
desiredEnv: {},
endpoint: "https://127.0.0.1:8080",
gatewayBin,
pid,
});
const realpathSync = fs.realpathSync;
const gatewayExecutablePaths = new Set([`/proc/${pid}/exe`, gatewayBin]);
vi.spyOn(fs, "realpathSync").mockImplementation(
((target) =>
gatewayExecutablePaths.has(String(target)) ? gatewayBin : realpathSync(target)) as typeof fs.realpathSync,
);
mockGatewayProcess(pid, gatewayBin);
const command = vi.fn().mockResolvedValue({ exitCode: 0, stderr: "", stdout: "" });
const add = vi.fn();

try {
await installGatewayHostVerificationAlias({ command } as unknown as HostCliClient, { add });
await installGatewayHostVerificationAlias(
{ command } as unknown as HostCliClient,
{ add },
home,
);
const cleanupMount = add.mock.calls[0]?.[1] as () => Promise<void>;
await cleanupMount();

Expand All @@ -133,7 +154,7 @@ describe("compatible Anthropic inference switch setup", () => {
);
}
} finally {
fs.rmSync(stateDirectory, { force: true, recursive: true });
fs.rmSync(home, { force: true, recursive: true });
}
});

Expand All @@ -153,7 +174,11 @@ describe("compatible Anthropic inference switch setup", () => {
const add = vi.fn();

try {
await installGatewayHostVerificationAlias({ command } as unknown as HostCliClient, { add });
await installGatewayHostVerificationAlias(
{ command } as unknown as HostCliClient,
{ add },
stateDirectory,
);
const cleanupMount = add.mock.calls[0]?.[1] as () => Promise<void>;
await cleanupMount();

Expand Down
Loading