mirror of
https://github.com/software-mansion/argent.git
synced 2026-09-14 19:27:14 +08:00
b835de2326
## Summary Fixes the biggest chunk of #980: the published package shipped **four byte-identical copies** of the Android screen-sharing agent (`resources/android/`: jar + per-ABI `.so`, ~12.7 MiB each) — one next to each platform's simulator-server binary, because the binary resolves the agent relative to its working directory and the spawn set cwd to the per-platform dir. This ships **one shared copy** at `bin/resources/android/` and points the spawn cwd at the bin root instead. Package size (built from this branch, same artifact set as 0.22.1): | | before | after | |---|---|---| | unpacked | 115.5 MB | **76.4 MB** | | packed | 37.6 MB | 25.4 MB | 76.4 MB is under npmmirror's 83886080-byte unpacked-size cap (the limit #980 trips — note it applies to `dist.unpackedSize`, not the tarball). Already-published oversized versions are immutable, so the mirror also needs the `cnpm/unpkg-white-list` entry to sync the backlog; this PR keeps future versions under the cap. ## Changes - `scripts/download-simulator-server.sh` extracts the agent tarball once, to `bin/resources/android/`, instead of next to each binary. - `bundle-tools.cjs` copies that single shared directory into the package. - `@argent/native-devtools-ios` replaces `simulatorServerBinaryDir()` with `simulatorServerRunDir()`: the bin root when the shared `resources/android/` exists there, falling back to the per-platform dir so an `ARGENT_SIMULATOR_SERVER_DIR` override pointing at a pre-dedup layout keeps working. - The blueprint spawns simulator-server with `cwd: RUN_DIR` (binary path stays absolute; the agent lookup is the only cwd-relative path in the simulator-server crate — audited: every other fs path there is a tempdir, `dirs::cache_dir()`, or caller-supplied). No symlinks, no postinstall scripts — plain files plus a different cwd, so nothing changes for npm/pnpm/yarn/bun or Windows. ## Testing - Unit: resolver tests updated + new shared-layout case; blueprint test asserts the spawn cwd. - Packaging: ran the modified download script + `npm run pack` end-to-end; tarball contains exactly one `bin/resources/android/` (94 files vs 112). - Live: branch tool-server with `ARGENT_SIMULATOR_SERVER_DIR` pointed at the new layout — iOS simulator (screenshot) and Android emulator (boot-device, screenshot, gesture-tap) green; `lsof` confirms both spawned simulator-servers run with cwd = bin root, where `resources/android/<jar>` and each per-ABI `.so` resolve (verified present at those exact relative paths). - Physical Android phone (Galaxy S24, the one path that actually pushes the agent): live-tested — the `android_device` controller resolved the agent from the shared layout, pushed it, and connected ("All agent connections established successfully"); screenshot and tap through the on-phone agent both green, spawn cwd confirmed as the shared bin root. No docs update needed: internal packaging/layout only — no MCP tool, CLI, config, or flow-file surface changes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01UGAsAvYBJ3Jy9DKLaX9aoZ <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved simulator-server resource handling by using one shared screen-sharing resource location across host platforms. * Added a warning when required shared resources are unavailable. * Ensured simulator-server processes start from the correct runtime directory. * **Documentation** * Clarified simulator-server runtime and shared resource behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
388 lines
19 KiB
TypeScript
388 lines
19 KiB
TypeScript
import * as fs from "node:fs";
|
|
import * as os from "node:os";
|
|
import * as path from "node:path";
|
|
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
|
// Static import primes vite's module graph so the dynamic re-import below
|
|
// resolves to the same node; we re-import via the SAME specifier after
|
|
// vi.resetModules() to reset captured env per-test.
|
|
import type * as ResolverModule from "../src/index";
|
|
|
|
// Unit tests for the resolver in this package. The resolver is what gates
|
|
// iOS-only binaries from being looked up on Linux callers, and what joins
|
|
// `process.platform` into the simulator-server bin path. Both behaviors
|
|
// only execute on resolver invocation, so we test the exported functions
|
|
// directly. We override ARGENT_NATIVE_DEVTOOLS_DIR /
|
|
// ARGENT_SIMULATOR_SERVER_DIR per-test so the resolver looks at a tmpdir we
|
|
// control rather than the real packages/native-devtools-ios layout.
|
|
|
|
let tmpRoot = "";
|
|
const originalPlatform = process.platform;
|
|
const originalArch = process.arch;
|
|
const originalDevtoolsDir = process.env.ARGENT_NATIVE_DEVTOOLS_DIR;
|
|
const originalSimulatorDir = process.env.ARGENT_SIMULATOR_SERVER_DIR;
|
|
const originalDevtoolsTcpDir = process.env.ARGENT_NATIVE_DEVTOOLS_TCP_DIR;
|
|
const originalSimulatorTcpDir = process.env.ARGENT_SIMULATOR_SERVER_TCP_DIR;
|
|
|
|
function setPlatform(value: NodeJS.Platform) {
|
|
Object.defineProperty(process, "platform", { value, configurable: true });
|
|
}
|
|
|
|
function setArch(value: NodeJS.Architecture) {
|
|
Object.defineProperty(process, "arch", { value, configurable: true });
|
|
}
|
|
|
|
// The on-disk binary name is `.exe` on Windows, extensionless elsewhere — must
|
|
// match simulatorServerBinaryName(). Tests that don't override the platform run
|
|
// against the host's real one, so their fixtures have to use the host-correct
|
|
// name to pass on a Windows runner as well as on macOS/Linux.
|
|
function ssBinName(): string {
|
|
return process.platform === "win32" ? "simulator-server.exe" : "simulator-server";
|
|
}
|
|
|
|
beforeAll(() => {
|
|
tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "argent-resolver-"));
|
|
});
|
|
|
|
afterAll(() => {
|
|
if (tmpRoot) fs.rmSync(tmpRoot, { recursive: true, force: true });
|
|
setPlatform(originalPlatform);
|
|
setArch(originalArch);
|
|
if (originalDevtoolsDir === undefined) delete process.env.ARGENT_NATIVE_DEVTOOLS_DIR;
|
|
else process.env.ARGENT_NATIVE_DEVTOOLS_DIR = originalDevtoolsDir;
|
|
if (originalSimulatorDir === undefined) delete process.env.ARGENT_SIMULATOR_SERVER_DIR;
|
|
else process.env.ARGENT_SIMULATOR_SERVER_DIR = originalSimulatorDir;
|
|
if (originalDevtoolsTcpDir === undefined) delete process.env.ARGENT_NATIVE_DEVTOOLS_TCP_DIR;
|
|
else process.env.ARGENT_NATIVE_DEVTOOLS_TCP_DIR = originalDevtoolsTcpDir;
|
|
if (originalSimulatorTcpDir === undefined) delete process.env.ARGENT_SIMULATOR_SERVER_TCP_DIR;
|
|
else process.env.ARGENT_SIMULATOR_SERVER_TCP_DIR = originalSimulatorTcpDir;
|
|
});
|
|
|
|
afterEach(() => {
|
|
setPlatform(originalPlatform);
|
|
setArch(originalArch);
|
|
delete process.env.ARGENT_NATIVE_DEVTOOLS_TCP_DIR;
|
|
delete process.env.ARGENT_SIMULATOR_SERVER_TCP_DIR;
|
|
});
|
|
|
|
/**
|
|
* Re-import the resolver after env / platform mutations. The module captures
|
|
* ARGENT_NATIVE_DEVTOOLS_DIR / ARGENT_SIMULATOR_SERVER_DIR at top-level on
|
|
* first load; vi.resetModules() clears vite's cache so the next import()
|
|
* re-executes the module body and picks up the current env. The dynamic
|
|
* specifier must match the static import above byte-for-byte so vite's
|
|
* module graph resolves to the same node.
|
|
*/
|
|
async function loadResolver(): Promise<typeof ResolverModule> {
|
|
vi.resetModules();
|
|
return await import("../src/index");
|
|
}
|
|
|
|
describe("requireDarwin gating", () => {
|
|
it("throws with a root-cause message on linux for iOS-only dylibs", async () => {
|
|
// A Linux caller asking for an iOS Simulator dylib should get the root
|
|
// cause ("requires a macOS host") not a misleading "file not found",
|
|
// which is what happened before this PR and led to confused bug reports.
|
|
setPlatform("linux");
|
|
const r = await loadResolver();
|
|
expect(() => r.bootstrapDylibPath()).toThrow(/requires a macOS host/);
|
|
expect(() => r.nativeDevtoolsDylibPath()).toThrow(/requires a macOS host/);
|
|
expect(() => r.keyboardPatchDylibPath()).toThrow(/requires a macOS host/);
|
|
});
|
|
|
|
it("resolves TCP dylibs on linux (remote upload artifacts, not gated)", async () => {
|
|
// TCP variants are payloads uploaded to a remote Mac orchestrator via
|
|
// sim-remote, so a Linux host must be able to resolve them. They are guarded
|
|
// only by the file-existence check below, NOT by requireDarwin.
|
|
setPlatform("linux");
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "tcp-dylibs-"));
|
|
fs.writeFileSync(path.join(dir, "libArgentInjectionBootstrap.dylib"), "");
|
|
fs.writeFileSync(path.join(dir, "libNativeDevtoolsIos.dylib"), "");
|
|
fs.writeFileSync(path.join(dir, "libKeyboardPatch.dylib"), "");
|
|
process.env.ARGENT_NATIVE_DEVTOOLS_TCP_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(r.bootstrapDylibPathTcp()).toBe(path.join(dir, "libArgentInjectionBootstrap.dylib"));
|
|
expect(r.nativeDevtoolsDylibPathTcp()).toBe(path.join(dir, "libNativeDevtoolsIos.dylib"));
|
|
expect(r.keyboardPatchDylibPathTcp()).toBe(path.join(dir, "libKeyboardPatch.dylib"));
|
|
});
|
|
|
|
it("resolves TCP dylibs from the default dylibs/tcp on linux (neutral, no override)", async () => {
|
|
// Without the tcp override env, the tcp dylib dir defaults to DYLIB_DIR/tcp —
|
|
// platform-NEUTRAL, exactly like the tcp ax-service's bin/tcp. Resolving from
|
|
// the base dir on a Linux host must land under tcp/, never a host-platform
|
|
// subdir, since these are darwin artifacts uploaded to the remote orchestrator.
|
|
setPlatform("linux");
|
|
const base = fs.mkdtempSync(path.join(tmpRoot, "dylibs-base-"));
|
|
const tcpDir = path.join(base, "tcp");
|
|
fs.mkdirSync(tcpDir, { recursive: true });
|
|
fs.writeFileSync(path.join(tcpDir, "libArgentInjectionBootstrap.dylib"), "");
|
|
fs.writeFileSync(path.join(tcpDir, "libNativeDevtoolsIos.dylib"), "");
|
|
fs.writeFileSync(path.join(tcpDir, "libKeyboardPatch.dylib"), "");
|
|
process.env.ARGENT_NATIVE_DEVTOOLS_DIR = base;
|
|
try {
|
|
const r = await loadResolver();
|
|
expect(r.bootstrapDylibPathTcp()).toBe(
|
|
path.join(tcpDir, "libArgentInjectionBootstrap.dylib")
|
|
);
|
|
expect(r.nativeDevtoolsDylibPathTcp()).toBe(path.join(tcpDir, "libNativeDevtoolsIos.dylib"));
|
|
expect(r.keyboardPatchDylibPathTcp()).toBe(path.join(tcpDir, "libKeyboardPatch.dylib"));
|
|
} finally {
|
|
if (originalDevtoolsDir === undefined) delete process.env.ARGENT_NATIVE_DEVTOOLS_DIR;
|
|
else process.env.ARGENT_NATIVE_DEVTOOLS_DIR = originalDevtoolsDir;
|
|
}
|
|
});
|
|
|
|
it("throws a plain not-found (not a macOS-host error) for missing TCP dylibs on linux", async () => {
|
|
// When the TCP artifacts haven't been downloaded, the file-existence check
|
|
// gives a "not found" error — never the "requires a macOS host" gate.
|
|
setPlatform("linux");
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "tcp-dylibs-missing-"));
|
|
process.env.ARGENT_NATIVE_DEVTOOLS_TCP_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(() => r.bootstrapDylibPathTcp()).toThrow(/dylib not found/);
|
|
expect(() => r.bootstrapDylibPathTcp()).not.toThrow(/requires a macOS host/);
|
|
// The error must be self-servicing: name the override env var so a user
|
|
// hitting a stale/dev build learns how to relocate the lookup.
|
|
expect(() => r.bootstrapDylibPathTcp()).toThrow(/ARGENT_NATIVE_DEVTOOLS_TCP_DIR/);
|
|
});
|
|
|
|
it("throws an actionable not-found (naming the override env) for a missing TCP ax-service", async () => {
|
|
// A missing TCP ax-service otherwise surfaces deep in describe as a
|
|
// misleading "reboot the simulator" hint; the resolver error must instead
|
|
// point at the override env so the real cause is diagnosable.
|
|
setPlatform("darwin");
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "ax-tcp-missing-"));
|
|
fs.mkdirSync(path.join(dir, "tcp"), { recursive: true });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(() => r.axServiceBinaryPathTcp()).toThrow(/TCP-transport binary not found/);
|
|
expect(() => r.axServiceBinaryPathTcp()).toThrow(/ARGENT_SIMULATOR_SERVER_TCP_DIR/);
|
|
});
|
|
|
|
it("throws with a root-cause message on linux for ax-service", async () => {
|
|
// ax-service is darwin-only (runs INSIDE the iOS Simulator), so the
|
|
// resolver must throw the platform error BEFORE the file-existence check.
|
|
setPlatform("linux");
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = tmpRoot;
|
|
const r = await loadResolver();
|
|
expect(() => r.axServiceBinaryPath()).toThrow(/requires a macOS host/);
|
|
});
|
|
|
|
it("resolves the ax-service TCP binary from the platform-neutral bin/tcp on linux", async () => {
|
|
// The TCP ax-service is uploaded to and `simctl spawn`d on the remote Mac
|
|
// orchestrator, so a Linux host must resolve it from the neutral bin/tcp —
|
|
// NOT bin/linux/tcp, which would never hold the darwin-built binary.
|
|
setPlatform("linux");
|
|
setArch("x64");
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "ax-tcp-linux-"));
|
|
const tcpDir = path.join(dir, "tcp");
|
|
fs.mkdirSync(tcpDir, { recursive: true });
|
|
const binPath = path.join(tcpDir, "ax-service");
|
|
fs.writeFileSync(binPath, "", { mode: 0o755 });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(r.axServiceBinaryPathTcp()).toBe(binPath);
|
|
});
|
|
});
|
|
|
|
describe("simulator-server path resolution", () => {
|
|
it("joins process.platform into the bin path", async () => {
|
|
// The whole point of the per-platform bin layout. We're verifying that
|
|
// the resolver constructs <BIN_ROOT>/<platform>/simulator-server, not
|
|
// <BIN_ROOT>/simulator-server.
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "platform-join-"));
|
|
const platDir = path.join(dir, process.platform);
|
|
fs.mkdirSync(platDir, { recursive: true });
|
|
const binPath = path.join(platDir, ssBinName());
|
|
fs.writeFileSync(binPath, "", { mode: 0o755 });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(r.simulatorServerBinaryPath()).toBe(binPath);
|
|
expect(r.simulatorServerRunDir()).toBe(platDir);
|
|
});
|
|
|
|
it("run dir is the bin root when the shared resources/android copy exists", async () => {
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "shared-resources-"));
|
|
const platDir = path.join(dir, process.platform);
|
|
fs.mkdirSync(platDir, { recursive: true });
|
|
fs.writeFileSync(path.join(platDir, ssBinName()), "", { mode: 0o755 });
|
|
fs.mkdirSync(path.join(dir, "resources", "android"), { recursive: true });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(r.simulatorServerRunDir()).toBe(dir);
|
|
});
|
|
|
|
it("throws when the per-platform binary is missing", async () => {
|
|
// Empty per-platform dir: the resolver should fail loudly with both the
|
|
// platform name and the expected path in the message so the user can
|
|
// act on it (re-run the download script, switch hosts, etc).
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "missing-"));
|
|
fs.mkdirSync(path.join(dir, process.platform), { recursive: true });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(() => r.simulatorServerBinaryPath()).toThrow(/simulator-server binary not found/);
|
|
expect(() => r.simulatorServerBinaryPath()).toThrow(new RegExp(process.platform));
|
|
});
|
|
|
|
it("includes a migration hint when ARGENT_SIMULATOR_SERVER_DIR points at the old flat layout", async () => {
|
|
// Prior to the Linux per-platform layout, ARGENT_SIMULATOR_SERVER_DIR
|
|
// was the directory that contained simulator-server directly. A user
|
|
// with that setup now gets a "not found" error; the migration hint in
|
|
// the message tells them exactly what changed and how to fix it.
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "flat-layout-"));
|
|
fs.mkdirSync(path.join(dir, process.platform), { recursive: true });
|
|
// Place the binary at the flat (old) path, host-correct name.
|
|
const flatBin = path.join(dir, ssBinName());
|
|
fs.writeFileSync(flatBin, "", { mode: 0o755 });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(() => r.simulatorServerBinaryPath()).toThrow(/old flat path/);
|
|
expect(() => r.simulatorServerBinaryPath()).toThrow(new RegExp(process.platform));
|
|
});
|
|
});
|
|
|
|
describe("host platform key (arch-aware Linux bin dirs)", () => {
|
|
// Linux binaries are single-arch ELFs (unlike the universal macOS binary),
|
|
// so arm64 Linux resolves to its own "linux-arm64" directory while x86_64
|
|
// keeps the pre-arm64 "linux" name. Without this split, an arm64 host would
|
|
// silently pick up the x86_64 ELF and fail with ENOEXEC at spawn time.
|
|
it("resolves bin/linux-arm64 on arm64 Linux", async () => {
|
|
setPlatform("linux");
|
|
setArch("arm64");
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "linux-arm64-"));
|
|
const platDir = path.join(dir, "linux-arm64");
|
|
fs.mkdirSync(platDir, { recursive: true });
|
|
const binPath = path.join(platDir, "simulator-server");
|
|
fs.writeFileSync(binPath, "", { mode: 0o755 });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(r.hostPlatformKey()).toBe("linux-arm64");
|
|
expect(r.simulatorServerBinaryPath()).toBe(binPath);
|
|
expect(r.simulatorServerRunDir()).toBe(platDir);
|
|
});
|
|
|
|
it("keeps resolving bin/linux on x86_64 Linux", async () => {
|
|
setPlatform("linux");
|
|
setArch("x64");
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "linux-x64-"));
|
|
const platDir = path.join(dir, "linux");
|
|
fs.mkdirSync(platDir, { recursive: true });
|
|
const binPath = path.join(platDir, "simulator-server");
|
|
fs.writeFileSync(binPath, "", { mode: 0o755 });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(r.hostPlatformKey()).toBe("linux");
|
|
expect(r.simulatorServerBinaryPath()).toBe(binPath);
|
|
});
|
|
|
|
it("keeps resolving bin/darwin on arm64 macOS (universal binary)", async () => {
|
|
setPlatform("darwin");
|
|
setArch("arm64");
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "darwin-arm64-"));
|
|
const platDir = path.join(dir, "darwin");
|
|
fs.mkdirSync(platDir, { recursive: true });
|
|
const binPath = path.join(platDir, "simulator-server");
|
|
fs.writeFileSync(binPath, "", { mode: 0o755 });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(r.hostPlatformKey()).toBe("darwin");
|
|
expect(r.simulatorServerBinaryPath()).toBe(binPath);
|
|
});
|
|
|
|
it("names the linux-arm64 key in the missing-binary error", async () => {
|
|
// The error must name the directory actually searched ("linux-arm64"),
|
|
// not bare process.platform, so an arm64 user re-running the download
|
|
// script can tell which asset is absent.
|
|
setPlatform("linux");
|
|
setArch("arm64");
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "linux-arm64-missing-"));
|
|
fs.mkdirSync(path.join(dir, "linux-arm64"), { recursive: true });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(() => r.simulatorServerBinaryPath()).toThrow(/linux-arm64/);
|
|
});
|
|
});
|
|
|
|
describe("Windows (win32) binary resolution", () => {
|
|
// The Windows release ships a PE `.exe` (simulator-server.exe), not the
|
|
// extensionless binary other hosts use. The resolver must pick the `.exe`
|
|
// name AND key the directory by "win32" (process.platform), so a Windows
|
|
// host finds bin/win32/simulator-server.exe. iOS is macOS-only, so this
|
|
// binary serves Android + Chromium hosts.
|
|
it("resolves bin/win32/simulator-server.exe on Windows", async () => {
|
|
setPlatform("win32");
|
|
setArch("x64");
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "win32-"));
|
|
const platDir = path.join(dir, "win32");
|
|
fs.mkdirSync(platDir, { recursive: true });
|
|
const binPath = path.join(platDir, "simulator-server.exe");
|
|
fs.writeFileSync(binPath, "", { mode: 0o755 });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(r.hostPlatformKey()).toBe("win32");
|
|
expect(r.simulatorServerBinaryName()).toBe("simulator-server.exe");
|
|
expect(r.simulatorServerBinaryPath()).toBe(binPath);
|
|
expect(r.simulatorServerRunDir()).toBe(platDir);
|
|
});
|
|
|
|
it("does not resolve an extensionless binary on Windows", async () => {
|
|
// Guards against a half-migrated layout: an extensionless
|
|
// bin/win32/simulator-server must NOT satisfy the resolver, since Windows
|
|
// can't exec it — the error should point at the `.exe` it actually needs.
|
|
setPlatform("win32");
|
|
setArch("x64");
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "win32-noext-"));
|
|
const platDir = path.join(dir, "win32");
|
|
fs.mkdirSync(platDir, { recursive: true });
|
|
fs.writeFileSync(path.join(platDir, "simulator-server"), "", { mode: 0o755 });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(() => r.simulatorServerBinaryPath()).toThrow(/simulator-server\.exe/);
|
|
expect(() => r.simulatorServerBinaryPath()).toThrow(/win32/);
|
|
});
|
|
});
|
|
|
|
describe("ax-service path resolution", () => {
|
|
it("joins process.platform into the ax-service bin path", async () => {
|
|
if (originalPlatform !== "darwin") return;
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "ax-platform-"));
|
|
const platDir = path.join(dir, "darwin");
|
|
fs.mkdirSync(platDir, { recursive: true });
|
|
const binPath = path.join(platDir, "ax-service");
|
|
fs.writeFileSync(binPath, "", { mode: 0o755 });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(r.axServiceBinaryPath()).toBe(binPath);
|
|
});
|
|
|
|
it("resolves the ax-service TCP binary from the platform-neutral bin/tcp", async () => {
|
|
// The tcp ax-service is host-platform-independent (uploaded to the remote
|
|
// orchestrator), so it resolves at bin/tcp — not bin/<hostPlatform>/tcp.
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "ax-tcp-"));
|
|
const tcpDir = path.join(dir, "tcp");
|
|
fs.mkdirSync(tcpDir, { recursive: true });
|
|
const binPath = path.join(tcpDir, "ax-service");
|
|
fs.writeFileSync(binPath, "", { mode: 0o755 });
|
|
process.env.ARGENT_SIMULATOR_SERVER_DIR = dir;
|
|
const r = await loadResolver();
|
|
expect(r.axServiceBinaryPathTcp()).toBe(binPath);
|
|
});
|
|
});
|
|
|
|
describe("ARGENT_NATIVE_DEVTOOLS_DIR override", () => {
|
|
it("uses the env-var dir for dylib resolution on darwin", async () => {
|
|
// The launcher script swaps the dylib dir at runtime via this env var
|
|
// (matches the ARGENT_SIMULATOR_SERVER_DIR pattern). Linux callers can't
|
|
// exercise the happy path because requireDarwin throws first, so this
|
|
// test only meaningfully runs on darwin — skip elsewhere rather than
|
|
// pretend to test it.
|
|
if (originalPlatform !== "darwin") return;
|
|
const dir = fs.mkdtempSync(path.join(tmpRoot, "dylib-override-"));
|
|
const dylib = path.join(dir, "libNativeDevtoolsIos.dylib");
|
|
fs.writeFileSync(dylib, "");
|
|
process.env.ARGENT_NATIVE_DEVTOOLS_DIR = dir;
|
|
setPlatform("darwin");
|
|
const r = await loadResolver();
|
|
expect(r.nativeDevtoolsDylibPath()).toBe(dylib);
|
|
});
|
|
});
|