169 lines
4.7 KiB
JavaScript
169 lines
4.7 KiB
JavaScript
import { spawn } from "node:child_process";
|
|
import fs from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const helperDir = path.dirname(fileURLToPath(import.meta.url));
|
|
|
|
export const testsDir = path.resolve(helperDir, "..");
|
|
export const skillHome = path.resolve(testsDir, "..");
|
|
export const fetchScriptPath = path.join(skillHome, "scripts", "fetch-sales-intelligence.mjs");
|
|
|
|
let preparedRuntimeHomePromise = null;
|
|
|
|
export function testRuntimeHome() {
|
|
return (
|
|
process.env.ORACLE_SI_TEST_RUNTIME_HOME ||
|
|
path.join(os.tmpdir(), "knowledge-one-view-cli-tests", "runtime")
|
|
);
|
|
}
|
|
|
|
async function prepareRuntimeHome() {
|
|
if (process.env.ORACLE_SI_TEST_RUNTIME_HOME) {
|
|
await fs.mkdir(process.env.ORACLE_SI_TEST_RUNTIME_HOME, { recursive: true });
|
|
return process.env.ORACLE_SI_TEST_RUNTIME_HOME;
|
|
}
|
|
|
|
const runtimeHome = testRuntimeHome();
|
|
if (!process.env.ORACLE_SI_RUNTIME_HOME) {
|
|
await fs.mkdir(runtimeHome, { recursive: true });
|
|
return runtimeHome;
|
|
}
|
|
|
|
if (!preparedRuntimeHomePromise) {
|
|
preparedRuntimeHomePromise = (async () => {
|
|
await fs.rm(runtimeHome, { recursive: true, force: true });
|
|
await fs.mkdir(runtimeHome, { recursive: true });
|
|
for (const fileName of ["auth-state.json", "session-meta.json"]) {
|
|
await fs.copyFile(
|
|
path.join(process.env.ORACLE_SI_RUNTIME_HOME, fileName),
|
|
path.join(runtimeHome, fileName)
|
|
);
|
|
}
|
|
return runtimeHome;
|
|
})();
|
|
}
|
|
|
|
return preparedRuntimeHomePromise;
|
|
}
|
|
|
|
export function flagsInArgs(args) {
|
|
return args.filter((arg) => String(arg).startsWith("--"));
|
|
}
|
|
|
|
export function argValue(args, flagName) {
|
|
const index = args.indexOf(flagName);
|
|
return index >= 0 ? args[index + 1] : null;
|
|
}
|
|
|
|
export function executionModes(args) {
|
|
return ["--intent", "--view", "--query", "--sql"].filter((flagName) => args.includes(flagName));
|
|
}
|
|
|
|
export function withoutFlags(args, flagsToRemove) {
|
|
const flags = new Set(flagsToRemove);
|
|
const next = [];
|
|
for (let index = 0; index < args.length; index += 1) {
|
|
const token = args[index];
|
|
if (!flags.has(token)) {
|
|
next.push(token);
|
|
continue;
|
|
}
|
|
if (token !== "--query" && token !== "--render-sql" && args[index + 1] && !args[index + 1].startsWith("--")) {
|
|
index += 1;
|
|
}
|
|
}
|
|
return next;
|
|
}
|
|
|
|
export async function runFetch(cliArgs, options = {}) {
|
|
const {
|
|
expectCode = 0,
|
|
timeoutMs = 120000,
|
|
runtimeHome: requestedRuntimeHome = null,
|
|
} = options;
|
|
const runtimeHome = requestedRuntimeHome || (await prepareRuntimeHome());
|
|
const noCacheArgs = cliArgs.includes("--no-cache") ? [...cliArgs] : [...cliArgs, "--no-cache"];
|
|
const finalArgs = noCacheArgs.includes("--runtime-home")
|
|
? noCacheArgs
|
|
: [...noCacheArgs, "--runtime-home", runtimeHome];
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const child = spawn(process.execPath, [fetchScriptPath, ...finalArgs], {
|
|
stdio: ["ignore", "pipe", "pipe"],
|
|
env: process.env,
|
|
});
|
|
let stdout = "";
|
|
let stderr = "";
|
|
let timedOut = false;
|
|
const startedAt = process.hrtime.bigint();
|
|
|
|
const timer = setTimeout(() => {
|
|
timedOut = true;
|
|
child.kill();
|
|
}, timeoutMs);
|
|
|
|
child.stdout.setEncoding("utf8");
|
|
child.stderr.setEncoding("utf8");
|
|
child.stdout.on("data", (chunk) => {
|
|
stdout += chunk;
|
|
});
|
|
child.stderr.on("data", (chunk) => {
|
|
stderr += chunk;
|
|
});
|
|
|
|
child.on("error", reject);
|
|
child.on("close", (code) => {
|
|
clearTimeout(timer);
|
|
const durationMs = Number(process.hrtime.bigint() - startedAt) / 1_000_000;
|
|
let json = null;
|
|
try {
|
|
json = stdout.trim() ? JSON.parse(stdout) : null;
|
|
} catch {}
|
|
|
|
const result = {
|
|
args: finalArgs,
|
|
code,
|
|
stdout,
|
|
stderr,
|
|
json,
|
|
timedOut,
|
|
durationMs,
|
|
};
|
|
|
|
if (expectCode !== null && code !== expectCode) {
|
|
reject(
|
|
new Error(
|
|
[
|
|
`Unexpected exit code ${code}; expected ${expectCode}.`,
|
|
`Command: ${process.execPath} ${fetchScriptPath} ${finalArgs.join(" ")}`,
|
|
stderr.trim() || stdout.trim(),
|
|
]
|
|
.filter(Boolean)
|
|
.join("\n")
|
|
)
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (expectCode === 0 && (!json || typeof json !== "object")) {
|
|
reject(
|
|
new Error(
|
|
[
|
|
"Expected JSON output from fetch-sales-intelligence.mjs.",
|
|
`Command: ${process.execPath} ${fetchScriptPath} ${finalArgs.join(" ")}`,
|
|
stderr.trim() || stdout.trim(),
|
|
]
|
|
.filter(Boolean)
|
|
.join("\n")
|
|
)
|
|
);
|
|
return;
|
|
}
|
|
|
|
resolve(result);
|
|
});
|
|
});
|
|
}
|