ic-mops 1.1.1 → 1.1.2-pre.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.ts +1 -0
- package/commands/replica.ts +38 -9
- package/commands/test/test.ts +18 -1
- package/dist/cli.js +1 -0
- package/dist/commands/replica.d.ts +3 -2
- package/dist/commands/replica.js +34 -7
- package/dist/commands/test/test.d.ts +2 -1
- package/dist/commands/test/test.js +14 -0
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/cli.ts
CHANGED
|
@@ -214,6 +214,7 @@ program
|
|
|
214
214
|
.addOption(new Option('--mode <mode>', 'Test mode').choices(['interpreter', 'wasi', 'replica']).default('interpreter'))
|
|
215
215
|
.addOption(new Option('--replica <replica>', 'Which replica to use to run tests in replica mode').choices(['dfx', 'pocket-ic']))
|
|
216
216
|
.option('-w, --watch', 'Enable watch mode')
|
|
217
|
+
.option('--debug', 'Show debug logs')
|
|
217
218
|
.action(async (filter, options) => {
|
|
218
219
|
checkConfigFile(true);
|
|
219
220
|
await installAll({silent: true, lock: 'ignore', installFromLockFile: true});
|
package/commands/replica.ts
CHANGED
|
@@ -8,19 +8,21 @@ import {spawn as spawnAsync} from 'promisify-child-process';
|
|
|
8
8
|
import {IDL} from '@dfinity/candid';
|
|
9
9
|
import {Actor, HttpAgent} from '@dfinity/agent';
|
|
10
10
|
import {PocketIc, PocketIcServer} from 'pic-ic';
|
|
11
|
+
import chalk from 'chalk';
|
|
11
12
|
|
|
12
13
|
import {readConfig} from '../mops.js';
|
|
13
14
|
import {toolchain} from './toolchain/index.js';
|
|
15
|
+
import {getDfxVersion} from '../helpers/get-dfx-version.js';
|
|
14
16
|
|
|
15
17
|
type StartOptions = {
|
|
16
|
-
type ?: 'dfx' | 'pocket-ic';
|
|
18
|
+
type ?: 'dfx' | 'pocket-ic' | 'dfx-pocket-ic';
|
|
17
19
|
dir ?: string;
|
|
18
20
|
verbose ?: boolean;
|
|
19
21
|
silent ?: boolean;
|
|
20
22
|
};
|
|
21
23
|
|
|
22
24
|
export class Replica {
|
|
23
|
-
type : 'dfx' | 'pocket-ic' = 'dfx';
|
|
25
|
+
type : 'dfx' | 'pocket-ic' | 'dfx-pocket-ic' = 'dfx';
|
|
24
26
|
verbose = false;
|
|
25
27
|
canisters : Record<string, {cwd : string; canisterId : string; actor : any; stream : PassThrough;}> = {};
|
|
26
28
|
pocketIcServer ?: PocketIcServer;
|
|
@@ -36,20 +38,33 @@ export class Replica {
|
|
|
36
38
|
|
|
37
39
|
silent || console.log(`Starting ${this.type} replica...`);
|
|
38
40
|
|
|
39
|
-
if (this.type
|
|
41
|
+
if (this.type === 'dfx' || this.type === 'dfx-pocket-ic') {
|
|
40
42
|
fs.mkdirSync(this.dir, {recursive: true});
|
|
41
43
|
fs.writeFileSync(path.join(this.dir, 'dfx.json'), JSON.stringify(this.dfxJson(''), null, 2));
|
|
42
44
|
fs.writeFileSync(path.join(this.dir, 'canister.did'), 'service : { runTests: () -> (); }');
|
|
43
45
|
|
|
44
46
|
await this.stop();
|
|
45
47
|
|
|
46
|
-
this.dfxProcess = spawn('dfx', ['start', '
|
|
48
|
+
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});
|
|
47
49
|
|
|
48
50
|
// process canister logs
|
|
49
51
|
this._attachCanisterLogHandler(this.dfxProcess);
|
|
50
52
|
|
|
51
53
|
this.dfxProcess.stdout.on('data', (data) => {
|
|
52
|
-
|
|
54
|
+
if (this.verbose) {
|
|
55
|
+
console.log('DFX:', data.toString());
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
this.dfxProcess.stderr.on('data', (data) => {
|
|
60
|
+
if (this.verbose) {
|
|
61
|
+
console.error('DFX:', data.toString());
|
|
62
|
+
}
|
|
63
|
+
if (data.toString().includes('Failed to bind socket to')) {
|
|
64
|
+
console.error(chalk.red(data.toString()));
|
|
65
|
+
console.log('Please run again after some time');
|
|
66
|
+
process.exit(11);
|
|
67
|
+
}
|
|
53
68
|
});
|
|
54
69
|
|
|
55
70
|
// await for dfx to start
|
|
@@ -115,9 +130,22 @@ export class Replica {
|
|
|
115
130
|
}
|
|
116
131
|
|
|
117
132
|
async stop(sigint = false) {
|
|
118
|
-
if (this.type
|
|
119
|
-
this.dfxProcess
|
|
120
|
-
|
|
133
|
+
if (this.type === 'dfx' || this.type === 'dfx-pocket-ic') {
|
|
134
|
+
if (this.dfxProcess) {
|
|
135
|
+
this.dfxProcess.kill();
|
|
136
|
+
// give replica some time to stop
|
|
137
|
+
await new Promise((resolve) => {
|
|
138
|
+
setTimeout(resolve, 1000);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// if (!this.dfxProcess) {
|
|
143
|
+
// try {
|
|
144
|
+
// execSync('dfx killall', {cwd: this.dir, timeout: 3_000, stdio: ['pipe', this.verbose ? 'inherit' : 'ignore', 'pipe']});
|
|
145
|
+
// execSync('dfx stop' + (this.verbose ? '' : ' -qqqq'), {cwd: this.dir, timeout: 10_000, stdio: ['pipe', this.verbose ? 'inherit' : 'ignore', 'pipe']});
|
|
146
|
+
// }
|
|
147
|
+
// catch {}
|
|
148
|
+
// }
|
|
121
149
|
}
|
|
122
150
|
else if (this.pocketIc && this.pocketIcServer) {
|
|
123
151
|
if (!sigint) {
|
|
@@ -128,7 +156,7 @@ export class Replica {
|
|
|
128
156
|
}
|
|
129
157
|
|
|
130
158
|
async deploy(name : string, wasm : string, idlFactory : IDL.InterfaceFactory, cwd : string = process.cwd(), signal ?: AbortSignal) {
|
|
131
|
-
if (this.type === 'dfx') {
|
|
159
|
+
if (this.type === 'dfx' || this.type === 'dfx-pocket-ic') {
|
|
132
160
|
// prepare dfx.json for current canister
|
|
133
161
|
let dfxJson = path.join(this.dir, 'dfx.json');
|
|
134
162
|
|
|
@@ -253,6 +281,7 @@ export class Replica {
|
|
|
253
281
|
return {
|
|
254
282
|
version: 1,
|
|
255
283
|
canisters,
|
|
284
|
+
dfx: getDfxVersion(),
|
|
256
285
|
defaults: {
|
|
257
286
|
build: {
|
|
258
287
|
packtool: 'mops sources',
|
package/commands/test/test.ts
CHANGED
|
@@ -8,6 +8,7 @@ import chalk from 'chalk';
|
|
|
8
8
|
import {globSync} from 'glob';
|
|
9
9
|
import chokidar from 'chokidar';
|
|
10
10
|
import debounce from 'debounce';
|
|
11
|
+
import {SemVer} from 'semver';
|
|
11
12
|
|
|
12
13
|
import {sources} from '../sources.js';
|
|
13
14
|
import {getRootDir, readConfig} from '../../mops.js';
|
|
@@ -25,6 +26,7 @@ import {Replica} from '../replica.js';
|
|
|
25
26
|
import {ActorMethod} from '@dfinity/agent';
|
|
26
27
|
import {PassThrough, Readable} from 'node:stream';
|
|
27
28
|
import {TestMode} from '../../types.js';
|
|
29
|
+
import {getDfxVersion} from '../../helpers/get-dfx-version.js';
|
|
28
30
|
|
|
29
31
|
let ignore = [
|
|
30
32
|
'**/node_modules/**',
|
|
@@ -39,13 +41,14 @@ let globConfig = {
|
|
|
39
41
|
};
|
|
40
42
|
|
|
41
43
|
type ReporterName = 'verbose' | 'files' | 'compact' | 'silent';
|
|
42
|
-
type ReplicaName = 'dfx' | 'pocket-ic';
|
|
44
|
+
type ReplicaName = 'dfx' | 'pocket-ic' | 'dfx-pocket-ic';
|
|
43
45
|
|
|
44
46
|
type TestOptions = {
|
|
45
47
|
watch : boolean;
|
|
46
48
|
reporter : ReporterName;
|
|
47
49
|
mode : TestMode;
|
|
48
50
|
replica : ReplicaName;
|
|
51
|
+
debug : boolean;
|
|
49
52
|
};
|
|
50
53
|
|
|
51
54
|
|
|
@@ -66,7 +69,20 @@ export async function test(filter = '', options : Partial<TestOptions> = {}) {
|
|
|
66
69
|
let rootDir = getRootDir();
|
|
67
70
|
|
|
68
71
|
let replicaType = options.replica ?? (config.toolchain?.['pocket-ic'] ? 'pocket-ic' : 'dfx' as ReplicaName);
|
|
72
|
+
|
|
73
|
+
if (replicaType === 'pocket-ic' && !config.toolchain?.['pocket-ic']) {
|
|
74
|
+
let dfxVersion = getDfxVersion();
|
|
75
|
+
if (!dfxVersion || new SemVer(dfxVersion).compare('0.24.1') < 0) {
|
|
76
|
+
console.log(chalk.red('Please update dfx to the version >=0.24.1 or specify pocket-ic version in mops.toml'));
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
replicaType = 'dfx-pocket-ic';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
69
84
|
replica.type = replicaType;
|
|
85
|
+
replica.verbose = !!options.debug;
|
|
70
86
|
|
|
71
87
|
if (options.watch) {
|
|
72
88
|
replica.ttl = 60 * 15; // 15 minutes
|
|
@@ -202,6 +218,7 @@ export async function testWithReporter(reporterName : ReporterName | Reporter |
|
|
|
202
218
|
let testTempDir = path.join(getRootDir(), '.mops/.test/');
|
|
203
219
|
replica.dir = testTempDir;
|
|
204
220
|
|
|
221
|
+
fs.rmSync(testTempDir, {recursive: true, force: true});
|
|
205
222
|
fs.mkdirSync(testTempDir, {recursive: true});
|
|
206
223
|
|
|
207
224
|
await parallel(os.cpus().length, files, async (file : string) => {
|
package/dist/cli.js
CHANGED
|
@@ -183,6 +183,7 @@ program
|
|
|
183
183
|
.addOption(new Option('--mode <mode>', 'Test mode').choices(['interpreter', 'wasi', 'replica']).default('interpreter'))
|
|
184
184
|
.addOption(new Option('--replica <replica>', 'Which replica to use to run tests in replica mode').choices(['dfx', 'pocket-ic']))
|
|
185
185
|
.option('-w, --watch', 'Enable watch mode')
|
|
186
|
+
.option('--debug', 'Show debug logs')
|
|
186
187
|
.action(async (filter, options) => {
|
|
187
188
|
checkConfigFile(true);
|
|
188
189
|
await installAll({ silent: true, lock: 'ignore', installFromLockFile: true });
|
|
@@ -3,13 +3,13 @@ import { PassThrough } from 'node:stream';
|
|
|
3
3
|
import { IDL } from '@dfinity/candid';
|
|
4
4
|
import { PocketIc, PocketIcServer } from 'pic-ic';
|
|
5
5
|
type StartOptions = {
|
|
6
|
-
type?: 'dfx' | 'pocket-ic';
|
|
6
|
+
type?: 'dfx' | 'pocket-ic' | 'dfx-pocket-ic';
|
|
7
7
|
dir?: string;
|
|
8
8
|
verbose?: boolean;
|
|
9
9
|
silent?: boolean;
|
|
10
10
|
};
|
|
11
11
|
export declare class Replica {
|
|
12
|
-
type: 'dfx' | 'pocket-ic';
|
|
12
|
+
type: 'dfx' | 'pocket-ic' | 'dfx-pocket-ic';
|
|
13
13
|
verbose: boolean;
|
|
14
14
|
canisters: Record<string, {
|
|
15
15
|
cwd: string;
|
|
@@ -43,6 +43,7 @@ export declare class Replica {
|
|
|
43
43
|
dfxJson(canisterName: string, wasmPath?: string, didPath?: string): {
|
|
44
44
|
version: number;
|
|
45
45
|
canisters: Record<string, any>;
|
|
46
|
+
dfx: string;
|
|
46
47
|
defaults: {
|
|
47
48
|
build: {
|
|
48
49
|
packtool: string;
|
package/dist/commands/replica.js
CHANGED
|
@@ -6,8 +6,10 @@ import { PassThrough } from 'node:stream';
|
|
|
6
6
|
import { spawn as spawnAsync } from 'promisify-child-process';
|
|
7
7
|
import { Actor, HttpAgent } from '@dfinity/agent';
|
|
8
8
|
import { PocketIc, PocketIcServer } from 'pic-ic';
|
|
9
|
+
import chalk from 'chalk';
|
|
9
10
|
import { readConfig } from '../mops.js';
|
|
10
11
|
import { toolchain } from './toolchain/index.js';
|
|
12
|
+
import { getDfxVersion } from '../helpers/get-dfx-version.js';
|
|
11
13
|
export class Replica {
|
|
12
14
|
constructor() {
|
|
13
15
|
this.type = 'dfx';
|
|
@@ -21,16 +23,28 @@ export class Replica {
|
|
|
21
23
|
this.verbose = verbose ?? this.verbose;
|
|
22
24
|
this.dir = dir ?? this.dir;
|
|
23
25
|
silent || console.log(`Starting ${this.type} replica...`);
|
|
24
|
-
if (this.type
|
|
26
|
+
if (this.type === 'dfx' || this.type === 'dfx-pocket-ic') {
|
|
25
27
|
fs.mkdirSync(this.dir, { recursive: true });
|
|
26
28
|
fs.writeFileSync(path.join(this.dir, 'dfx.json'), JSON.stringify(this.dfxJson(''), null, 2));
|
|
27
29
|
fs.writeFileSync(path.join(this.dir, 'canister.did'), 'service : { runTests: () -> (); }');
|
|
28
30
|
await this.stop();
|
|
29
|
-
this.dfxProcess = spawn('dfx', ['start', '
|
|
31
|
+
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 });
|
|
30
32
|
// process canister logs
|
|
31
33
|
this._attachCanisterLogHandler(this.dfxProcess);
|
|
32
34
|
this.dfxProcess.stdout.on('data', (data) => {
|
|
33
|
-
|
|
35
|
+
if (this.verbose) {
|
|
36
|
+
console.log('DFX:', data.toString());
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
this.dfxProcess.stderr.on('data', (data) => {
|
|
40
|
+
if (this.verbose) {
|
|
41
|
+
console.error('DFX:', data.toString());
|
|
42
|
+
}
|
|
43
|
+
if (data.toString().includes('Failed to bind socket to')) {
|
|
44
|
+
console.error(chalk.red(data.toString()));
|
|
45
|
+
console.log('Please run again after some time');
|
|
46
|
+
process.exit(11);
|
|
47
|
+
}
|
|
34
48
|
});
|
|
35
49
|
// await for dfx to start
|
|
36
50
|
let ok = false;
|
|
@@ -87,9 +101,21 @@ export class Replica {
|
|
|
87
101
|
});
|
|
88
102
|
}
|
|
89
103
|
async stop(sigint = false) {
|
|
90
|
-
if (this.type
|
|
91
|
-
this.dfxProcess
|
|
92
|
-
|
|
104
|
+
if (this.type === 'dfx' || this.type === 'dfx-pocket-ic') {
|
|
105
|
+
if (this.dfxProcess) {
|
|
106
|
+
this.dfxProcess.kill();
|
|
107
|
+
// give replica some time to stop
|
|
108
|
+
await new Promise((resolve) => {
|
|
109
|
+
setTimeout(resolve, 1000);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
// if (!this.dfxProcess) {
|
|
113
|
+
// try {
|
|
114
|
+
// execSync('dfx killall', {cwd: this.dir, timeout: 3_000, stdio: ['pipe', this.verbose ? 'inherit' : 'ignore', 'pipe']});
|
|
115
|
+
// execSync('dfx stop' + (this.verbose ? '' : ' -qqqq'), {cwd: this.dir, timeout: 10_000, stdio: ['pipe', this.verbose ? 'inherit' : 'ignore', 'pipe']});
|
|
116
|
+
// }
|
|
117
|
+
// catch {}
|
|
118
|
+
// }
|
|
93
119
|
}
|
|
94
120
|
else if (this.pocketIc && this.pocketIcServer) {
|
|
95
121
|
if (!sigint) {
|
|
@@ -99,7 +125,7 @@ export class Replica {
|
|
|
99
125
|
}
|
|
100
126
|
}
|
|
101
127
|
async deploy(name, wasm, idlFactory, cwd = process.cwd(), signal) {
|
|
102
|
-
if (this.type === 'dfx') {
|
|
128
|
+
if (this.type === 'dfx' || this.type === 'dfx-pocket-ic') {
|
|
103
129
|
// prepare dfx.json for current canister
|
|
104
130
|
let dfxJson = path.join(this.dir, 'dfx.json');
|
|
105
131
|
let oldDfxJsonData;
|
|
@@ -202,6 +228,7 @@ export class Replica {
|
|
|
202
228
|
return {
|
|
203
229
|
version: 1,
|
|
204
230
|
canisters,
|
|
231
|
+
dfx: getDfxVersion(),
|
|
205
232
|
defaults: {
|
|
206
233
|
build: {
|
|
207
234
|
packtool: 'mops sources',
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Reporter } from './reporters/reporter.js';
|
|
2
2
|
import { TestMode } from '../../types.js';
|
|
3
3
|
type ReporterName = 'verbose' | 'files' | 'compact' | 'silent';
|
|
4
|
-
type ReplicaName = 'dfx' | 'pocket-ic';
|
|
4
|
+
type ReplicaName = 'dfx' | 'pocket-ic' | 'dfx-pocket-ic';
|
|
5
5
|
type TestOptions = {
|
|
6
6
|
watch: boolean;
|
|
7
7
|
reporter: ReporterName;
|
|
8
8
|
mode: TestMode;
|
|
9
9
|
replica: ReplicaName;
|
|
10
|
+
debug: boolean;
|
|
10
11
|
};
|
|
11
12
|
export declare function test(filter?: string, options?: Partial<TestOptions>): Promise<void>;
|
|
12
13
|
export declare function testWithReporter(reporterName: ReporterName | Reporter | undefined, filter: string | undefined, defaultMode: TestMode | undefined, replicaType: ReplicaName, watch?: boolean, signal?: AbortSignal): Promise<boolean>;
|
|
@@ -7,6 +7,7 @@ import chalk from 'chalk';
|
|
|
7
7
|
import { globSync } from 'glob';
|
|
8
8
|
import chokidar from 'chokidar';
|
|
9
9
|
import debounce from 'debounce';
|
|
10
|
+
import { SemVer } from 'semver';
|
|
10
11
|
import { sources } from '../sources.js';
|
|
11
12
|
import { getRootDir, readConfig } from '../../mops.js';
|
|
12
13
|
import { parallel } from '../../parallel.js';
|
|
@@ -19,6 +20,7 @@ import { SilentReporter } from './reporters/silent-reporter.js';
|
|
|
19
20
|
import { toolchain } from '../toolchain/index.js';
|
|
20
21
|
import { Replica } from '../replica.js';
|
|
21
22
|
import { PassThrough } from 'node:stream';
|
|
23
|
+
import { getDfxVersion } from '../../helpers/get-dfx-version.js';
|
|
22
24
|
let ignore = [
|
|
23
25
|
'**/node_modules/**',
|
|
24
26
|
'**/.mops/**',
|
|
@@ -43,7 +45,18 @@ export async function test(filter = '', options = {}) {
|
|
|
43
45
|
let config = readConfig();
|
|
44
46
|
let rootDir = getRootDir();
|
|
45
47
|
let replicaType = options.replica ?? (config.toolchain?.['pocket-ic'] ? 'pocket-ic' : 'dfx');
|
|
48
|
+
if (replicaType === 'pocket-ic' && !config.toolchain?.['pocket-ic']) {
|
|
49
|
+
let dfxVersion = getDfxVersion();
|
|
50
|
+
if (!dfxVersion || new SemVer(dfxVersion).compare('0.24.1') < 0) {
|
|
51
|
+
console.log(chalk.red('Please update dfx to the version >=0.24.1 or specify pocket-ic version in mops.toml'));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
replicaType = 'dfx-pocket-ic';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
46
58
|
replica.type = replicaType;
|
|
59
|
+
replica.verbose = !!options.debug;
|
|
47
60
|
if (options.watch) {
|
|
48
61
|
replica.ttl = 60 * 15; // 15 minutes
|
|
49
62
|
let sigint = false;
|
|
@@ -156,6 +169,7 @@ export async function testWithReporter(reporterName, filter = '', defaultMode =
|
|
|
156
169
|
}
|
|
157
170
|
let testTempDir = path.join(getRootDir(), '.mops/.test/');
|
|
158
171
|
replica.dir = testTempDir;
|
|
172
|
+
fs.rmSync(testTempDir, { recursive: true, force: true });
|
|
159
173
|
fs.mkdirSync(testTempDir, { recursive: true });
|
|
160
174
|
await parallel(os.cpus().length, files, async (file) => {
|
|
161
175
|
if (signal?.aborted) {
|
package/dist/package.json
CHANGED