ic-mops 1.11.1 → 2.0.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/.DS_Store +0 -0
- package/.eslintrc.json +7 -7
- package/CHANGELOG.md +15 -0
- package/api/actors.ts +41 -37
- package/api/downloadPackageFiles.ts +75 -61
- package/api/getHighestVersion.ts +5 -5
- package/api/index.ts +4 -4
- package/api/network.ts +19 -21
- package/api/resolveVersion.ts +14 -11
- package/bin/mops.js +1 -1
- package/bun.lock +234 -198
- package/bundle/bench/bench-canister.mo +2 -2
- package/bundle/bench/user-bench.mo +0 -4
- package/bundle/bin/mops.js +1 -1
- package/bundle/cli.js +1000 -924
- package/bundle/cli.tgz +0 -0
- package/bundle/declarations/bench/bench.did +3 -3
- package/bundle/declarations/bench/bench.did.d.ts +3 -3
- package/bundle/declarations/bench/index.d.ts +3 -3
- package/bundle/declarations/bench/index.js +1 -1
- package/bundle/declarations/main/index.d.ts +3 -3
- package/bundle/declarations/main/index.js +1 -1
- package/bundle/declarations/main/main.did +78 -121
- package/bundle/declarations/main/main.did.d.ts +48 -98
- package/bundle/declarations/main/main.did.js +53 -107
- package/bundle/declarations/storage/index.d.ts +3 -3
- package/bundle/declarations/storage/index.js +4 -4
- package/bundle/declarations/storage/storage.did.d.ts +3 -3
- package/bundle/package.json +6 -5
- package/bundle/templates/mops-publish.yml +3 -3
- package/bundle/templates/mops-test.yml +3 -3
- package/bundle-package-json.ts +8 -8
- package/cache.ts +80 -65
- package/check-requirements.ts +49 -45
- package/cli.ts +577 -376
- package/commands/add.ts +142 -129
- package/commands/available-updates.ts +55 -28
- package/commands/bench/bench-canister.mo +114 -108
- package/commands/bench/user-bench.mo +6 -6
- package/commands/bench-replica.ts +146 -106
- package/commands/bench.ts +563 -497
- package/commands/build.ts +177 -0
- package/commands/bump.ts +68 -57
- package/commands/check-candid.ts +24 -0
- package/commands/docs-coverage.ts +124 -102
- package/commands/docs.ts +118 -108
- package/commands/format.ts +171 -155
- package/commands/init.ts +301 -275
- package/commands/install/install-all.ts +75 -62
- package/commands/install/install-dep.ts +43 -28
- package/commands/install/install-deps.ts +23 -15
- package/commands/install/install-local-dep.ts +42 -34
- package/commands/install/install-mops-dep.ts +154 -123
- package/commands/install/sync-local-cache.ts +39 -35
- package/commands/maintainer.ts +109 -99
- package/commands/outdated.ts +31 -18
- package/commands/owner.ts +107 -99
- package/commands/publish.ts +534 -443
- package/commands/remove.ts +119 -89
- package/commands/replica.ts +391 -303
- package/commands/search.ts +42 -36
- package/commands/self.ts +63 -56
- package/commands/sources.ts +66 -49
- package/commands/sync.ts +92 -75
- package/commands/template.ts +145 -102
- package/commands/test/mmf1.ts +146 -119
- package/commands/test/reporters/compact-reporter.ts +87 -84
- package/commands/test/reporters/files-reporter.ts +56 -51
- package/commands/test/reporters/reporter.ts +12 -6
- package/commands/test/reporters/silent-reporter.ts +58 -59
- package/commands/test/reporters/verbose-reporter.ts +66 -54
- package/commands/test/test.ts +497 -460
- package/commands/test/utils.ts +85 -6
- package/commands/toolchain/index.ts +363 -322
- package/commands/toolchain/moc.ts +78 -50
- package/commands/toolchain/pocket-ic.ts +41 -34
- package/commands/toolchain/toolchain-utils.ts +92 -72
- package/commands/toolchain/wasmtime.ts +37 -34
- package/commands/update.ts +91 -56
- package/commands/user.ts +90 -81
- package/commands/watch/deployer.ts +188 -152
- package/commands/watch/error-checker.ts +90 -80
- package/commands/watch/formatter.ts +72 -60
- package/commands/watch/generator.ts +116 -96
- package/commands/watch/globMoFiles.ts +13 -13
- package/commands/watch/parseDfxJson.ts +63 -57
- package/commands/watch/tester.ts +83 -65
- package/commands/watch/warning-checker.ts +149 -136
- package/commands/watch/watch.ts +123 -95
- package/declarations/bench/bench.did.d.ts +3 -3
- package/declarations/bench/index.d.ts +3 -3
- package/declarations/bench/index.js +1 -1
- package/declarations/main/index.d.ts +3 -3
- package/declarations/main/index.js +1 -1
- package/declarations/main/main.did.d.ts +3 -3
- package/declarations/storage/index.d.ts +3 -3
- package/declarations/storage/index.js +4 -4
- package/declarations/storage/storage.did.d.ts +3 -3
- package/dist/api/actors.d.ts +4 -4
- package/dist/api/actors.js +8 -8
- package/dist/api/downloadPackageFiles.d.ts +2 -2
- package/dist/api/downloadPackageFiles.js +10 -10
- package/dist/api/getHighestVersion.js +1 -1
- package/dist/api/index.d.ts +4 -4
- package/dist/api/index.js +4 -4
- package/dist/api/network.js +9 -9
- package/dist/api/resolveVersion.js +3 -3
- package/dist/bin/mops.js +1 -1
- package/dist/bundle-package-json.js +8 -8
- package/dist/cache.js +22 -17
- package/dist/check-requirements.js +11 -11
- package/dist/cli.js +283 -186
- package/dist/commands/add.d.ts +1 -1
- package/dist/commands/add.js +41 -38
- package/dist/commands/available-updates.d.ts +1 -1
- package/dist/commands/available-updates.js +32 -14
- package/dist/commands/bench/bench-canister.mo +114 -108
- package/dist/commands/bench/user-bench.mo +6 -6
- package/dist/commands/bench-replica.d.ts +6 -5
- package/dist/commands/bench-replica.js +58 -36
- package/dist/commands/bench.d.ts +5 -5
- package/dist/commands/bench.js +134 -118
- package/dist/commands/build.d.ts +7 -0
- package/dist/commands/build.js +121 -0
- package/dist/commands/bump.js +27 -18
- package/dist/commands/check-candid.d.ts +4 -0
- package/dist/commands/check-candid.js +15 -0
- package/dist/commands/docs-coverage.d.ts +1 -1
- package/dist/commands/docs-coverage.js +45 -31
- package/dist/commands/docs.d.ts +1 -1
- package/dist/commands/docs.js +39 -38
- package/dist/commands/format.js +31 -27
- package/dist/commands/init.js +102 -92
- package/dist/commands/install/install-all.d.ts +2 -2
- package/dist/commands/install/install-all.js +23 -21
- package/dist/commands/install/install-dep.d.ts +1 -1
- package/dist/commands/install/install-dep.js +21 -8
- package/dist/commands/install/install-deps.d.ts +1 -1
- package/dist/commands/install/install-deps.js +1 -1
- package/dist/commands/install/install-local-dep.js +11 -9
- package/dist/commands/install/install-mops-dep.d.ts +1 -1
- package/dist/commands/install/install-mops-dep.js +32 -27
- package/dist/commands/install/sync-local-cache.js +10 -10
- package/dist/commands/maintainer.js +21 -21
- package/dist/commands/outdated.js +16 -6
- package/dist/commands/owner.js +21 -21
- package/dist/commands/publish.js +148 -128
- package/dist/commands/remove.d.ts +1 -1
- package/dist/commands/remove.js +42 -30
- package/dist/commands/replica.d.ts +9 -8
- package/dist/commands/replica.js +105 -65
- package/dist/commands/search.js +15 -13
- package/dist/commands/self.js +31 -28
- package/dist/commands/sources.d.ts +5 -1
- package/dist/commands/sources.js +23 -17
- package/dist/commands/sync.d.ts +1 -1
- package/dist/commands/sync.js +38 -25
- package/dist/commands/template.js +66 -56
- package/dist/commands/test/mmf1.d.ts +3 -3
- package/dist/commands/test/mmf1.js +33 -31
- package/dist/commands/test/reporters/compact-reporter.d.ts +3 -3
- package/dist/commands/test/reporters/compact-reporter.js +19 -15
- package/dist/commands/test/reporters/files-reporter.d.ts +3 -3
- package/dist/commands/test/reporters/files-reporter.js +18 -14
- package/dist/commands/test/reporters/reporter.d.ts +2 -2
- package/dist/commands/test/reporters/silent-reporter.d.ts +3 -3
- package/dist/commands/test/reporters/silent-reporter.js +4 -4
- package/dist/commands/test/reporters/verbose-reporter.d.ts +3 -3
- package/dist/commands/test/reporters/verbose-reporter.js +17 -13
- package/dist/commands/test/test.d.ts +4 -4
- package/dist/commands/test/test.js +151 -181
- package/dist/commands/test/utils.d.ts +6 -0
- package/dist/commands/test/utils.js +63 -2
- package/dist/commands/toolchain/index.d.ts +1 -1
- package/dist/commands/toolchain/index.js +81 -69
- package/dist/commands/toolchain/moc.d.ts +1 -1
- package/dist/commands/toolchain/moc.js +48 -24
- package/dist/commands/toolchain/pocket-ic.js +12 -12
- package/dist/commands/toolchain/toolchain-utils.d.ts +2 -0
- package/dist/commands/toolchain/toolchain-utils.js +32 -23
- package/dist/commands/toolchain/wasmtime.js +11 -11
- package/dist/commands/update.d.ts +1 -1
- package/dist/commands/update.js +30 -12
- package/dist/commands/user.js +31 -28
- package/dist/commands/watch/deployer.d.ts +4 -4
- package/dist/commands/watch/deployer.js +45 -36
- package/dist/commands/watch/error-checker.d.ts +2 -2
- package/dist/commands/watch/error-checker.js +27 -27
- package/dist/commands/watch/formatter.d.ts +4 -4
- package/dist/commands/watch/formatter.js +17 -17
- package/dist/commands/watch/generator.d.ts +3 -3
- package/dist/commands/watch/generator.js +28 -23
- package/dist/commands/watch/globMoFiles.js +8 -8
- package/dist/commands/watch/parseDfxJson.d.ts +2 -2
- package/dist/commands/watch/parseDfxJson.js +9 -9
- package/dist/commands/watch/tester.d.ts +4 -4
- package/dist/commands/watch/tester.js +23 -21
- package/dist/commands/watch/warning-checker.d.ts +3 -3
- package/dist/commands/watch/warning-checker.js +36 -36
- package/dist/commands/watch/watch.js +45 -32
- package/dist/declarations/bench/bench.did.d.ts +3 -3
- package/dist/declarations/bench/index.d.ts +3 -3
- package/dist/declarations/bench/index.js +1 -1
- package/dist/declarations/main/index.d.ts +3 -3
- package/dist/declarations/main/index.js +1 -1
- package/dist/declarations/main/main.did.d.ts +3 -3
- package/dist/declarations/storage/index.d.ts +3 -3
- package/dist/declarations/storage/index.js +4 -4
- package/dist/declarations/storage/storage.did.d.ts +3 -3
- package/dist/environments/nodejs/cli.d.ts +1 -0
- package/dist/environments/nodejs/cli.js +4 -0
- package/dist/environments/web/cli.d.ts +1 -0
- package/dist/environments/web/cli.js +4 -0
- package/dist/error.d.ts +1 -0
- package/dist/error.js +5 -0
- package/dist/fix-dist.js +5 -5
- package/dist/helpers/find-changelog-entry.js +8 -5
- package/dist/helpers/get-dep-name.d.ts +1 -0
- package/dist/helpers/get-dep-name.js +4 -1
- package/dist/helpers/get-dfx-version.js +4 -4
- package/dist/helpers/get-moc-path.js +8 -7
- package/dist/helpers/get-moc-version.js +10 -7
- package/dist/helpers/get-package-id.js +2 -2
- package/dist/helpers/is-candid-compatible.d.ts +1 -0
- package/dist/helpers/is-candid-compatible.js +20 -0
- package/dist/integrity.d.ts +1 -1
- package/dist/integrity.js +47 -38
- package/dist/jest.config.d.ts +11 -0
- package/dist/jest.config.js +14 -0
- package/dist/mops.d.ts +6 -6
- package/dist/mops.js +87 -80
- package/dist/notify-installs.js +4 -4
- package/dist/package.json +11 -10
- package/dist/pem.d.ts +3 -3
- package/dist/pem.js +20 -12
- package/dist/release-cli.js +20 -20
- package/dist/resolve-packages.d.ts +1 -1
- package/dist/resolve-packages.js +52 -36
- package/dist/templates/mops-publish.yml +3 -3
- package/dist/templates/mops-test.yml +3 -3
- package/dist/templates/src/lib.mo +13 -13
- package/dist/templates/test/lib.test.mo +2 -2
- package/dist/templates.js +1 -1
- package/dist/tests/cli.test.d.ts +1 -0
- package/dist/tests/cli.test.js +63 -0
- package/dist/types.d.ts +14 -4
- package/dist/vessel.d.ts +2 -2
- package/dist/vessel.js +41 -34
- package/dist/wasm/pkg/bundler/package.json +20 -0
- package/dist/wasm/pkg/bundler/wasm.d.ts +3 -0
- package/dist/wasm/pkg/bundler/wasm.js +5 -0
- package/dist/wasm/pkg/bundler/wasm_bg.js +93 -0
- package/dist/wasm/pkg/bundler/wasm_bg.wasm +0 -0
- package/dist/wasm/pkg/bundler/wasm_bg.wasm.d.ts +8 -0
- package/dist/wasm/pkg/nodejs/package.json +14 -0
- package/dist/wasm/pkg/nodejs/wasm.d.ts +3 -0
- package/dist/wasm/pkg/nodejs/wasm.js +98 -0
- package/dist/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
- package/dist/wasm/pkg/nodejs/wasm_bg.wasm.d.ts +8 -0
- package/dist/wasm/pkg/web/package.json +18 -0
- package/dist/wasm/pkg/web/wasm.d.ts +35 -0
- package/dist/wasm/pkg/web/wasm.js +191 -0
- package/dist/wasm/pkg/web/wasm_bg.wasm +0 -0
- package/dist/wasm/pkg/web/wasm_bg.wasm.d.ts +8 -0
- package/dist/wasm.d.ts +5 -0
- package/dist/wasm.js +10 -0
- package/environments/nodejs/cli.ts +6 -0
- package/environments/web/cli.ts +6 -0
- package/error.ts +6 -0
- package/fix-dist.ts +5 -5
- package/global.d.ts +3 -3
- package/helpers/find-changelog-entry.ts +26 -23
- package/helpers/get-dep-name.ts +7 -3
- package/helpers/get-dfx-version.ts +8 -9
- package/helpers/get-moc-path.ts +25 -26
- package/helpers/get-moc-version.ts +21 -19
- package/helpers/get-package-id.ts +4 -4
- package/helpers/is-candid-compatible.ts +22 -0
- package/integrity.ts +270 -236
- package/jest.config.js +14 -0
- package/mops.ts +238 -215
- package/notify-installs.ts +16 -17
- package/package.json +21 -15
- package/parallel.ts +28 -24
- package/pem.ts +55 -47
- package/release-cli.ts +73 -39
- package/resolve-packages.ts +231 -189
- package/templates/mops-publish.yml +3 -3
- package/templates/mops-test.yml +3 -3
- package/templates/src/lib.mo +13 -13
- package/templates/test/lib.test.mo +2 -2
- package/templates.ts +4 -4
- package/tests/__snapshots__/cli.test.ts.snap +202 -0
- package/tests/build/error/candid/bar.did +3 -0
- package/tests/build/error/dfx.json +12 -0
- package/tests/build/error/mops.toml +9 -0
- package/tests/build/error/src/Bar.mo +5 -0
- package/tests/build/error/src/Foo.mo +5 -0
- package/tests/build/success/.dfx/local/canister_ids.json +17 -0
- package/tests/build/success/.dfx/local/canisters/bar/bar.did +3 -0
- package/tests/build/success/.dfx/local/canisters/bar/bar.most +4 -0
- package/tests/build/success/.dfx/local/canisters/bar/bar.wasm +0 -0
- package/tests/build/success/.dfx/local/canisters/bar/constructor.did +3 -0
- package/tests/build/success/.dfx/local/canisters/bar/index.js +42 -0
- package/tests/build/success/.dfx/local/canisters/bar/init_args.txt +1 -0
- package/tests/build/success/.dfx/local/canisters/bar/service.did +3 -0
- package/tests/build/success/.dfx/local/canisters/bar/service.did.d.ts +7 -0
- package/tests/build/success/.dfx/local/canisters/bar/service.did.js +4 -0
- package/tests/build/success/.dfx/local/canisters/foo/constructor.did +3 -0
- package/tests/build/success/.dfx/local/canisters/foo/foo.did +3 -0
- package/tests/build/success/.dfx/local/canisters/foo/foo.most +4 -0
- package/tests/build/success/.dfx/local/canisters/foo/foo.wasm +0 -0
- package/tests/build/success/.dfx/local/canisters/foo/index.js +42 -0
- package/tests/build/success/.dfx/local/canisters/foo/init_args.txt +1 -0
- package/tests/build/success/.dfx/local/canisters/foo/service.did +3 -0
- package/tests/build/success/.dfx/local/canisters/foo/service.did.d.ts +7 -0
- package/tests/build/success/.dfx/local/canisters/foo/service.did.js +4 -0
- package/tests/build/success/.dfx/local/lsp/ucwa4-rx777-77774-qaada-cai.did +3 -0
- package/tests/build/success/.dfx/local/lsp/ulvla-h7777-77774-qaacq-cai.did +3 -0
- package/tests/build/success/.dfx/local/network-id +4 -0
- package/tests/build/success/candid/bar.did +3 -0
- package/tests/build/success/dfx.json +12 -0
- package/tests/build/success/mops.toml +9 -0
- package/tests/build/success/src/Bar.mo +5 -0
- package/tests/build/success/src/Foo.mo +5 -0
- package/tests/check-candid/a.did +3 -0
- package/tests/check-candid/b.did +5 -0
- package/tests/check-candid/c.did +3 -0
- package/tests/cli.test.ts +82 -0
- package/tsconfig.json +26 -19
- package/types.ts +41 -31
- package/vessel.ts +219 -187
- package/wasm/Cargo.lock +1475 -0
- package/wasm/Cargo.toml +28 -0
- package/wasm/pkg/bundler/package.json +20 -0
- package/wasm/pkg/bundler/wasm.d.ts +3 -0
- package/wasm/pkg/bundler/wasm.js +5 -0
- package/wasm/pkg/bundler/wasm_bg.js +93 -0
- package/wasm/pkg/bundler/wasm_bg.wasm +0 -0
- package/wasm/pkg/bundler/wasm_bg.wasm.d.ts +8 -0
- package/wasm/pkg/nodejs/package.json +14 -0
- package/wasm/pkg/nodejs/wasm.d.ts +3 -0
- package/wasm/pkg/nodejs/wasm.js +98 -0
- package/wasm/pkg/nodejs/wasm_bg.wasm +0 -0
- package/wasm/pkg/nodejs/wasm_bg.wasm.d.ts +8 -0
- package/wasm/pkg/web/package.json +18 -0
- package/wasm/pkg/web/wasm.d.ts +35 -0
- package/wasm/pkg/web/wasm.js +191 -0
- package/wasm/pkg/web/wasm_bg.wasm +0 -0
- package/wasm/pkg/web/wasm_bg.wasm.d.ts +8 -0
- package/wasm/src/lib.rs +17 -0
- package/wasm.ts +16 -0
package/commands/test/test.ts
CHANGED
|
@@ -1,479 +1,516 @@
|
|
|
1
|
-
import process from
|
|
2
|
-
import {spawn
|
|
3
|
-
import path from
|
|
4
|
-
import fs from
|
|
5
|
-
import os from
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import { PassThrough } from "node:stream";
|
|
7
|
+
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
import { globSync } from "glob";
|
|
10
|
+
import chokidar from "chokidar";
|
|
11
|
+
import debounce from "debounce";
|
|
12
|
+
import { SemVer } from "semver";
|
|
13
|
+
import { ActorMethod } from "@icp-sdk/core/agent";
|
|
14
|
+
|
|
15
|
+
import { sources } from "../sources.js";
|
|
16
|
+
import { getRootDir, readConfig } from "../../mops.js";
|
|
17
|
+
import { parallel } from "../../parallel.js";
|
|
18
|
+
|
|
19
|
+
import { MMF1 } from "./mmf1.js";
|
|
20
|
+
import {
|
|
21
|
+
absToRel,
|
|
22
|
+
pipeMMF,
|
|
23
|
+
pipeStderrToMMF,
|
|
24
|
+
pipeStdoutToMMF,
|
|
25
|
+
} from "./utils.js";
|
|
26
|
+
import { Reporter } from "./reporters/reporter.js";
|
|
27
|
+
import { VerboseReporter } from "./reporters/verbose-reporter.js";
|
|
28
|
+
import { FilesReporter } from "./reporters/files-reporter.js";
|
|
29
|
+
import { CompactReporter } from "./reporters/compact-reporter.js";
|
|
30
|
+
import { SilentReporter } from "./reporters/silent-reporter.js";
|
|
31
|
+
import { toolchain } from "../toolchain/index.js";
|
|
32
|
+
import { Replica } from "../replica.js";
|
|
33
|
+
import { TestMode } from "../../types.js";
|
|
34
|
+
import { getDfxVersion } from "../../helpers/get-dfx-version.js";
|
|
30
35
|
|
|
31
36
|
let ignore = [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
"**/node_modules/**",
|
|
38
|
+
"**/.mops/**",
|
|
39
|
+
"**/.vessel/**",
|
|
40
|
+
"**/.git/**",
|
|
36
41
|
];
|
|
37
42
|
|
|
38
43
|
let globConfig = {
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
nocase: true,
|
|
45
|
+
ignore: ignore,
|
|
41
46
|
};
|
|
42
47
|
|
|
43
|
-
type ReporterName =
|
|
44
|
-
type ReplicaName =
|
|
48
|
+
type ReporterName = "verbose" | "files" | "compact" | "silent";
|
|
49
|
+
type ReplicaName = "dfx" | "pocket-ic" | "dfx-pocket-ic";
|
|
45
50
|
|
|
46
51
|
type TestOptions = {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
watch: boolean;
|
|
53
|
+
reporter: ReporterName;
|
|
54
|
+
mode: TestMode;
|
|
55
|
+
replica: ReplicaName;
|
|
56
|
+
verbose: boolean;
|
|
52
57
|
};
|
|
53
58
|
|
|
54
|
-
|
|
55
59
|
let replica = new Replica();
|
|
56
|
-
let replicaStartPromise
|
|
57
|
-
|
|
58
|
-
async function startReplicaOnce(replica
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export async function test(filter = '', options : Partial<TestOptions> = {}) {
|
|
68
|
-
let config = readConfig();
|
|
69
|
-
let rootDir = getRootDir();
|
|
70
|
-
|
|
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
|
-
|
|
84
|
-
replica.type = replicaType;
|
|
85
|
-
replica.verbose = !!options.verbose;
|
|
86
|
-
|
|
87
|
-
if (options.watch) {
|
|
88
|
-
replica.ttl = 60 * 15; // 15 minutes
|
|
89
|
-
|
|
90
|
-
let sigint = false;
|
|
91
|
-
process.on('SIGINT', () => {
|
|
92
|
-
if (sigint) {
|
|
93
|
-
console.log('Force exit');
|
|
94
|
-
process.exit(0);
|
|
95
|
-
}
|
|
96
|
-
sigint = true;
|
|
97
|
-
|
|
98
|
-
if (replicaStartPromise) {
|
|
99
|
-
console.log('Stopping replica...');
|
|
100
|
-
replica.stop(true).then(() => {
|
|
101
|
-
process.exit(0);
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
process.exit(0);
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// todo: run only changed for *.test.mo?
|
|
110
|
-
// todo: run all for *.mo?
|
|
111
|
-
|
|
112
|
-
let curRun = Promise.resolve(true);
|
|
113
|
-
let controller = new AbortController();
|
|
114
|
-
|
|
115
|
-
let run = debounce(async () => {
|
|
116
|
-
controller.abort();
|
|
117
|
-
await curRun;
|
|
118
|
-
|
|
119
|
-
console.clear();
|
|
120
|
-
process.stdout.write('\x1Bc');
|
|
121
|
-
|
|
122
|
-
controller = new AbortController();
|
|
123
|
-
curRun = runAll(options.reporter, filter, options.mode, replicaType, true, controller.signal);
|
|
124
|
-
await curRun;
|
|
125
|
-
|
|
126
|
-
console.log('-'.repeat(50));
|
|
127
|
-
console.log('Waiting for file changes...');
|
|
128
|
-
console.log(chalk.gray((`Press ${chalk.gray('Ctrl+C')} to exit.`)));
|
|
129
|
-
}, 200);
|
|
130
|
-
|
|
131
|
-
let watcher = chokidar.watch([
|
|
132
|
-
path.join(rootDir, '**/*.mo'),
|
|
133
|
-
path.join(rootDir, 'mops.toml'),
|
|
134
|
-
], {
|
|
135
|
-
ignored: ignore,
|
|
136
|
-
ignoreInitial: true,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
watcher.on('all', () => {
|
|
140
|
-
run();
|
|
141
|
-
});
|
|
142
|
-
run();
|
|
143
|
-
}
|
|
144
|
-
else {
|
|
145
|
-
let passed = await runAll(options.reporter, filter, options.mode, replicaType);
|
|
146
|
-
if (!passed) {
|
|
147
|
-
process.exit(1);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
let mocPath = '';
|
|
153
|
-
let wasmtimePath = '';
|
|
154
|
-
|
|
155
|
-
async function runAll(reporterName : ReporterName | undefined, filter = '', mode : TestMode = 'interpreter', replicaType : ReplicaName, watch = false, signal ?: AbortSignal) : Promise<boolean> {
|
|
156
|
-
let done = await testWithReporter(reporterName, filter, mode, replicaType, watch, signal);
|
|
157
|
-
return done;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export async function testWithReporter(reporterName : ReporterName | Reporter | undefined, filter = '', defaultMode : TestMode = 'interpreter', replicaType : ReplicaName, watch = false, signal ?: AbortSignal) : Promise<boolean> {
|
|
161
|
-
let rootDir = getRootDir();
|
|
162
|
-
let files : string[] = [];
|
|
163
|
-
let libFiles = globSync('**/test?(s)/lib.mo', globConfig);
|
|
164
|
-
if (libFiles[0]) {
|
|
165
|
-
files = [libFiles[0]];
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
let globStr = '**/test?(s)/**/*.test.mo';
|
|
169
|
-
if (filter) {
|
|
170
|
-
globStr = `**/test?(s)/**/*${filter}*.mo`;
|
|
171
|
-
}
|
|
172
|
-
files = globSync(path.join(rootDir, globStr), globConfig);
|
|
173
|
-
}
|
|
174
|
-
if (!files.length) {
|
|
175
|
-
if (filter) {
|
|
176
|
-
console.log(`No test files found for filter '${filter}'`);
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
console.log('No test files found');
|
|
180
|
-
console.log('Put your tests in \'test\' directory in *.test.mo files');
|
|
181
|
-
return false;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
let reporter : Reporter;
|
|
186
|
-
|
|
187
|
-
if (!reporterName || typeof reporterName === 'string') {
|
|
188
|
-
if (!reporterName) {
|
|
189
|
-
reporterName = files.length > 1 ? 'files' : 'verbose';
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (reporterName == 'compact') {
|
|
193
|
-
reporter = new CompactReporter;
|
|
194
|
-
}
|
|
195
|
-
else if (reporterName == 'files') {
|
|
196
|
-
reporter = new FilesReporter;
|
|
197
|
-
}
|
|
198
|
-
else if (reporterName == 'silent') {
|
|
199
|
-
reporter = new SilentReporter;
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
reporter = new VerboseReporter;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
reporter = reporterName;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
reporter.addFiles(files);
|
|
210
|
-
|
|
211
|
-
let config = readConfig();
|
|
212
|
-
let sourcesArr = await sources();
|
|
213
|
-
|
|
214
|
-
if (!mocPath) {
|
|
215
|
-
mocPath = await toolchain.bin('moc', {fallback: true});
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
let testTempDir = path.join(getRootDir(), '.mops/.test/');
|
|
219
|
-
replica.dir = testTempDir;
|
|
220
|
-
|
|
221
|
-
fs.rmSync(testTempDir, {recursive: true, force: true});
|
|
222
|
-
fs.mkdirSync(testTempDir, {recursive: true});
|
|
223
|
-
|
|
224
|
-
await parallel(os.cpus().length, files, async (file : string) => {
|
|
225
|
-
if (signal?.aborted) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
let mmf = new MMF1('store', absToRel(file));
|
|
230
|
-
|
|
231
|
-
// mode overrides
|
|
232
|
-
let lines = fs.readFileSync(file, 'utf8').split('\n');
|
|
233
|
-
let mode = defaultMode;
|
|
234
|
-
if (lines.includes('// @testmode wasi')) {
|
|
235
|
-
mode = 'wasi';
|
|
236
|
-
}
|
|
237
|
-
else if (lines.includes('// @testmode replica') || lines.find(line => line.match(/^(persistent )?actor( class)?/))) {
|
|
238
|
-
mode = 'replica';
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (mode === 'wasi' && !wasmtimePath) {
|
|
242
|
-
// ensure wasmtime is installed or specified in config
|
|
243
|
-
if (config.toolchain?.wasmtime) {
|
|
244
|
-
wasmtimePath = await toolchain.bin('wasmtime');
|
|
245
|
-
}
|
|
246
|
-
// fallback wasmtime to global binary if not specified in config (legacy)
|
|
247
|
-
else {
|
|
248
|
-
wasmtimePath = 'wasmtime';
|
|
249
|
-
console.log(chalk.yellow('Warning:'), 'Wasmtime is not specified in config. Using global binary "wasmtime". This will be removed in the future.');
|
|
250
|
-
console.log(`Run ${chalk.green('mops toolchain use wasmtime')} or add ${chalk.green('wasmtime = "<version>"')} in mops.toml to avoid breaking changes with future versions of mops.`);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
let promise = new Promise<void>((resolve) => {
|
|
255
|
-
let mocArgs = ['--hide-warnings', '--error-detail=2', ...sourcesArr.join(' ').split(' '), file].filter(x => x);
|
|
256
|
-
|
|
257
|
-
// interpret
|
|
258
|
-
if (mode === 'interpreter') {
|
|
259
|
-
let proc = spawn(mocPath, ['-r', '-ref-system-api', ...mocArgs], {signal});
|
|
260
|
-
proc.addListener('error', (error : any) => {
|
|
261
|
-
if (error?.code === 'ABORT_ERR') {
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
throw error;
|
|
265
|
-
});
|
|
266
|
-
pipeMMF(proc, mmf).then(resolve);
|
|
267
|
-
}
|
|
268
|
-
// build and run wasm
|
|
269
|
-
else if (mode === 'wasi') {
|
|
270
|
-
let wasmFile = `${path.join(testTempDir, path.parse(file).name)}.wasm`;
|
|
271
|
-
|
|
272
|
-
// build
|
|
273
|
-
let buildProc = spawn(mocPath, [`-o=${wasmFile}`, '-wasi-system-api', ...mocArgs], {signal});
|
|
274
|
-
buildProc.addListener('error', (error : any) => {
|
|
275
|
-
if (error?.code === 'ABORT_ERR') {
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
throw error;
|
|
279
|
-
});
|
|
280
|
-
pipeMMF(buildProc, mmf).then(async () => {
|
|
281
|
-
if (mmf.failed > 0) {
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
// run
|
|
285
|
-
let wasmtimeArgs = [];
|
|
286
|
-
if (config.toolchain?.wasmtime && config.toolchain?.wasmtime >= '14.0.0') {
|
|
287
|
-
wasmtimeArgs = [
|
|
288
|
-
'-S', 'preview2=n',
|
|
289
|
-
'-C', 'cache=n',
|
|
290
|
-
'-W', 'bulk-memory',
|
|
291
|
-
'-W', 'multi-memory',
|
|
292
|
-
'-W', 'memory64',
|
|
293
|
-
'-W', 'max-wasm-stack=4000000',
|
|
294
|
-
'-W', 'nan-canonicalization=y',
|
|
295
|
-
wasmFile,
|
|
296
|
-
];
|
|
297
|
-
}
|
|
298
|
-
else {
|
|
299
|
-
console.error(chalk.red('Minimum wasmtime version is 14.0.0. Please update wasmtime to the latest version'));
|
|
300
|
-
process.exit(1);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
let proc = spawn(wasmtimePath, wasmtimeArgs, {signal});
|
|
304
|
-
proc.addListener('error', (error : any) => {
|
|
305
|
-
if (error?.code === 'ABORT_ERR') {
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
throw error;
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
await pipeMMF(proc, mmf);
|
|
312
|
-
}).finally(() => {
|
|
313
|
-
fs.rmSync(wasmFile, {force: true});
|
|
314
|
-
}).then(resolve);
|
|
315
|
-
}
|
|
316
|
-
// build and execute in replica
|
|
317
|
-
else if (mode === 'replica') {
|
|
318
|
-
// mmf.strategy = 'print'; // because we run replica tests one-by-one
|
|
319
|
-
|
|
320
|
-
let wasmFile = `${path.join(testTempDir, path.parse(file).name)}.wasm`;
|
|
321
|
-
|
|
322
|
-
// build
|
|
323
|
-
let buildProc = spawn(mocPath, [`-o=${wasmFile}`, ...mocArgs], {signal});
|
|
324
|
-
buildProc.addListener('error', (error : any) => {
|
|
325
|
-
if (error?.code === 'ABORT_ERR') {
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
throw error;
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
pipeMMF(buildProc, mmf).then(async () => {
|
|
332
|
-
if (mmf.failed > 0) {
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
await startReplicaOnce(replica, replicaType);
|
|
337
|
-
|
|
338
|
-
if (signal?.aborted) {
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
let canisterName = path.parse(file).name;
|
|
343
|
-
let idlFactory = ({IDL} : any) => {
|
|
344
|
-
return IDL.Service({'runTests': IDL.Func([], [], [])});
|
|
345
|
-
};
|
|
346
|
-
interface _SERVICE {'runTests' : ActorMethod<[], undefined>;}
|
|
347
|
-
|
|
348
|
-
let canister = await replica.deploy(canisterName, wasmFile, idlFactory, undefined, signal);
|
|
349
|
-
|
|
350
|
-
if (signal?.aborted || !canister) {
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
pipeStdoutToMMF(canister.stream, mmf);
|
|
355
|
-
|
|
356
|
-
let actor = await replica.getActor(canisterName) as _SERVICE;
|
|
357
|
-
|
|
358
|
-
try {
|
|
359
|
-
if (globalThis.mopsReplicaTestRunning) {
|
|
360
|
-
await new Promise<void>((resolve) => {
|
|
361
|
-
let timerId = setInterval(() => {
|
|
362
|
-
if (!globalThis.mopsReplicaTestRunning) {
|
|
363
|
-
resolve();
|
|
364
|
-
clearInterval(timerId);
|
|
365
|
-
}
|
|
366
|
-
}, Math.random() * 1000 |0);
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
if (signal?.aborted) {
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
globalThis.mopsReplicaTestRunning = true;
|
|
375
|
-
await actor.runTests();
|
|
376
|
-
globalThis.mopsReplicaTestRunning = false;
|
|
377
|
-
|
|
378
|
-
mmf.pass();
|
|
379
|
-
}
|
|
380
|
-
catch (e : any) {
|
|
381
|
-
let stderrStream = new PassThrough();
|
|
382
|
-
pipeStderrToMMF(stderrStream, mmf, path.dirname(file));
|
|
383
|
-
stderrStream.write(e.message);
|
|
384
|
-
}
|
|
385
|
-
}).finally(async () => {
|
|
386
|
-
globalThis.mopsReplicaTestRunning = false;
|
|
387
|
-
fs.rmSync(wasmFile, {force: true});
|
|
388
|
-
}).then(resolve);
|
|
389
|
-
}
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
if (signal?.aborted) {
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
reporter.addRun(file, mmf, promise, mode);
|
|
397
|
-
|
|
398
|
-
await promise;
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
if (replicaStartPromise && !watch) {
|
|
402
|
-
await replica.stop();
|
|
403
|
-
fs.rmSync(testTempDir, {recursive: true, force: true});
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
if (signal?.aborted) {
|
|
407
|
-
return false;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
return reporter.done();
|
|
60
|
+
let replicaStartPromise: Promise<void> | undefined;
|
|
61
|
+
|
|
62
|
+
async function startReplicaOnce(replica: Replica, type: ReplicaName) {
|
|
63
|
+
if (!replicaStartPromise) {
|
|
64
|
+
replicaStartPromise = new Promise((resolve) => {
|
|
65
|
+
replica.start({ type, silent: true }).then(resolve);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return replicaStartPromise;
|
|
411
69
|
}
|
|
412
70
|
|
|
413
|
-
function
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
71
|
+
export async function test(filter = "", options: Partial<TestOptions> = {}) {
|
|
72
|
+
let config = readConfig();
|
|
73
|
+
let rootDir = getRootDir();
|
|
74
|
+
|
|
75
|
+
let replicaType =
|
|
76
|
+
options.replica ??
|
|
77
|
+
(config.toolchain?.["pocket-ic"] ? "pocket-ic" : ("dfx" as ReplicaName));
|
|
78
|
+
|
|
79
|
+
if (replicaType === "pocket-ic" && !config.toolchain?.["pocket-ic"]) {
|
|
80
|
+
let dfxVersion = getDfxVersion();
|
|
81
|
+
if (!dfxVersion || new SemVer(dfxVersion).compare("0.24.1") < 0) {
|
|
82
|
+
console.log(
|
|
83
|
+
chalk.red(
|
|
84
|
+
"Please update dfx to the version >=0.24.1 or specify pocket-ic version in mops.toml",
|
|
85
|
+
),
|
|
86
|
+
);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
} else {
|
|
89
|
+
replicaType = "dfx-pocket-ic";
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
replica.type = replicaType;
|
|
94
|
+
replica.verbose = !!options.verbose;
|
|
95
|
+
|
|
96
|
+
if (options.watch) {
|
|
97
|
+
replica.ttl = 60 * 15; // 15 minutes
|
|
98
|
+
|
|
99
|
+
let sigint = false;
|
|
100
|
+
process.on("SIGINT", () => {
|
|
101
|
+
if (sigint) {
|
|
102
|
+
console.log("Force exit");
|
|
103
|
+
process.exit(0);
|
|
104
|
+
}
|
|
105
|
+
sigint = true;
|
|
106
|
+
|
|
107
|
+
if (replicaStartPromise) {
|
|
108
|
+
console.log("Stopping replica...");
|
|
109
|
+
replica.stop(true).then(() => {
|
|
110
|
+
process.exit(0);
|
|
111
|
+
});
|
|
112
|
+
} else {
|
|
113
|
+
process.exit(0);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// todo: run only changed for *.test.mo?
|
|
118
|
+
// todo: run all for *.mo?
|
|
119
|
+
|
|
120
|
+
let curRun = Promise.resolve(true);
|
|
121
|
+
let controller = new AbortController();
|
|
122
|
+
|
|
123
|
+
let run = debounce(async () => {
|
|
124
|
+
controller.abort();
|
|
125
|
+
await curRun;
|
|
126
|
+
|
|
127
|
+
console.clear();
|
|
128
|
+
process.stdout.write("\x1Bc");
|
|
129
|
+
|
|
130
|
+
controller = new AbortController();
|
|
131
|
+
curRun = runAll(
|
|
132
|
+
options.reporter,
|
|
133
|
+
filter,
|
|
134
|
+
options.mode,
|
|
135
|
+
replicaType,
|
|
136
|
+
true,
|
|
137
|
+
controller.signal,
|
|
138
|
+
);
|
|
139
|
+
await curRun;
|
|
140
|
+
|
|
141
|
+
console.log("-".repeat(50));
|
|
142
|
+
console.log("Waiting for file changes...");
|
|
143
|
+
console.log(chalk.gray(`Press ${chalk.gray("Ctrl+C")} to exit.`));
|
|
144
|
+
}, 200);
|
|
145
|
+
|
|
146
|
+
let watcher = chokidar.watch(
|
|
147
|
+
[path.join(rootDir, "**/*.mo"), path.join(rootDir, "mops.toml")],
|
|
148
|
+
{
|
|
149
|
+
ignored: ignore,
|
|
150
|
+
ignoreInitial: true,
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
watcher.on("all", () => {
|
|
155
|
+
run();
|
|
156
|
+
});
|
|
157
|
+
run();
|
|
158
|
+
} else {
|
|
159
|
+
let passed = await runAll(
|
|
160
|
+
options.reporter,
|
|
161
|
+
filter,
|
|
162
|
+
options.mode,
|
|
163
|
+
replicaType,
|
|
164
|
+
);
|
|
165
|
+
if (!passed) {
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
422
169
|
}
|
|
423
170
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
let lineBefore = lines[+m2 - 2];
|
|
446
|
-
if (lineBefore) {
|
|
447
|
-
failedLine += chalk.dim(`\n ${+m2 - 1}\t| ${lineBefore.replaceAll('\t', ' ')}`);
|
|
448
|
-
}
|
|
449
|
-
failedLine += `\n${chalk.redBright`->`} ${m2}\t| ${lines[+m2 - 1]?.replaceAll('\t', ' ')}`;
|
|
450
|
-
if (lines.length > +m2) {
|
|
451
|
-
failedLine += chalk.dim(`\n ${+m2 + 1}\t| ${lines[+m2]?.replaceAll('\t', ' ')}`);
|
|
452
|
-
}
|
|
453
|
-
failedLine += chalk.dim('\n ...');
|
|
454
|
-
return res;
|
|
455
|
-
});
|
|
456
|
-
if (failedLine) {
|
|
457
|
-
text += failedLine;
|
|
458
|
-
}
|
|
459
|
-
mmf.fail(text);
|
|
460
|
-
});
|
|
171
|
+
let mocPath = "";
|
|
172
|
+
let wasmtimePath = "";
|
|
173
|
+
|
|
174
|
+
async function runAll(
|
|
175
|
+
reporterName: ReporterName | undefined,
|
|
176
|
+
filter = "",
|
|
177
|
+
mode: TestMode = "interpreter",
|
|
178
|
+
replicaType: ReplicaName,
|
|
179
|
+
watch = false,
|
|
180
|
+
signal?: AbortSignal,
|
|
181
|
+
): Promise<boolean> {
|
|
182
|
+
let done = await testWithReporter(
|
|
183
|
+
reporterName,
|
|
184
|
+
filter,
|
|
185
|
+
mode,
|
|
186
|
+
replicaType,
|
|
187
|
+
watch,
|
|
188
|
+
signal,
|
|
189
|
+
);
|
|
190
|
+
return done;
|
|
461
191
|
}
|
|
462
192
|
|
|
463
|
-
function
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
193
|
+
export async function testWithReporter(
|
|
194
|
+
reporterName: ReporterName | Reporter | undefined,
|
|
195
|
+
filter = "",
|
|
196
|
+
defaultMode: TestMode = "interpreter",
|
|
197
|
+
replicaType: ReplicaName,
|
|
198
|
+
watch = false,
|
|
199
|
+
signal?: AbortSignal,
|
|
200
|
+
): Promise<boolean> {
|
|
201
|
+
let rootDir = getRootDir();
|
|
202
|
+
let files: string[] = [];
|
|
203
|
+
let libFiles = globSync("**/test?(s)/lib.mo", globConfig);
|
|
204
|
+
if (libFiles[0]) {
|
|
205
|
+
files = [libFiles[0]];
|
|
206
|
+
} else {
|
|
207
|
+
let globStr = "**/test?(s)/**/*.test.mo";
|
|
208
|
+
if (filter) {
|
|
209
|
+
globStr = `**/test?(s)/**/*${filter}*.mo`;
|
|
210
|
+
}
|
|
211
|
+
files = globSync(path.join(rootDir, globStr), globConfig);
|
|
212
|
+
}
|
|
213
|
+
if (!files.length) {
|
|
214
|
+
if (filter) {
|
|
215
|
+
console.log(`No test files found for filter '${filter}'`);
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
console.log("No test files found");
|
|
219
|
+
console.log("Put your tests in 'test' directory in *.test.mo files");
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
let reporter: Reporter;
|
|
224
|
+
|
|
225
|
+
if (!reporterName || typeof reporterName === "string") {
|
|
226
|
+
if (!reporterName) {
|
|
227
|
+
reporterName = files.length > 1 ? "files" : "verbose";
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (reporterName == "compact") {
|
|
231
|
+
reporter = new CompactReporter();
|
|
232
|
+
} else if (reporterName == "files") {
|
|
233
|
+
reporter = new FilesReporter();
|
|
234
|
+
} else if (reporterName == "silent") {
|
|
235
|
+
reporter = new SilentReporter();
|
|
236
|
+
} else {
|
|
237
|
+
reporter = new VerboseReporter();
|
|
238
|
+
}
|
|
239
|
+
} else {
|
|
240
|
+
reporter = reporterName;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
reporter.addFiles(files);
|
|
244
|
+
|
|
245
|
+
let config = readConfig();
|
|
246
|
+
let sourcesArr = await sources();
|
|
247
|
+
|
|
248
|
+
if (!mocPath) {
|
|
249
|
+
mocPath = await toolchain.bin("moc", { fallback: true });
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
let testTempDir = path.join(getRootDir(), ".mops/.test/");
|
|
253
|
+
replica.dir = testTempDir;
|
|
254
|
+
|
|
255
|
+
fs.rmSync(testTempDir, { recursive: true, force: true });
|
|
256
|
+
fs.mkdirSync(testTempDir, { recursive: true });
|
|
257
|
+
|
|
258
|
+
let filesWithMode = files.map((file) => {
|
|
259
|
+
let lines = fs.readFileSync(file, "utf8").split("\n");
|
|
260
|
+
let mode = defaultMode;
|
|
261
|
+
if (lines.includes("// @testmode wasi")) {
|
|
262
|
+
mode = "wasi";
|
|
263
|
+
} else if (
|
|
264
|
+
lines.includes("// @testmode replica") ||
|
|
265
|
+
lines.find((line) => line.match(/^(persistent )?actor( class)?/))
|
|
266
|
+
) {
|
|
267
|
+
mode = "replica";
|
|
268
|
+
}
|
|
269
|
+
return { file, mode };
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
let hasWasiTests = filesWithMode.some(({ mode }) => mode === "wasi");
|
|
273
|
+
let hasReplicaTests = filesWithMode.some(({ mode }) => mode === "replica");
|
|
274
|
+
|
|
275
|
+
// prepare wasmtime path
|
|
276
|
+
if (hasWasiTests && !wasmtimePath) {
|
|
277
|
+
// ensure wasmtime is installed or specified in config
|
|
278
|
+
if (config.toolchain?.wasmtime) {
|
|
279
|
+
wasmtimePath = await toolchain.bin("wasmtime");
|
|
280
|
+
}
|
|
281
|
+
// fallback wasmtime to global binary if not specified in config (legacy)
|
|
282
|
+
else {
|
|
283
|
+
wasmtimePath = "wasmtime";
|
|
284
|
+
console.log(
|
|
285
|
+
chalk.yellow("Warning:"),
|
|
286
|
+
'Wasmtime is not specified in config. Using global binary "wasmtime". This will be removed in the future.',
|
|
287
|
+
);
|
|
288
|
+
console.log(
|
|
289
|
+
`Run ${chalk.green("mops toolchain use wasmtime")} or add ${chalk.green('wasmtime = "<version>"')} in mops.toml to avoid breaking changes with future versions of mops.`,
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
let runTestFile = async ({
|
|
295
|
+
file,
|
|
296
|
+
mode,
|
|
297
|
+
}: {
|
|
298
|
+
file: string;
|
|
299
|
+
mode: TestMode;
|
|
300
|
+
}) => {
|
|
301
|
+
if (signal?.aborted) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// print logs immediately for replica tests because we run them one-by-one
|
|
306
|
+
let mmf = new MMF1(mode === "replica" ? "print" : "store", absToRel(file));
|
|
307
|
+
|
|
308
|
+
let promise = new Promise<void>((resolve) => {
|
|
309
|
+
let mocArgs = [
|
|
310
|
+
"--hide-warnings",
|
|
311
|
+
"--error-detail=2",
|
|
312
|
+
...sourcesArr.join(" ").split(" "),
|
|
313
|
+
file,
|
|
314
|
+
].filter((x) => x);
|
|
315
|
+
|
|
316
|
+
// interpret
|
|
317
|
+
if (mode === "interpreter") {
|
|
318
|
+
let proc = spawn(mocPath, ["-r", "-ref-system-api", ...mocArgs], {
|
|
319
|
+
signal,
|
|
320
|
+
});
|
|
321
|
+
proc.addListener("error", (error: any) => {
|
|
322
|
+
if (error?.code === "ABORT_ERR") {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
throw error;
|
|
326
|
+
});
|
|
327
|
+
pipeMMF(proc, mmf).then(resolve);
|
|
328
|
+
}
|
|
329
|
+
// build and run wasm
|
|
330
|
+
else if (mode === "wasi") {
|
|
331
|
+
let wasmFile = `${path.join(testTempDir, path.parse(file).name)}.wasm`;
|
|
332
|
+
|
|
333
|
+
// build
|
|
334
|
+
let buildProc = spawn(
|
|
335
|
+
mocPath,
|
|
336
|
+
[`-o=${wasmFile}`, "-wasi-system-api", ...mocArgs],
|
|
337
|
+
{ signal },
|
|
338
|
+
);
|
|
339
|
+
buildProc.addListener("error", (error: any) => {
|
|
340
|
+
if (error?.code === "ABORT_ERR") {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
throw error;
|
|
344
|
+
});
|
|
345
|
+
pipeMMF(buildProc, mmf)
|
|
346
|
+
.then(async () => {
|
|
347
|
+
if (mmf.failed > 0) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
// run
|
|
351
|
+
let wasmtimeArgs = [];
|
|
352
|
+
if (
|
|
353
|
+
config.toolchain?.wasmtime &&
|
|
354
|
+
config.toolchain?.wasmtime >= "14.0.0"
|
|
355
|
+
) {
|
|
356
|
+
wasmtimeArgs = [
|
|
357
|
+
"-S",
|
|
358
|
+
"preview2=n",
|
|
359
|
+
"-C",
|
|
360
|
+
"cache=n",
|
|
361
|
+
"-W",
|
|
362
|
+
"bulk-memory",
|
|
363
|
+
"-W",
|
|
364
|
+
"multi-memory",
|
|
365
|
+
"-W",
|
|
366
|
+
"memory64",
|
|
367
|
+
"-W",
|
|
368
|
+
"max-wasm-stack=4000000",
|
|
369
|
+
"-W",
|
|
370
|
+
"nan-canonicalization=y",
|
|
371
|
+
wasmFile,
|
|
372
|
+
];
|
|
373
|
+
} else {
|
|
374
|
+
console.error(
|
|
375
|
+
chalk.red(
|
|
376
|
+
"Minimum wasmtime version is 14.0.0. Please update wasmtime to the latest version",
|
|
377
|
+
),
|
|
378
|
+
);
|
|
379
|
+
process.exit(1);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
let proc = spawn(wasmtimePath, wasmtimeArgs, { signal });
|
|
383
|
+
proc.addListener("error", (error: any) => {
|
|
384
|
+
if (error?.code === "ABORT_ERR") {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
throw error;
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
await pipeMMF(proc, mmf);
|
|
391
|
+
})
|
|
392
|
+
.finally(() => {
|
|
393
|
+
fs.rmSync(wasmFile, { force: true });
|
|
394
|
+
})
|
|
395
|
+
.then(resolve);
|
|
396
|
+
}
|
|
397
|
+
// build and execute in replica
|
|
398
|
+
else if (mode === "replica") {
|
|
399
|
+
let wasmFile = `${path.join(testTempDir, path.parse(file).name)}.wasm`;
|
|
400
|
+
|
|
401
|
+
// build
|
|
402
|
+
let buildProc = spawn(mocPath, [`-o=${wasmFile}`, ...mocArgs], {
|
|
403
|
+
signal,
|
|
404
|
+
});
|
|
405
|
+
buildProc.addListener("error", (error: any) => {
|
|
406
|
+
if (error?.code === "ABORT_ERR") {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
throw error;
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
pipeMMF(buildProc, mmf)
|
|
413
|
+
.then(async () => {
|
|
414
|
+
if (mmf.failed > 0) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
await startReplicaOnce(replica, replicaType);
|
|
419
|
+
|
|
420
|
+
if (signal?.aborted) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
let canisterName = path.parse(file).name;
|
|
425
|
+
let idlFactory = ({ IDL }: any) => {
|
|
426
|
+
return IDL.Service({ runTests: IDL.Func([], [], []) });
|
|
427
|
+
};
|
|
428
|
+
interface _SERVICE {
|
|
429
|
+
runTests: ActorMethod<[], undefined>;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
let canister = await replica.deploy(
|
|
433
|
+
canisterName,
|
|
434
|
+
wasmFile,
|
|
435
|
+
idlFactory,
|
|
436
|
+
undefined,
|
|
437
|
+
signal,
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
if (signal?.aborted || !canister) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
pipeStdoutToMMF(canister.stream, mmf);
|
|
445
|
+
|
|
446
|
+
let actor = (await replica.getActor(canisterName)) as _SERVICE;
|
|
447
|
+
|
|
448
|
+
try {
|
|
449
|
+
if (globalThis.mopsReplicaTestRunning) {
|
|
450
|
+
await new Promise<void>((resolve) => {
|
|
451
|
+
let timerId = setInterval(
|
|
452
|
+
() => {
|
|
453
|
+
if (!globalThis.mopsReplicaTestRunning) {
|
|
454
|
+
resolve();
|
|
455
|
+
clearInterval(timerId);
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
(Math.random() * 1000) | 0,
|
|
459
|
+
);
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (signal?.aborted) {
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
globalThis.mopsReplicaTestRunning = true;
|
|
468
|
+
await actor.runTests();
|
|
469
|
+
globalThis.mopsReplicaTestRunning = false;
|
|
470
|
+
|
|
471
|
+
mmf.pass();
|
|
472
|
+
} catch (e: any) {
|
|
473
|
+
let stderrStream = new PassThrough();
|
|
474
|
+
pipeStderrToMMF(stderrStream, mmf, path.dirname(file));
|
|
475
|
+
stderrStream.write(e.message);
|
|
476
|
+
}
|
|
477
|
+
})
|
|
478
|
+
.finally(async () => {
|
|
479
|
+
globalThis.mopsReplicaTestRunning = false;
|
|
480
|
+
fs.rmSync(wasmFile, { force: true });
|
|
481
|
+
})
|
|
482
|
+
.then(resolve);
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
if (signal?.aborted) {
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
reporter.addRun(file, mmf, promise, mode);
|
|
491
|
+
|
|
492
|
+
await promise;
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
await parallel(
|
|
496
|
+
os.cpus().length,
|
|
497
|
+
filesWithMode.filter(({ mode }) => mode !== "replica"),
|
|
498
|
+
runTestFile,
|
|
499
|
+
);
|
|
500
|
+
await parallel(
|
|
501
|
+
1,
|
|
502
|
+
filesWithMode.filter(({ mode }) => mode === "replica"),
|
|
503
|
+
runTestFile,
|
|
504
|
+
);
|
|
505
|
+
|
|
506
|
+
if (hasReplicaTests && !watch) {
|
|
507
|
+
await replica.stop();
|
|
508
|
+
fs.rmSync(testTempDir, { recursive: true, force: true });
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (signal?.aborted) {
|
|
512
|
+
return false;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return reporter.done();
|
|
479
516
|
}
|