@dfinity/pic
Version:
An Internet Computer Protocol canister testing library for TypeScript and JavaScript.
126 lines • 4.11 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PocketIcServer = void 0;
const node_child_process_1 = require("node:child_process");
const node_path_1 = require("node:path");
const node_fs_1 = require("node:fs");
const error_1 = require("./error");
const util_1 = require("./util");
const node_stream_1 = require("node:stream");
/**
* This class represents the main PocketIC server.
* It is responsible for maintaining the lifecycle of the server process.
* See {@link PocketIc} for details on the client to use with this server.
*
* @category API
*
* @example
* ```ts
* import { PocketIc, PocketIcServer } from '@dfinity/pic';
* import { _SERVICE, idlFactory } from '../declarations';
*
* const wasmPath = resolve('..', '..', 'canister.wasm');
*
* const picServer = await PocketIcServer.create();
* const pic = await PocketIc.create(picServer.getUrl());
*
* const fixture = await pic.setupCanister<_SERVICE>({ idlFactory, wasmPath });
* const { actor } = fixture;
*
* // perform tests...
*
* await pic.tearDown();
* await picServer.stop();
* ```
*/
class PocketIcServer {
serverProcess;
url;
constructor(serverProcess, portNumber) {
this.serverProcess = serverProcess;
this.url = `http://127.0.0.1:${portNumber}`;
}
/**
* Start a new PocketIC server.
*
* @param options Options for starting the server.
* @returns An instance of the PocketIC server.
*/
static async start(options = {}) {
const binPath = this.getBinPath();
await this.assertBinExists(binPath);
const pid = process.ppid;
const picFilePrefix = `pocket_ic_${pid}`;
const portFilePath = (0, util_1.tmpFile)(`${picFilePrefix}.port`);
const serverProcess = (0, node_child_process_1.spawn)(binPath, ['--port-file', portFilePath]);
if (options.showRuntimeLogs) {
serverProcess.stdout.pipe(process.stdout);
}
else {
serverProcess.stdout.pipe(new NullStream());
}
if (options.showCanisterLogs) {
serverProcess.stderr.pipe(process.stderr);
}
else {
serverProcess.stderr.pipe(new NullStream());
}
serverProcess.on('error', error => {
if ((0, util_1.isArm)() && (0, util_1.isDarwin)()) {
throw new error_1.BinStartMacOSArmError(error);
}
throw new error_1.BinStartError(error);
});
return await (0, util_1.poll)(async () => {
const portString = await (0, util_1.readFileAsString)(portFilePath);
const port = parseInt(portString);
if (isNaN(port)) {
throw new error_1.BinTimeoutError();
}
return new PocketIcServer(serverProcess, port);
}, { intervalMs: POLL_INTERVAL_MS, timeoutMs: POLL_TIMEOUT_MS });
}
/**
* Get the URL of the server.
*
* @returns The URL of the server.
*/
getUrl() {
return this.url;
}
/**
* Stop the server.
*
* @returns A promise that resolves when the server has stopped.
*/
async stop() {
return new Promise((resolve, reject) => {
this.serverProcess.on('exit', () => {
resolve();
});
this.serverProcess.on('error', error => {
reject(error);
});
this.serverProcess.kill();
});
}
static getBinPath() {
return (0, node_path_1.resolve)(__dirname, '..', 'pocket-ic');
}
static async assertBinExists(binPath) {
const binExists = await (0, util_1.exists)(binPath);
if (!binExists) {
throw new error_1.BinNotFoundError(binPath);
}
(0, node_fs_1.chmodSync)(binPath, 0o700);
}
}
exports.PocketIcServer = PocketIcServer;
const POLL_INTERVAL_MS = 20;
const POLL_TIMEOUT_MS = 30_000;
class NullStream extends node_stream_1.Writable {
_write(_chunk, _encoding, callback) {
callback();
}
}
//# sourceMappingURL=pocket-ic-server.js.map