Skip to content

Commit

Permalink
[cli] run pocket-ic from dfx
Browse files Browse the repository at this point in the history
  • Loading branch information
ZenVoich committed Nov 7, 2024
1 parent c435fa2 commit a998e6a
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 13 deletions.
1 change: 1 addition & 0 deletions cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ program
.addOption(new Option('--mode <mode>', 'Test mode').choices(['interpreter', 'wasi', 'replica']).default('interpreter'))
.addOption(new Option('--replica <replica>', 'Which replica to use to run tests in replica mode').choices(['dfx', 'pocket-ic']))
.option('-w, --watch', 'Enable watch mode')
.option('--debug', 'Show debug logs')
.action(async (filter, options) => {
checkConfigFile(true);
await installAll({silent: true, lock: 'ignore', installFromLockFile: true});
Expand Down
47 changes: 38 additions & 9 deletions cli/commands/replica.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@ import {spawn as spawnAsync} from 'promisify-child-process';
import {IDL} from '@dfinity/candid';
import {Actor, HttpAgent} from '@dfinity/agent';
import {PocketIc, PocketIcServer} from 'pic-ic';
import chalk from 'chalk';

import {readConfig} from '../mops.js';
import {toolchain} from './toolchain/index.js';
import {getDfxVersion} from '../helpers/get-dfx-version.js';

type StartOptions = {
type ?: 'dfx' | 'pocket-ic';
type ?: 'dfx' | 'pocket-ic' | 'dfx-pocket-ic';
dir ?: string;
verbose ?: boolean;
silent ?: boolean;
};

export class Replica {
type : 'dfx' | 'pocket-ic' = 'dfx';
type : 'dfx' | 'pocket-ic' | 'dfx-pocket-ic' = 'dfx';
verbose = false;
canisters : Record<string, {cwd : string; canisterId : string; actor : any; stream : PassThrough;}> = {};
pocketIcServer ?: PocketIcServer;
Expand All @@ -36,20 +38,33 @@ export class Replica {

silent || console.log(`Starting ${this.type} replica...`);

if (this.type == 'dfx') {
if (this.type === 'dfx' || this.type === 'dfx-pocket-ic') {
fs.mkdirSync(this.dir, {recursive: true});
fs.writeFileSync(path.join(this.dir, 'dfx.json'), JSON.stringify(this.dfxJson(''), null, 2));
fs.writeFileSync(path.join(this.dir, 'canister.did'), 'service : { runTests: () -> (); }');

await this.stop();

this.dfxProcess = spawn('dfx', ['start', '--clean', '--artificial-delay', '0', (this.verbose ? '' : '-qqqq')].filter(x => x), {cwd: this.dir});
this.dfxProcess = spawn('dfx', ['start', this.type === 'dfx-pocket-ic' ? '--pocketic' : '', '--clean', (this.verbose ? '' : '-qqqq'), '--artificial-delay', '0'].filter(x => x).flat(), {cwd: this.dir});

// process canister logs
this._attachCanisterLogHandler(this.dfxProcess);

this.dfxProcess.stdout.on('data', (data) => {
console.log('DFX:', data.toString());
if (this.verbose) {
console.log('DFX:', data.toString());
}
});

this.dfxProcess.stderr.on('data', (data) => {
if (this.verbose) {
console.error('DFX:', data.toString());
}
if (data.toString().includes('Failed to bind socket to')) {
console.error(chalk.red(data.toString()));
console.log('Please run again after some time');
process.exit(11);
}
});

// await for dfx to start
Expand Down Expand Up @@ -115,9 +130,22 @@ export class Replica {
}

async stop(sigint = false) {
if (this.type == 'dfx') {
this.dfxProcess?.kill();
// execSync('dfx stop' + (this.verbose ? '' : ' -qqqq'), {cwd: this.dir, timeout: 10_000, stdio: ['pipe', this.verbose ? 'inherit' : 'ignore', 'pipe']});
if (this.type === 'dfx' || this.type === 'dfx-pocket-ic') {
if (this.dfxProcess) {
this.dfxProcess.kill();
// give replica some time to stop
await new Promise((resolve) => {
setTimeout(resolve, 1000);
});
}

// if (!this.dfxProcess) {
// try {
// execSync('dfx killall', {cwd: this.dir, timeout: 3_000, stdio: ['pipe', this.verbose ? 'inherit' : 'ignore', 'pipe']});
// execSync('dfx stop' + (this.verbose ? '' : ' -qqqq'), {cwd: this.dir, timeout: 10_000, stdio: ['pipe', this.verbose ? 'inherit' : 'ignore', 'pipe']});
// }
// catch {}
// }
}
else if (this.pocketIc && this.pocketIcServer) {
if (!sigint) {
Expand All @@ -128,7 +156,7 @@ export class Replica {
}

async deploy(name : string, wasm : string, idlFactory : IDL.InterfaceFactory, cwd : string = process.cwd(), signal ?: AbortSignal) {
if (this.type === 'dfx') {
if (this.type === 'dfx' || this.type === 'dfx-pocket-ic') {
// prepare dfx.json for current canister
let dfxJson = path.join(this.dir, 'dfx.json');

Expand Down Expand Up @@ -253,6 +281,7 @@ export class Replica {
return {
version: 1,
canisters,
dfx: getDfxVersion(),
defaults: {
build: {
packtool: 'mops sources',
Expand Down
19 changes: 18 additions & 1 deletion cli/commands/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import chalk from 'chalk';
import {globSync} from 'glob';
import chokidar from 'chokidar';
import debounce from 'debounce';
import {SemVer} from 'semver';

import {sources} from '../sources.js';
import {getRootDir, readConfig} from '../../mops.js';
Expand All @@ -25,6 +26,7 @@ import {Replica} from '../replica.js';
import {ActorMethod} from '@dfinity/agent';
import {PassThrough, Readable} from 'node:stream';
import {TestMode} from '../../types.js';
import {getDfxVersion} from '../../helpers/get-dfx-version.js';

let ignore = [
'**/node_modules/**',
Expand All @@ -39,13 +41,14 @@ let globConfig = {
};

type ReporterName = 'verbose' | 'files' | 'compact' | 'silent';
type ReplicaName = 'dfx' | 'pocket-ic';
type ReplicaName = 'dfx' | 'pocket-ic' | 'dfx-pocket-ic';

type TestOptions = {
watch : boolean;
reporter : ReporterName;
mode : TestMode;
replica : ReplicaName;
debug : boolean;
};


Expand All @@ -66,7 +69,20 @@ export async function test(filter = '', options : Partial<TestOptions> = {}) {
let rootDir = getRootDir();

let replicaType = options.replica ?? (config.toolchain?.['pocket-ic'] ? 'pocket-ic' : 'dfx' as ReplicaName);

if (replicaType === 'pocket-ic' && !config.toolchain?.['pocket-ic']) {
let dfxVersion = getDfxVersion();
if (!dfxVersion || new SemVer(dfxVersion).compare('0.24.1') < 0) {
console.log(chalk.red('Please update dfx to the version >=0.24.1 or specify pocket-ic version in mops.toml'));
process.exit(1);
}
else {
replicaType = 'dfx-pocket-ic';
}
}

replica.type = replicaType;
replica.verbose = !!options.debug;

if (options.watch) {
replica.ttl = 60 * 15; // 15 minutes
Expand Down Expand Up @@ -202,6 +218,7 @@ export async function testWithReporter(reporterName : ReporterName | Reporter |
let testTempDir = path.join(getRootDir(), '.mops/.test/');
replica.dir = testTempDir;

fs.rmSync(testTempDir, {recursive: true, force: true});
fs.mkdirSync(testTempDir, {recursive: true});

await parallel(os.cpus().length, files, async (file : string) => {
Expand Down
2 changes: 1 addition & 1 deletion dfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"packtool": "mops sources"
}
},
"dfx": "0.24.0",
"dfx": "0.24.1",
"networks": {
"staging": {
"type": "persistent",
Expand Down
3 changes: 1 addition & 2 deletions mops.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,4 @@ bench = "1.0.0"

[toolchain]
moc = "0.12.1"
wasmtime = "23.0.1"
pocket-ic = "4.0.0"
wasmtime = "23.0.1"

0 comments on commit a998e6a

Please sign in to comment.