Skip to content

Commit a92ebed

Browse files
committed
test: create test scratch via mkdtempForTest instead of os.tmpdir()
Route every product-test scratch directory through the per-package mkdtempForTest/mkdtempForTestSync helpers so it lands under the run's redirected TMPDIR and is removed once per run, instead of ad-hoc path.join(os.tmpdir(), name) that reuses a fixed path across the suite. Collapses the repeated daemon.log idiom to one scratch dir per call site, drops now-redundant randomUUID/Date.now() uniqueness suffixes, and folds two ad-hoc Android screenshot paths into the existing withTempScreenshot helper. Adds the missing tmp-dir helpers to platform-harmonyos, provider-webdriver, and replay-test and rounds out platform-apple's. Adds an AST-based check-test-tmpdir gate + unit test that fails any product test file reading os.tmpdir() directly, with a documented allowlist for the tmpdir-mechanism, mirror-production, and unix-socket-length cases. Also drops a stale installArgs field from a snapshot-helper manifest fixture (a #2618 leftover) that broke typecheck.
1 parent 2cafab3 commit a92ebed

86 files changed

Lines changed: 777 additions & 370 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/capture-kit/src/audio-probe-runtime.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import assert from 'node:assert/strict';
22
import { promises as fs } from 'node:fs';
3-
import os from 'node:os';
3+
44
import path from 'node:path';
55
import { test } from 'vitest';
66
import type {
@@ -19,6 +19,7 @@ import {
1919
createDurableResourceEnvelope,
2020
encodeDurableDescriptor,
2121
} from './durable-resource-envelope.ts';
22+
import { mkdtempForTest } from './tmp-dir.fixtures.ts';
2223

2324
const device: DeviceInfo = {
2425
id: 'macos-host',
@@ -56,7 +57,7 @@ function envelopeWith(body: object) {
5657
}
5758

5859
async function withStatusDir<T>(run: (dir: string) => Promise<T>): Promise<T> {
59-
const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'audio-probe-kit-'));
60+
const dir = await mkdtempForTest('audio-probe-kit-');
6061
try {
6162
return await run(dir);
6263
} finally {

packages/host-kit/src/internal/archive-extraction.fixtures.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import { promises as fs } from 'node:fs';
2-
import os from 'node:os';
2+
33
import path from 'node:path';
44
import { gzipSync } from 'node:zlib';
55
import * as tar from 'tar-stream';
66
import { runCmdSync } from './exec.ts';
7+
import { mkdtempForTest } from './tmp-dir.fixtures.ts';
78

89
export async function createArchiveWorkspace(): Promise<{
910
archivePath: string;
1011
outputRoot: string;
1112
root: string;
1213
}> {
13-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'agent-device-archive-'));
14+
const root = await mkdtempForTest('agent-device-archive-');
1415
const outputRoot = path.join(root, 'output');
1516
await fs.mkdir(outputRoot);
1617
return { archivePath: path.join(root, 'fixture.archive'), outputRoot, root };

packages/host-kit/src/internal/durable-file.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import assert from 'node:assert/strict';
22
import fs from 'node:fs';
3-
import os from 'node:os';
3+
44
import path from 'node:path';
55
import { afterEach, expect, test, vi } from 'vitest';
66
import { isAtomicPublishTemporaryPath, publishDurableFileSync } from './atomic-file.ts';
7+
import { mkdtempForTestSync } from './tmp-dir.fixtures.ts';
78

89
const roots: string[] = [];
910

@@ -109,7 +110,7 @@ test('preserves a file fsync error when descriptor cleanup also fails', () => {
109110
});
110111

111112
function fixtureRoot(label: string): string {
112-
const root = fs.mkdtempSync(path.join(os.tmpdir(), `agent-device-durable-file-${label}-`));
113+
const root = mkdtempForTestSync(`agent-device-durable-file-${label}-`);
113114
roots.push(root);
114115
return root;
115116
}

packages/host-kit/src/internal/owner-identity.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import assert from 'node:assert/strict';
22
import fs from 'node:fs';
3-
import os from 'node:os';
3+
44
import path from 'node:path';
55
import { afterEach, test, vi } from 'vitest';
66
import {
@@ -10,6 +10,7 @@ import {
1010
type OwnerIdentity,
1111
} from './owner-identity.ts';
1212
import { readProcessStartTime } from './host-process.ts';
13+
import { mkdtempForTestSync } from './tmp-dir.fixtures.ts';
1314

1415
afterEach(() => {
1516
vi.restoreAllMocks();
@@ -28,7 +29,10 @@ test('distinguishes dead and PID-reused owners', () => {
2829

2930
test('distinguishes a gone state directory from permission and transient I/O failures', () => {
3031
const startTime = readProcessStartTime(process.pid);
31-
const missing = path.join(os.tmpdir(), `agent-device-missing-owner-${Date.now()}`);
32+
const missing = path.join(
33+
mkdtempForTestSync('agent-device-missing-owner'),
34+
`agent-device-missing-owner-${Date.now()}`,
35+
);
3236
assert.equal(
3337
classifyOwnerLiveness({ owner: { pid: process.pid, startTime }, stateDir: missing }),
3438
'owner-state-dir-gone',

packages/host-kit/src/internal/verified-file.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import assert from 'node:assert/strict';
22
import fs from 'node:fs';
3-
import os from 'node:os';
3+
44
import path from 'node:path';
55
import { afterEach, expect, test, vi } from 'vitest';
66
import { AppError, normalizeError } from '@agent-device/kernel/errors';
@@ -17,6 +17,7 @@ import {
1717
openVerifiedFileForRead,
1818
openVerifiedFileForTruncate,
1919
} from './verified-file.ts';
20+
import { mkdtempForTestSync } from './tmp-dir.fixtures.ts';
2021

2122
const roots: string[] = [];
2223

@@ -111,7 +112,7 @@ test('returns absent for a missing read without creating the file', () => {
111112
});
112113

113114
function fixturePath(label: string): string {
114-
const root = fs.mkdtempSync(path.join(os.tmpdir(), `agent-device-verified-${label}-`));
115+
const root = mkdtempForTestSync(`agent-device-verified-${label}-`);
115116
roots.push(root);
116117
return path.join(root, 'artifact');
117118
}

packages/platform-android/src/__tests__/app-deployment.test.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { test } from 'vitest';
22
import assert from 'node:assert/strict';
33
import { promises as fs } from 'node:fs';
4-
import os from 'node:os';
4+
55
import path from 'node:path';
66
import { AppError } from '@agent-device/kernel/errors';
77
import { installAndroidInstallablePath } from '../app-deployment.ts';
@@ -14,7 +14,8 @@ import { withAndroidAdbProvider } from '../adb-executor.ts';
1414
import type { DeviceInfo } from '@agent-device/kernel/device';
1515
import { assertRejectsAppError } from './test-utils/app-error.ts';
1616
import { withFakeAdb } from './test-utils/fake-adb.ts';
17-
import { mkdtempForTest } from './test-utils/tmp-dir.ts';
17+
18+
import { mkdtempForTest, mkdtempForTestSync } from './test-utils/tmp-dir.ts';
1819

1920
// The fake adb provider installs through the production withAndroidAdbProvider
2021
// scope, so `calls` records device-scoped args without a leading `-s <serial>`.
@@ -32,7 +33,10 @@ test('inferAndroidAppName derives readable names from package ids', () => {
3233
});
3334

3435
test('installAndroidInstallablePath installs .apk via adb install -r', async () => {
35-
const apkPath = path.join(os.tmpdir(), `agent-device-test-${Date.now()}.apk`);
36+
const apkPath = path.join(
37+
mkdtempForTestSync('agent-device-test'),
38+
`agent-device-test-${Date.now()}.apk`,
39+
);
3640
await fs.writeFile(apkPath, 'placeholder', 'utf8');
3741
await withFakeAdb(
3842
() => undefined,
@@ -49,7 +53,10 @@ test('installAndroidInstallablePath installs .apk via adb install -r', async ()
4953
});
5054

5155
test('installAndroidInstallablePath uses provider install capability when available', async () => {
52-
const apkPath = path.join(os.tmpdir(), `agent-device-provider-install-${Date.now()}.apk`);
56+
const apkPath = path.join(
57+
mkdtempForTestSync('agent-device-provider-install'),
58+
`agent-device-provider-install-${Date.now()}.apk`,
59+
);
5360
await fs.writeFile(apkPath, 'placeholder', 'utf8');
5461
const installCalls: Array<{ source: string; replace: boolean | undefined }> = [];
5562
const device: DeviceInfo = {
@@ -84,7 +91,10 @@ test('installAndroidInstallablePath uses provider install capability when availa
8491
test('an app install timeout keeps the generic adb-server advice', async () => {
8592
// The OEM install dialog can hold an app install too, but the helper-specific advice names an
8693
// agent-device helper package, so it must not leak onto the app-under-test install path.
87-
const apkPath = path.join(os.tmpdir(), `agent-device-app-install-timeout-${Date.now()}.apk`);
94+
const apkPath = path.join(
95+
mkdtempForTestSync('agent-device-app-install-timeout'),
96+
`agent-device-app-install-timeout-${Date.now()}.apk`,
97+
);
8898
await fs.writeFile(apkPath, 'placeholder', 'utf8');
8999
const device: DeviceInfo = {
90100
platform: 'android',

packages/platform-android/src/__tests__/snapshot-helper-install.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ const manifest: AndroidSnapshotHelperManifest = {
2626
targetSdk: 36,
2727
outputFormat: 'uiautomator-xml',
2828
statusProtocol: 'android-snapshot-helper-v1',
29-
installArgs: ['install', '-r'],
3029
};
3130

3231
beforeEach(() => {

packages/platform-android/src/__tests__/snapshot.test.ts

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { afterEach, beforeEach, test, vi } from 'vitest';
22
import assert from 'node:assert/strict';
33
import { promises as fs } from 'node:fs';
4-
import os from 'node:os';
4+
55
import path from 'node:path';
66

77
vi.mock('@agent-device/host-kit/command', async (importOriginal) => {
@@ -114,31 +114,29 @@ afterEach(async () => {
114114

115115
test('screenshotAndroid waits for transient UI to settle before capture', async () => {
116116
const events: string[] = [];
117-
const outPath = path.join(os.tmpdir(), `agent-device-android-screenshot-${Date.now()}.png`);
118-
119-
mockScreenshotEvents(events);
120-
121-
await screenshotAndroid(device, outPath);
117+
await withTempScreenshot('screenshot-settle-', async (outPath) => {
118+
mockScreenshotEvents(events);
119+
await screenshotAndroid(device, outPath);
122120

123-
const relevantEvents = events.filter((event, index) => {
124-
if (event !== 'enable') {
125-
return true;
126-
}
127-
return index === 0;
121+
const relevantEvents = events.filter((event, index) => {
122+
if (event !== 'enable') {
123+
return true;
124+
}
125+
return index === 0;
126+
});
127+
assert.deepEqual(relevantEvents, ['enable', 'settle:1000', 'capture', 'disable']);
128128
});
129-
assert.deepEqual(relevantEvents, ['enable', 'settle:1000', 'capture', 'disable']);
130129
});
131130

132131
test('screenshotAndroid skips stabilization when requested', async () => {
133132
const events: string[] = [];
134-
const outPath = path.join(os.tmpdir(), `agent-device-android-screenshot-${Date.now()}.png`);
135-
136-
mockScreenshotEvents(events);
133+
await withTempScreenshot('screenshot-stabilize-', async (outPath) => {
134+
mockScreenshotEvents(events);
135+
await screenshotAndroid(device, outPath, { stabilize: false });
137136

138-
await screenshotAndroid(device, outPath, { stabilize: false });
139-
140-
assert.deepEqual(events, ['capture']);
141-
assert.equal(mockSleep.mock.calls.length, 0);
137+
assert.deepEqual(events, ['capture']);
138+
assert.equal(mockSleep.mock.calls.length, 0);
139+
});
142140
});
143141

144142
test('screenshotAndroid writes a valid PNG when output is clean', async () => {

packages/platform-android/src/__tests__/test-utils/android-file-host.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { constants } from 'node:fs';
22
import {
33
access,
44
mkdir,
5-
mkdtemp,
65
open,
76
readFile,
87
readdir,
@@ -12,9 +11,10 @@ import {
1211
writeFile,
1312
} from 'node:fs/promises';
1413
import { createHash, randomUUID } from 'node:crypto';
15-
import os from 'node:os';
14+
1615
import path from 'node:path';
1716
import type { AndroidAdbFileHost } from '../../adb-host.ts';
17+
import { mkdtempForTest } from './tmp-dir.ts';
1818

1919
export function createAndroidFileHost(): AndroidAdbFileHost {
2020
return {
@@ -30,7 +30,7 @@ export function createAndroidFileHost(): AndroidAdbFileHost {
3030
return false;
3131
}
3232
},
33-
makeTempDirectory: async (prefix) => await mkdtemp(path.join(os.tmpdir(), prefix)),
33+
makeTempDirectory: async (prefix) => await mkdtempForTest(prefix),
3434
readBytes: async (filePath) => await readFile(filePath),
3535
readDirectory: async (directory) => await readdir(directory),
3636
readText: async (filePath) => await readFile(filePath, 'utf8'),
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1+
import fs from 'node:fs';
12
import fsPromises from 'node:fs/promises';
23
import os from 'node:os';
34
import path from 'node:path';
45

6+
// fallow-ignore-next-line code-duplication
57
export async function mkdtempForTest(prefix: string): Promise<string> {
68
return fsPromises.mkdtemp(path.join(os.tmpdir(), prefix));
79
}
10+
11+
// fallow-ignore-next-line code-duplication
12+
export function mkdtempForTestSync(prefix: string): string {
13+
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
14+
}

0 commit comments

Comments
 (0)