From 537393498e9af67ca157f198a647f8699a6b652f Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 17 Jun 2026 19:04:44 +0200 Subject: [PATCH 1/9] =?UTF-8?q?chore:=20bump=20all=20icp-dev-env=20images?= =?UTF-8?q?=20to=201.0.1,=20Makefile=20=E2=86=92=20test.sh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updates all already-merged Motoko and Rust examples: - icp-dev-env-{motoko,rust,all} images: 0.3.2/1.0.0 → 1.0.1 - Convert Makefile test targets to test.sh bash scripts - Update workflow files and READMEs accordingly Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/backend_only.yml | 8 +- .github/workflows/canister_factory.yml | 4 +- .github/workflows/canister_logs.yml | 4 +- .github/workflows/cert-var.yml | 4 +- .github/workflows/composite_query.yml | 4 +- .github/workflows/daily_planner.yml | 4 +- .github/workflows/filevault.yml | 4 +- .github/workflows/flying_ninja.yml | 8 +- .github/workflows/hello_cycles.yml | 4 +- .github/workflows/hello_world.yml | 8 +- .../hosting-godot-html5-template-example.yml | 2 +- .../hosting-photo-storage-example.yml | 2 +- .../hosting-static-website-example.yaml | 2 +- .../hosting-unity-webgl-example.yaml | 2 +- .github/workflows/icp_transfer.yml | 6 +- .github/workflows/icrc2-swap.yml | 4 +- .github/workflows/low_wasm_memory.yml | 4 +- .github/workflows/parallel_calls.yml | 6 +- .github/workflows/pub-sub.yml | 4 +- .github/workflows/query_stats.yml | 4 +- .github/workflows/random_maze.yml | 4 +- .github/workflows/send_http_get.yml | 4 +- .github/workflows/send_http_post.yml | 4 +- .github/workflows/superheroes.yml | 4 +- .github/workflows/threshold-ecdsa.yml | 4 +- .github/workflows/threshold-schnorr.yml | 4 +- .../workflows/vetkeys-basic-bls-signing.yml | 4 +- .github/workflows/vetkeys-basic-ibe.yml | 4 +- .../workflows/vetkeys-basic-timelock-ibe.yml | 2 +- .github/workflows/vetkeys-basic-vetkd.yml | 8 +- .../vetkeys-encrypted-notes-app-vetkd.yml | 4 +- ...vetkeys-password-manager-with-metadata.yml | 4 +- .../workflows/vetkeys-password-manager.yml | 4 +- .github/workflows/who_am_i.yml | 8 +- motoko/backend_only/Makefile | 8 - motoko/backend_only/README.md | 2 +- motoko/backend_only/test.sh | 8 + motoko/canister_factory/Makefile | 49 ------ motoko/canister_factory/README.md | 6 +- motoko/canister_factory/test.sh | 51 +++++++ motoko/canister_logs/Makefile | 54 ------- motoko/canister_logs/README.md | 2 +- motoko/canister_logs/test.sh | 54 +++++++ motoko/cert-var/Makefile | 20 --- motoko/cert-var/README.md | 4 +- motoko/cert-var/test.sh | 20 +++ motoko/composite_query/Makefile | 45 ------ motoko/composite_query/README.md | 4 +- motoko/composite_query/test.sh | 42 ++++++ motoko/daily_planner/Makefile | 39 ----- motoko/daily_planner/README.md | 2 +- motoko/daily_planner/test.sh | 39 +++++ motoko/filevault/Makefile | 64 -------- motoko/filevault/README.md | 2 +- motoko/filevault/test.sh | 64 ++++++++ motoko/flying_ninja/Makefile | 28 ---- motoko/flying_ninja/README.md | 2 +- motoko/flying_ninja/test.sh | 28 ++++ motoko/hello_cycles/Makefile | 32 ---- motoko/hello_cycles/README.md | 4 +- motoko/hello_cycles/test.sh | 32 ++++ motoko/hello_world/Makefile | 15 -- motoko/hello_world/test.sh | 13 ++ motoko/icp_transfer/Makefile | 62 -------- motoko/icp_transfer/README.md | 4 +- motoko/icp_transfer/test.sh | 61 ++++++++ motoko/icrc2-swap/Makefile | 141 ------------------ motoko/icrc2-swap/README.md | 4 +- motoko/icrc2-swap/test.sh | 106 +++++++++++++ motoko/low_wasm_memory/Makefile | 22 --- motoko/low_wasm_memory/README.md | 4 +- motoko/low_wasm_memory/test.sh | 21 +++ motoko/parallel_calls/Makefile | 37 ----- motoko/parallel_calls/README.md | 2 +- motoko/parallel_calls/test.sh | 29 ++++ motoko/pub-sub/Makefile | 31 ---- motoko/pub-sub/README.md | 4 +- motoko/pub-sub/test.sh | 32 ++++ motoko/query_stats/Makefile | 45 ------ motoko/query_stats/README.md | 8 +- motoko/query_stats/test.sh | 18 +++ motoko/random_maze/Makefile | 20 --- motoko/random_maze/README.md | 2 +- motoko/random_maze/test.sh | 20 +++ motoko/send_http_get/Makefile | 8 - motoko/send_http_get/README.md | 2 +- motoko/send_http_get/test.sh | 8 + motoko/send_http_post/Makefile | 8 - motoko/send_http_post/README.md | 2 +- motoko/send_http_post/test.sh | 8 + motoko/superheroes/Makefile | 43 ------ motoko/superheroes/README.md | 4 +- motoko/superheroes/test.sh | 43 ++++++ motoko/threshold-ecdsa/Makefile | 18 --- motoko/threshold-ecdsa/README.md | 2 +- motoko/threshold-ecdsa/test.sh | 23 ++- motoko/threshold-schnorr/Makefile | 30 ---- motoko/threshold-schnorr/README.md | 2 +- motoko/threshold-schnorr/test.sh | 107 ++++--------- motoko/threshold-schnorr/verify.sh | 79 ++++++++++ motoko/vetkeys/basic_vetkd/Makefile | 13 -- motoko/vetkeys/basic_vetkd/test.sh | 13 ++ motoko/who_am_i/Makefile | 14 -- motoko/who_am_i/test.sh | 14 ++ rust/backend_only/Makefile | 8 - rust/backend_only/README.md | 2 +- rust/backend_only/test.sh | 8 + rust/flying_ninja/Makefile | 26 ---- rust/flying_ninja/README.md | 2 +- rust/flying_ninja/test.sh | 26 ++++ rust/hello_world/Makefile | 15 -- rust/hello_world/test.sh | 13 ++ rust/icp_transfer/Makefile | 62 -------- rust/icp_transfer/README.md | 4 +- rust/icp_transfer/test.sh | 61 ++++++++ rust/vetkeys/basic_vetkd/Makefile | 13 -- rust/vetkeys/basic_vetkd/test.sh | 13 ++ rust/who_am_i/Makefile | 14 -- rust/who_am_i/test.sh | 14 ++ 119 files changed, 1099 insertions(+), 1179 deletions(-) delete mode 100644 motoko/backend_only/Makefile create mode 100755 motoko/backend_only/test.sh delete mode 100644 motoko/canister_factory/Makefile create mode 100755 motoko/canister_factory/test.sh delete mode 100644 motoko/canister_logs/Makefile create mode 100755 motoko/canister_logs/test.sh delete mode 100644 motoko/cert-var/Makefile create mode 100755 motoko/cert-var/test.sh delete mode 100644 motoko/composite_query/Makefile create mode 100755 motoko/composite_query/test.sh delete mode 100644 motoko/daily_planner/Makefile create mode 100755 motoko/daily_planner/test.sh delete mode 100644 motoko/filevault/Makefile create mode 100755 motoko/filevault/test.sh delete mode 100644 motoko/flying_ninja/Makefile create mode 100755 motoko/flying_ninja/test.sh delete mode 100644 motoko/hello_cycles/Makefile create mode 100755 motoko/hello_cycles/test.sh delete mode 100644 motoko/hello_world/Makefile create mode 100755 motoko/hello_world/test.sh delete mode 100644 motoko/icp_transfer/Makefile create mode 100755 motoko/icp_transfer/test.sh delete mode 100644 motoko/icrc2-swap/Makefile create mode 100755 motoko/icrc2-swap/test.sh delete mode 100644 motoko/low_wasm_memory/Makefile create mode 100755 motoko/low_wasm_memory/test.sh delete mode 100644 motoko/parallel_calls/Makefile create mode 100755 motoko/parallel_calls/test.sh delete mode 100644 motoko/pub-sub/Makefile create mode 100755 motoko/pub-sub/test.sh delete mode 100644 motoko/query_stats/Makefile create mode 100755 motoko/query_stats/test.sh delete mode 100644 motoko/random_maze/Makefile create mode 100755 motoko/random_maze/test.sh delete mode 100644 motoko/send_http_get/Makefile create mode 100755 motoko/send_http_get/test.sh delete mode 100644 motoko/send_http_post/Makefile create mode 100755 motoko/send_http_post/test.sh delete mode 100644 motoko/superheroes/Makefile create mode 100755 motoko/superheroes/test.sh delete mode 100644 motoko/threshold-ecdsa/Makefile delete mode 100644 motoko/threshold-schnorr/Makefile create mode 100755 motoko/threshold-schnorr/verify.sh delete mode 100644 motoko/vetkeys/basic_vetkd/Makefile create mode 100755 motoko/vetkeys/basic_vetkd/test.sh delete mode 100644 motoko/who_am_i/Makefile create mode 100755 motoko/who_am_i/test.sh delete mode 100644 rust/backend_only/Makefile create mode 100755 rust/backend_only/test.sh delete mode 100644 rust/flying_ninja/Makefile create mode 100755 rust/flying_ninja/test.sh delete mode 100644 rust/hello_world/Makefile create mode 100755 rust/hello_world/test.sh delete mode 100644 rust/icp_transfer/Makefile create mode 100755 rust/icp_transfer/test.sh delete mode 100644 rust/vetkeys/basic_vetkd/Makefile create mode 100755 rust/vetkeys/basic_vetkd/test.sh delete mode 100644 rust/who_am_i/Makefile create mode 100755 rust/who_am_i/test.sh diff --git a/.github/workflows/backend_only.yml b/.github/workflows/backend_only.yml index 370d80c7c..fc7d58a1d 100644 --- a/.github/workflows/backend_only.yml +++ b/.github/workflows/backend_only.yml @@ -16,7 +16,7 @@ concurrency: jobs: motoko-backend_only: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -26,11 +26,11 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh rust-backend_only: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-rust:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-rust:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -40,4 +40,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/canister_factory.yml b/.github/workflows/canister_factory.yml index 04d847fad..7b90a5b13 100644 --- a/.github/workflows/canister_factory.yml +++ b/.github/workflows/canister_factory.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-canister_factory: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy --cycles 30t - make test + bash test.sh diff --git a/.github/workflows/canister_logs.yml b/.github/workflows/canister_logs.yml index 52eb58c5f..be7a1feba 100644 --- a/.github/workflows/canister_logs.yml +++ b/.github/workflows/canister_logs.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-canister_logs: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/cert-var.yml b/.github/workflows/cert-var.yml index 2eed236c7..51d45efbf 100644 --- a/.github/workflows/cert-var.yml +++ b/.github/workflows/cert-var.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-cert-var: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/composite_query.yml b/.github/workflows/composite_query.yml index 347b510c7..438864907 100644 --- a/.github/workflows/composite_query.yml +++ b/.github/workflows/composite_query.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-composite_query: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy --cycles 30t - make test + bash test.sh diff --git a/.github/workflows/daily_planner.yml b/.github/workflows/daily_planner.yml index 3c0c06622..760436a02 100644 --- a/.github/workflows/daily_planner.yml +++ b/.github/workflows/daily_planner.yml @@ -16,7 +16,7 @@ concurrency: jobs: motoko-daily_planner: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -26,4 +26,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/filevault.yml b/.github/workflows/filevault.yml index 3ac4e453a..a922cfdc4 100644 --- a/.github/workflows/filevault.yml +++ b/.github/workflows/filevault.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-filevault: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/flying_ninja.yml b/.github/workflows/flying_ninja.yml index 0d9a77b56..3c5f217a7 100644 --- a/.github/workflows/flying_ninja.yml +++ b/.github/workflows/flying_ninja.yml @@ -16,7 +16,7 @@ concurrency: jobs: motoko-flying_ninja: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -26,11 +26,11 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh rust-flying_ninja: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-rust:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-rust:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -40,4 +40,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/hello_cycles.yml b/.github/workflows/hello_cycles.yml index b9a3330c3..e083eb75f 100644 --- a/.github/workflows/hello_cycles.yml +++ b/.github/workflows/hello_cycles.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-hello_cycles: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/hello_world.yml b/.github/workflows/hello_world.yml index 82e824f21..61c986567 100644 --- a/.github/workflows/hello_world.yml +++ b/.github/workflows/hello_world.yml @@ -17,7 +17,7 @@ concurrency: jobs: motoko-hello_world: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -27,11 +27,11 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh rust-hello_world: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-rust:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-rust:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -41,4 +41,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/hosting-godot-html5-template-example.yml b/.github/workflows/hosting-godot-html5-template-example.yml index e99ce24bc..33f4045d0 100644 --- a/.github/workflows/hosting-godot-html5-template-example.yml +++ b/.github/workflows/hosting-godot-html5-template-example.yml @@ -15,7 +15,7 @@ concurrency: jobs: hosting-godot-html5-template: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-all:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-all:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: diff --git a/.github/workflows/hosting-photo-storage-example.yml b/.github/workflows/hosting-photo-storage-example.yml index 293c1968a..dba93c174 100644 --- a/.github/workflows/hosting-photo-storage-example.yml +++ b/.github/workflows/hosting-photo-storage-example.yml @@ -15,7 +15,7 @@ concurrency: jobs: hosting-photo-storage: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-all:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-all:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: diff --git a/.github/workflows/hosting-static-website-example.yaml b/.github/workflows/hosting-static-website-example.yaml index 536003122..36bf2881c 100644 --- a/.github/workflows/hosting-static-website-example.yaml +++ b/.github/workflows/hosting-static-website-example.yaml @@ -15,7 +15,7 @@ concurrency: jobs: hosting-static-website: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-all:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-all:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: diff --git a/.github/workflows/hosting-unity-webgl-example.yaml b/.github/workflows/hosting-unity-webgl-example.yaml index 36792f164..b0747c7c5 100644 --- a/.github/workflows/hosting-unity-webgl-example.yaml +++ b/.github/workflows/hosting-unity-webgl-example.yaml @@ -15,7 +15,7 @@ concurrency: jobs: hosting-unity-webgl: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-all:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-all:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: diff --git a/.github/workflows/icp_transfer.yml b/.github/workflows/icp_transfer.yml index 0bc50d8e8..61285c501 100644 --- a/.github/workflows/icp_transfer.yml +++ b/.github/workflows/icp_transfer.yml @@ -16,7 +16,7 @@ concurrency: jobs: motoko-icp_transfer: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.0 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -26,7 +26,7 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh rust-icp_transfer: runs-on: ubuntu-24.04 @@ -40,4 +40,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/icrc2-swap.yml b/.github/workflows/icrc2-swap.yml index 706d0514b..c4987d00d 100644 --- a/.github/workflows/icrc2-swap.yml +++ b/.github/workflows/icrc2-swap.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-icrc2-swap: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d make deploy - make test + bash test.sh diff --git a/.github/workflows/low_wasm_memory.yml b/.github/workflows/low_wasm_memory.yml index 4afd3eed2..abe4a3283 100644 --- a/.github/workflows/low_wasm_memory.yml +++ b/.github/workflows/low_wasm_memory.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-low_wasm_memory: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/parallel_calls.yml b/.github/workflows/parallel_calls.yml index cd32ac15d..e2fbd5dc9 100644 --- a/.github/workflows/parallel_calls.yml +++ b/.github/workflows/parallel_calls.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-parallel_calls: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,11 +25,11 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh motoko-parallel_calls-multi-subnet: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-all:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-all:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: diff --git a/.github/workflows/pub-sub.yml b/.github/workflows/pub-sub.yml index 286993661..2d471f1d9 100644 --- a/.github/workflows/pub-sub.yml +++ b/.github/workflows/pub-sub.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-pub-sub: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/query_stats.yml b/.github/workflows/query_stats.yml index 7a762983a..e12ea39c5 100644 --- a/.github/workflows/query_stats.yml +++ b/.github/workflows/query_stats.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-query_stats: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/random_maze.yml b/.github/workflows/random_maze.yml index e05509c75..ed7e7c854 100644 --- a/.github/workflows/random_maze.yml +++ b/.github/workflows/random_maze.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-random_maze: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/send_http_get.yml b/.github/workflows/send_http_get.yml index d6952c07c..9136c0f92 100644 --- a/.github/workflows/send_http_get.yml +++ b/.github/workflows/send_http_get.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-send_http_get: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/send_http_post.yml b/.github/workflows/send_http_post.yml index 8ec74874d..cd969c543 100644 --- a/.github/workflows/send_http_post.yml +++ b/.github/workflows/send_http_post.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-send_http_post: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/superheroes.yml b/.github/workflows/superheroes.yml index e063f27b7..7a48c67ef 100644 --- a/.github/workflows/superheroes.yml +++ b/.github/workflows/superheroes.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-superheroes: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/threshold-ecdsa.yml b/.github/workflows/threshold-ecdsa.yml index 637524a84..00db6ad88 100644 --- a/.github/workflows/threshold-ecdsa.yml +++ b/.github/workflows/threshold-ecdsa.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-threshold-ecdsa: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/threshold-schnorr.yml b/.github/workflows/threshold-schnorr.yml index 60f44f5ea..ca5e85f7c 100644 --- a/.github/workflows/threshold-schnorr.yml +++ b/.github/workflows/threshold-schnorr.yml @@ -15,7 +15,7 @@ concurrency: jobs: motoko-threshold-schnorr: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.2 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -25,4 +25,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/vetkeys-basic-bls-signing.yml b/.github/workflows/vetkeys-basic-bls-signing.yml index a3e850047..e38e0b617 100644 --- a/.github/workflows/vetkeys-basic-bls-signing.yml +++ b/.github/workflows/vetkeys-basic-bls-signing.yml @@ -16,7 +16,7 @@ concurrency: jobs: rust: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-rust:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-rust:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -26,7 +26,7 @@ jobs: run: icp network start -d && icp deploy motoko: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: diff --git a/.github/workflows/vetkeys-basic-ibe.yml b/.github/workflows/vetkeys-basic-ibe.yml index da55075fe..132c81eb6 100644 --- a/.github/workflows/vetkeys-basic-ibe.yml +++ b/.github/workflows/vetkeys-basic-ibe.yml @@ -16,7 +16,7 @@ concurrency: jobs: rust: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-rust:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-rust:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -26,7 +26,7 @@ jobs: run: icp network start -d && icp deploy motoko: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: diff --git a/.github/workflows/vetkeys-basic-timelock-ibe.yml b/.github/workflows/vetkeys-basic-timelock-ibe.yml index 16a419b15..3c610aca3 100644 --- a/.github/workflows/vetkeys-basic-timelock-ibe.yml +++ b/.github/workflows/vetkeys-basic-timelock-ibe.yml @@ -16,7 +16,7 @@ concurrency: jobs: rust: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-rust:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-rust:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: diff --git a/.github/workflows/vetkeys-basic-vetkd.yml b/.github/workflows/vetkeys-basic-vetkd.yml index 87ced8525..67d60034c 100644 --- a/.github/workflows/vetkeys-basic-vetkd.yml +++ b/.github/workflows/vetkeys-basic-vetkd.yml @@ -17,7 +17,7 @@ concurrency: jobs: motoko: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -27,11 +27,11 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh rust: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-rust:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-rust:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -41,4 +41,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/.github/workflows/vetkeys-encrypted-notes-app-vetkd.yml b/.github/workflows/vetkeys-encrypted-notes-app-vetkd.yml index ad8aded29..a166f927a 100644 --- a/.github/workflows/vetkeys-encrypted-notes-app-vetkd.yml +++ b/.github/workflows/vetkeys-encrypted-notes-app-vetkd.yml @@ -16,7 +16,7 @@ concurrency: jobs: rust: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-rust:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-rust:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -26,7 +26,7 @@ jobs: run: icp network start -d && icp deploy motoko: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: diff --git a/.github/workflows/vetkeys-password-manager-with-metadata.yml b/.github/workflows/vetkeys-password-manager-with-metadata.yml index c08a4713a..79beb304d 100644 --- a/.github/workflows/vetkeys-password-manager-with-metadata.yml +++ b/.github/workflows/vetkeys-password-manager-with-metadata.yml @@ -16,7 +16,7 @@ concurrency: jobs: rust: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-rust:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-rust:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -26,7 +26,7 @@ jobs: run: icp network start -d && icp deploy motoko: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: diff --git a/.github/workflows/vetkeys-password-manager.yml b/.github/workflows/vetkeys-password-manager.yml index 19d88e0d7..953638623 100644 --- a/.github/workflows/vetkeys-password-manager.yml +++ b/.github/workflows/vetkeys-password-manager.yml @@ -16,7 +16,7 @@ concurrency: jobs: rust: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-rust:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-rust:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -26,7 +26,7 @@ jobs: run: icp network start -d && icp deploy motoko: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: diff --git a/.github/workflows/who_am_i.yml b/.github/workflows/who_am_i.yml index 3103c5f5d..c157d5cd0 100644 --- a/.github/workflows/who_am_i.yml +++ b/.github/workflows/who_am_i.yml @@ -17,7 +17,7 @@ concurrency: jobs: motoko-who_am_i: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-motoko:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-motoko:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -27,11 +27,11 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh rust-who_am_i: runs-on: ubuntu-24.04 - container: ghcr.io/dfinity/icp-dev-env-rust:0.3.1 + container: ghcr.io/dfinity/icp-dev-env-rust:1.0.1 env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -41,4 +41,4 @@ jobs: run: | icp network start -d icp deploy - make test + bash test.sh diff --git a/motoko/backend_only/Makefile b/motoko/backend_only/Makefile deleted file mode 100644 index 08b2e2255..000000000 --- a/motoko/backend_only/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -.PHONY: test - -test: - @echo "=== Test 1: greet returns greeting ===" - @result=$$(icp canister call backend greet '("World")') && \ - echo "$$result" && \ - echo "$$result" | grep -q '"Hello, World!"' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/backend_only/README.md b/motoko/backend_only/README.md index 94f6e160e..59ad7616c 100644 --- a/motoko/backend_only/README.md +++ b/motoko/backend_only/README.md @@ -22,7 +22,7 @@ cd examples/motoko/backend_only ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` diff --git a/motoko/backend_only/test.sh b/motoko/backend_only/test.sh new file mode 100755 index 000000000..c0b398436 --- /dev/null +++ b/motoko/backend_only/test.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -e + +echo "=== Test 1: greet returns greeting ===" +result=$(icp canister call backend greet '("World")') && \ + echo "$result" && \ + echo "$result" | grep -q '"Hello, World!"' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/canister_factory/Makefile b/motoko/canister_factory/Makefile deleted file mode 100644 index c4159e33e..000000000 --- a/motoko/canister_factory/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -.PHONY: test topup - -topup: - icp canister top-up --amount 30t backend - -test: - @echo "--- Testing canister factory ---" - @echo "" - @echo "[1/5] newActorClass: creates a Counter canister via actor class" - @result=$$(icp canister call backend newActorClass '(2_000_000_000_000)') && \ - echo " $$result" && \ - echo "$$result" | grep -q 'principal' && \ - echo " PASS" || (echo " FAIL" && exit 1) - @echo "" - @echo "[2/5] installActorClass: two-step canister creation" - @result=$$(icp canister call backend installActorClass '(2_000_000_000_000)') && \ - echo " $$result" && \ - echo "$$result" | grep -q 'principal' && \ - echo " PASS" || (echo " FAIL" && exit 1) - @echo "" - @echo "[3/5] createAndInstallCanisterManually: low-level creation with empty WASM" - @result=$$(icp canister call backend createAndInstallCanisterManually '(2_000_000_000_000)') && \ - echo " $$result" && \ - echo "$$result" | grep -q 'principal' && \ - echo " PASS" || (echo " FAIL" && exit 1) - @echo "" - @echo "[4/5] upgradeActorClass: Counter → CounterV2, state PRESERVED (value stays 52)" - @canister_id=$$(icp canister call backend newActorClass '(2_000_000_000_000)' | grep -o '"[^"]*"' | tr -d '"') && \ - echo " created: $$canister_id" && \ - add_result=$$(icp canister call "$$canister_id" addToValue '(10)') && \ - echo " addToValue(10): $$add_result (expected: 52)" && \ - echo "$$add_result" | grep -q '52' && \ - icp canister call backend upgradeActorClass "(principal \"$$canister_id\")" > /dev/null && \ - result=$$(icp canister call "$$canister_id" getValue '()') && \ - echo " getValue after upgrade: $$result (expected: 52)" && \ - echo "$$result" | grep -q '52' && \ - echo " PASS" || (echo " FAIL" && exit 1) - @echo "" - @echo "[5/5] reinstallActorClass: Counter → CounterV2, state RESET (value back to 42)" - @canister_id=$$(icp canister call backend newActorClass '(2_000_000_000_000)' | grep -o '"[^"]*"' | tr -d '"') && \ - echo " created: $$canister_id" && \ - add_result=$$(icp canister call "$$canister_id" addToValue '(10)') && \ - echo " addToValue(10): $$add_result (expected: 52)" && \ - echo "$$add_result" | grep -q '52' && \ - icp canister call backend reinstallActorClass "(principal \"$$canister_id\")" > /dev/null && \ - result=$$(icp canister call "$$canister_id" getValue '()') && \ - echo " getValue after reinstall: $$result (expected: 42)" && \ - echo "$$result" | grep -q '42' && \ - echo " PASS" || (echo " FAIL" && exit 1) diff --git a/motoko/canister_factory/README.md b/motoko/canister_factory/README.md index 6550f985b..ade4892d2 100644 --- a/motoko/canister_factory/README.md +++ b/motoko/canister_factory/README.md @@ -25,15 +25,15 @@ cd examples/motoko/canister_factory ```bash icp network start -d icp deploy --cycles 30t -make test +bash test.sh icp network stop ``` The `--cycles 30t` flag funds the backend canister with 30 trillion cycles so it can forward cycles when creating child canisters. -`make test` exercises all five functions and verifies the core educational point: after `addToValue(10)` sets a child canister's value to 52, upgrading preserves it at 52 while reinstalling resets it to 42. +`bash test.sh` exercises all five functions and verifies the core educational point: after `addToValue(10)` sets a child canister's value to 52, upgrading preserves it at 52 while reinstalling resets it to 42. -> If the tests fail with an out-of-cycles error, run `make topup` to add 30 trillion cycles to the backend canister and retry. +> If the tests fail with an out-of-cycles error, run `icp canister top-up --amount 30t backend` to add 30 trillion cycles to the backend canister and retry. ## Available functions diff --git a/motoko/canister_factory/test.sh b/motoko/canister_factory/test.sh new file mode 100755 index 000000000..2c356dea5 --- /dev/null +++ b/motoko/canister_factory/test.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -e + +echo "--- Testing canister factory ---" +echo "" + +echo "[1/5] newActorClass: creates a Counter canister via actor class" +result=$(icp canister call backend newActorClass '(2_000_000_000_000)') && \ + echo " $result" && \ + echo "$result" | grep -q 'principal' && \ + echo " PASS" || (echo " FAIL" && exit 1) +echo "" + +echo "[2/5] installActorClass: two-step canister creation" +result=$(icp canister call backend installActorClass '(2_000_000_000_000)') && \ + echo " $result" && \ + echo "$result" | grep -q 'principal' && \ + echo " PASS" || (echo " FAIL" && exit 1) +echo "" + +echo "[3/5] createAndInstallCanisterManually: low-level creation with empty WASM" +result=$(icp canister call backend createAndInstallCanisterManually '(2_000_000_000_000)') && \ + echo " $result" && \ + echo "$result" | grep -q 'principal' && \ + echo " PASS" || (echo " FAIL" && exit 1) +echo "" + +echo "[4/5] upgradeActorClass: Counter → CounterV2, state PRESERVED (value stays 52)" +canister_id=$(icp canister call backend newActorClass '(2_000_000_000_000)' | grep -o '"[^"]*"' | tr -d '"') && \ + echo " created: $canister_id" && \ + add_result=$(icp canister call "$canister_id" addToValue '(10)') && \ + echo " addToValue(10): $add_result (expected: 52)" && \ + echo "$add_result" | grep -q '52' && \ + icp canister call backend upgradeActorClass "(principal \"$canister_id\")" > /dev/null && \ + result=$(icp canister call "$canister_id" getValue '()') && \ + echo " getValue after upgrade: $result (expected: 52)" && \ + echo "$result" | grep -q '52' && \ + echo " PASS" || (echo " FAIL" && exit 1) +echo "" + +echo "[5/5] reinstallActorClass: Counter → CounterV2, state RESET (value back to 42)" +canister_id=$(icp canister call backend newActorClass '(2_000_000_000_000)' | grep -o '"[^"]*"' | tr -d '"') && \ + echo " created: $canister_id" && \ + add_result=$(icp canister call "$canister_id" addToValue '(10)') && \ + echo " addToValue(10): $add_result (expected: 52)" && \ + echo "$add_result" | grep -q '52' && \ + icp canister call backend reinstallActorClass "(principal \"$canister_id\")" > /dev/null && \ + result=$(icp canister call "$canister_id" getValue '()') && \ + echo " getValue after reinstall: $result (expected: 42)" && \ + echo "$result" | grep -q '42' && \ + echo " PASS" || (echo " FAIL" && exit 1) diff --git a/motoko/canister_logs/Makefile b/motoko/canister_logs/Makefile deleted file mode 100644 index 30015d288..000000000 --- a/motoko/canister_logs/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -.PHONY: test - -test: - @echo "=== Test 1/11: print via update call is recorded in logs ===" - @icp canister call backend print '("print via update")' && \ - icp canister logs backend | grep -q 'print via update' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2/11: print_query via replicated update call is recorded in logs ===" - @icp canister call backend print_query '("print via replicated query")' && \ - icp canister logs backend | grep -q 'print via replicated query' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3/11: trap via update call is recorded in logs ===" - @icp canister call backend trap '("trap via update")' 2>/dev/null || true - @icp canister logs backend | grep -q 'trap via update' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 4/11: trap logs 'right before trap' message before trapping ===" - @icp canister logs backend | grep -q 'right before trap' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 5/11: trap_query via update call is recorded in logs ===" - @icp canister call backend trap_query '("trap via replicated query")' 2>/dev/null || true - @icp canister logs backend | grep -q 'trap via replicated query' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 6/11: trap_query logs 'right before trap_query' before trapping ===" - @icp canister logs backend | grep -q 'right before trap_query' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 7/11: memory_oob trap is recorded in logs ===" - @icp canister call backend memory_oob '()' 2>/dev/null || true - @icp canister logs backend | grep -q 'Region error: range out of bounds' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 8/11: memory_oob logs 'right before memory out of bounds' ===" - @icp canister logs backend | grep -q 'right before memory out of bounds' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 9/11: timer trap is recorded in logs (waiting up to 10s) ===" - @sleep 10 && \ - icp canister logs backend | grep -q 'timer trap' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 10/11: raw_rand returns a blob ===" - @result=$$(icp canister call backend raw_rand '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'blob' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 11/11: raw_rand success is recorded in logs ===" - @icp canister logs backend | grep -q 'ic.raw_rand() call succeeded' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/canister_logs/README.md b/motoko/canister_logs/README.md index 41568cd06..44de11506 100644 --- a/motoko/canister_logs/README.md +++ b/motoko/canister_logs/README.md @@ -53,7 +53,7 @@ cd examples/motoko/canister_logs ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` diff --git a/motoko/canister_logs/test.sh b/motoko/canister_logs/test.sh new file mode 100755 index 000000000..e5bec6d73 --- /dev/null +++ b/motoko/canister_logs/test.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +set -e + +echo "=== Test 1/11: print via update call is recorded in logs ===" +icp canister call backend print '("print via update")' && \ + icp canister logs backend | grep -q 'print via update' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2/11: print_query via replicated update call is recorded in logs ===" +icp canister call backend print_query '("print via replicated query")' && \ + icp canister logs backend | grep -q 'print via replicated query' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3/11: trap via update call is recorded in logs ===" +icp canister call backend trap '("trap via update")' 2>/dev/null || true +icp canister logs backend | grep -q 'trap via update' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 4/11: trap logs 'right before trap' message before trapping ===" +icp canister logs backend | grep -q 'right before trap' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 5/11: trap_query via update call is recorded in logs ===" +icp canister call backend trap_query '("trap via replicated query")' 2>/dev/null || true +icp canister logs backend | grep -q 'trap via replicated query' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 6/11: trap_query logs 'right before trap_query' before trapping ===" +icp canister logs backend | grep -q 'right before trap_query' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 7/11: memory_oob trap is recorded in logs ===" +icp canister call backend memory_oob '()' 2>/dev/null || true +icp canister logs backend | grep -q 'Region error: range out of bounds' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 8/11: memory_oob logs 'right before memory out of bounds' ===" +icp canister logs backend | grep -q 'right before memory out of bounds' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 9/11: timer trap is recorded in logs (waiting up to 10s) ===" +sleep 10 && \ + icp canister logs backend | grep -q 'timer trap' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 10/11: raw_rand returns a blob ===" +result=$(icp canister call backend raw_rand '()') && \ + echo "$result" && \ + echo "$result" | grep -q 'blob' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 11/11: raw_rand success is recorded in logs ===" +icp canister logs backend | grep -q 'ic.raw_rand() call succeeded' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/cert-var/Makefile b/motoko/cert-var/Makefile deleted file mode 100644 index 4f22d2983..000000000 --- a/motoko/cert-var/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -.PHONY: test - -test: - @echo "=== Test 1: set stores a value ===" - @icp canister call backend set '(42 : nat32)' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2: get returns the correct stored value ===" - @icp canister call --query backend get '()' | tee /dev/stderr | grep -q 'value = 42' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3: inc increments and returns the new value ===" - @result=$$(icp canister call backend inc '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q '43' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 4: get returns the updated value after inc ===" - @icp canister call --query backend get '()' | tee /dev/stderr | grep -q 'value = 43' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/cert-var/README.md b/motoko/cert-var/README.md index 19bda6f54..d0cd319be 100644 --- a/motoko/cert-var/README.md +++ b/motoko/cert-var/README.md @@ -35,11 +35,11 @@ cd examples/motoko/cert-var ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` -`make test` verifies **functional correctness** only — that values are stored and returned correctly. Cryptographic certificate verification (confirming the query response is authentically signed by the IC) is performed in the browser frontend, not the CLI tests. The icp-cli does not verify certificates on your behalf. +`bash test.sh` verifies **functional correctness** only — that values are stored and returned correctly. Cryptographic certificate verification (confirming the query response is authentically signed by the IC) is performed in the browser frontend, not the CLI tests. The icp-cli does not verify certificates on your behalf. For local frontend development with hot reload: diff --git a/motoko/cert-var/test.sh b/motoko/cert-var/test.sh new file mode 100755 index 000000000..ead3f3679 --- /dev/null +++ b/motoko/cert-var/test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -e + +echo "=== Test 1: set stores a value ===" +icp canister call backend set '(42 : nat32)' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2: get returns the correct stored value ===" +icp canister call --query backend get '()' | tee /dev/stderr | grep -q 'value = 42' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3: inc increments and returns the new value ===" +result=$(icp canister call backend inc '()') && \ + echo "$result" && \ + echo "$result" | grep -q '43' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 4: get returns the updated value after inc ===" +icp canister call --query backend get '()' | tee /dev/stderr | grep -q 'value = 43' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/composite_query/Makefile b/motoko/composite_query/Makefile deleted file mode 100644 index c8b1ce9b8..000000000 --- a/motoko/composite_query/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -.PHONY: test topup - -topup: - icp canister top-up --amount 30t backend - -test: - @echo "=== Test 1: put inserts a key-value pair ===" - @icp canister call backend put '(0, "zero")' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2: get (composite query) retrieves the stored value ===" - @# This exercises the composite query: Map.get calls Bucket.get on a child canister. - @result=$$(icp canister call --query backend get '(0)') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'opt "zero"' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3: getUpdate returns the same value via an update call ===" - @result=$$(icp canister call backend getUpdate '(0)') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'opt "zero"' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 4: get returns null for a missing key ===" - @result=$$(icp canister call --query backend get '(99)') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'null' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 5: composite query routes correctly across all four buckets ===" - @# Keys 0-3 each map to a different bucket (k % 4): 0→B0, 1→B1, 2→B2, 3→B3. - @# The composite query must call the right child canister for each key. - @icp canister call backend put '(1, "one")' && \ - icp canister call backend put '(2, "two")' && \ - icp canister call backend put '(3, "three")' && \ - result0=$$(icp canister call --query backend get '(0)') && \ - result1=$$(icp canister call --query backend get '(1)') && \ - result2=$$(icp canister call --query backend get '(2)') && \ - result3=$$(icp canister call --query backend get '(3)') && \ - echo "$$result0" && echo "$$result1" && echo "$$result2" && echo "$$result3" && \ - echo "$$result0" | grep -q 'opt "zero"' && \ - echo "$$result1" | grep -q 'opt "one"' && \ - echo "$$result2" | grep -q 'opt "two"' && \ - echo "$$result3" | grep -q 'opt "three"' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/composite_query/README.md b/motoko/composite_query/README.md index b665f8dce..340bf03a5 100644 --- a/motoko/composite_query/README.md +++ b/motoko/composite_query/README.md @@ -43,11 +43,11 @@ cd examples/motoko/composite_query ```bash icp network start -d icp deploy --cycles 30t -make test +bash test.sh icp network stop ``` -> `icp deploy --cycles 30t` is required because `Map` dynamically creates `Bucket` canisters — it needs extra cycles to fund their installation. If tests fail with an out-of-cycles error, run `make topup`. +> `icp deploy --cycles 30t` is required because `Map` dynamically creates `Bucket` canisters — it needs extra cycles to fund their installation. If tests fail with an out-of-cycles error, run `icp canister top-up --amount 30t backend`. ## Security considerations and best practices diff --git a/motoko/composite_query/test.sh b/motoko/composite_query/test.sh new file mode 100755 index 000000000..435dd17fb --- /dev/null +++ b/motoko/composite_query/test.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -e + +echo "=== Test 1: put inserts a key-value pair ===" +icp canister call backend put '(0, "zero")' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2: get (composite query) retrieves the stored value ===" +# This exercises the composite query: Map.get calls Bucket.get on a child canister. +result=$(icp canister call --query backend get '(0)') && \ + echo "$result" && \ + echo "$result" | grep -q 'opt "zero"' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3: getUpdate returns the same value via an update call ===" +result=$(icp canister call backend getUpdate '(0)') && \ + echo "$result" && \ + echo "$result" | grep -q 'opt "zero"' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 4: get returns null for a missing key ===" +result=$(icp canister call --query backend get '(99)') && \ + echo "$result" && \ + echo "$result" | grep -q 'null' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 5: composite query routes correctly across all four buckets ===" +# Keys 0-3 each map to a different bucket (k % 4): 0→B0, 1→B1, 2→B2, 3→B3. +# The composite query must call the right child canister for each key. +icp canister call backend put '(1, "one")' && \ + icp canister call backend put '(2, "two")' && \ + icp canister call backend put '(3, "three")' && \ + result0=$(icp canister call --query backend get '(0)') && \ + result1=$(icp canister call --query backend get '(1)') && \ + result2=$(icp canister call --query backend get '(2)') && \ + result3=$(icp canister call --query backend get '(3)') && \ + echo "$result0" && echo "$result1" && echo "$result2" && echo "$result3" && \ + echo "$result0" | grep -q 'opt "zero"' && \ + echo "$result1" | grep -q 'opt "one"' && \ + echo "$result2" | grep -q 'opt "two"' && \ + echo "$result3" | grep -q 'opt "three"' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/daily_planner/Makefile b/motoko/daily_planner/Makefile deleted file mode 100644 index 5e8d4fa4f..000000000 --- a/motoko/daily_planner/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -.PHONY: test - -test: - @echo "=== Test 1/6: getDayData returns null for a date with no notes ===" - @result=$$(icp canister call backend getDayData '("2000-01-15")') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'null' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2/6: addNote returns ok result ===" - @result=$$(icp canister call backend addNote '("2000-01-15", "Buy groceries")') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'ok' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3/6: getDayData returns stored note ===" - @result=$$(icp canister call backend getDayData '("2000-01-15")') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'Buy groceries' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 4/6: getMonthData returns entry for the stored month ===" - @result=$$(icp canister call backend getMonthData '(2000, 1)') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'Buy groceries' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 5/6: completeNote marks note as completed ===" - @icp canister call backend completeNote '("2000-01-15", 0)' && \ - result=$$(icp canister call backend getDayData '("2000-01-15")') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'isCompleted = true' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 6/6: getMonthData returns empty list for a different month ===" - @result=$$(icp canister call backend getMonthData '(1999, 12)') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'vec {}' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/daily_planner/README.md b/motoko/daily_planner/README.md index 18796f8f7..5b8f57cba 100644 --- a/motoko/daily_planner/README.md +++ b/motoko/daily_planner/README.md @@ -22,7 +22,7 @@ cd examples/motoko/daily_planner ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` diff --git a/motoko/daily_planner/test.sh b/motoko/daily_planner/test.sh new file mode 100755 index 000000000..a9d8acb2a --- /dev/null +++ b/motoko/daily_planner/test.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -e + +echo "=== Test 1/6: getDayData returns null for a date with no notes ===" +result=$(icp canister call backend getDayData '("2000-01-15")') && \ + echo "$result" && \ + echo "$result" | grep -q 'null' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2/6: addNote returns ok result ===" +result=$(icp canister call backend addNote '("2000-01-15", "Buy groceries")') && \ + echo "$result" && \ + echo "$result" | grep -q 'ok' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3/6: getDayData returns stored note ===" +result=$(icp canister call backend getDayData '("2000-01-15")') && \ + echo "$result" && \ + echo "$result" | grep -q 'Buy groceries' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 4/6: getMonthData returns entry for the stored month ===" +result=$(icp canister call backend getMonthData '(2000, 1)') && \ + echo "$result" && \ + echo "$result" | grep -q 'Buy groceries' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 5/6: completeNote marks note as completed ===" +icp canister call backend completeNote '("2000-01-15", 0)' && \ + result=$(icp canister call backend getDayData '("2000-01-15")') && \ + echo "$result" && \ + echo "$result" | grep -q 'isCompleted = true' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 6/6: getMonthData returns empty list for a different month ===" +result=$(icp canister call backend getMonthData '(1999, 12)') && \ + echo "$result" && \ + echo "$result" | grep -q 'vec {}' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/filevault/Makefile b/motoko/filevault/Makefile deleted file mode 100644 index 2315e9992..000000000 --- a/motoko/filevault/Makefile +++ /dev/null @@ -1,64 +0,0 @@ -.PHONY: test - -# Cleanup any leftover state from a previous run so tests are idempotent. -test: - @icp canister call backend deleteFile '("test.txt")' >/dev/null 2>&1 || true - - @echo "=== Test 1: getFiles returns empty list for new user ===" - @result=$$(icp canister call backend getFiles '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'vec {}' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2: checkFileExists returns false for non-existent file ===" - @result=$$(icp canister call backend checkFileExists '("test.txt")') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'false' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3: uploadFileChunk stores a file chunk ===" - @result=$$(icp canister call backend uploadFileChunk '("test.txt", blob "\68\65\6c\6c\6f", 0, "text/plain")') && \ - echo "$$result" && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 4: checkFileExists returns true after upload ===" - @result=$$(icp canister call backend checkFileExists '("test.txt")') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'true' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 5: getFiles shows uploaded file ===" - @result=$$(icp canister call backend getFiles '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'test.txt' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 6: getTotalChunks returns 1 after single chunk upload ===" - @result=$$(icp canister call backend getTotalChunks '("test.txt")') && \ - echo "$$result" && \ - echo "$$result" | grep -qF '(1 : nat)' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 7: getFileChunk returns chunk data ===" - @result=$$(icp canister call backend getFileChunk '("test.txt", 0)') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'opt' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 8: getFileType returns file type ===" - @result=$$(icp canister call backend getFileType '("test.txt")') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'text/plain' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 9: deleteFile removes the file ===" - @result=$$(icp canister call backend deleteFile '("test.txt")') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'true' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 10: getFiles is empty after deletion ===" - @result=$$(icp canister call backend getFiles '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'vec {}' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/filevault/README.md b/motoko/filevault/README.md index 7862e07d2..9f1346a2a 100644 --- a/motoko/filevault/README.md +++ b/motoko/filevault/README.md @@ -26,7 +26,7 @@ Start the local network, deploy, and run tests: ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` diff --git a/motoko/filevault/test.sh b/motoko/filevault/test.sh new file mode 100755 index 000000000..eb805e178 --- /dev/null +++ b/motoko/filevault/test.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +set -e + +# Cleanup any leftover state from a previous run so tests are idempotent. +icp canister call backend deleteFile '("test.txt")' >/dev/null 2>&1 || true + +echo "=== Test 1: getFiles returns empty list for new user ===" +result=$(icp canister call backend getFiles '()') && \ + echo "$result" && \ + echo "$result" | grep -q 'vec {}' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2: checkFileExists returns false for non-existent file ===" +result=$(icp canister call backend checkFileExists '("test.txt")') && \ + echo "$result" && \ + echo "$result" | grep -q 'false' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3: uploadFileChunk stores a file chunk ===" +result=$(icp canister call backend uploadFileChunk '("test.txt", blob "\68\65\6c\6c\6f", 0, "text/plain")') && \ + echo "$result" && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 4: checkFileExists returns true after upload ===" +result=$(icp canister call backend checkFileExists '("test.txt")') && \ + echo "$result" && \ + echo "$result" | grep -q 'true' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 5: getFiles shows uploaded file ===" +result=$(icp canister call backend getFiles '()') && \ + echo "$result" && \ + echo "$result" | grep -q 'test.txt' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 6: getTotalChunks returns 1 after single chunk upload ===" +result=$(icp canister call backend getTotalChunks '("test.txt")') && \ + echo "$result" && \ + echo "$result" | grep -qF '(1 : nat)' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 7: getFileChunk returns chunk data ===" +result=$(icp canister call backend getFileChunk '("test.txt", 0)') && \ + echo "$result" && \ + echo "$result" | grep -q 'opt' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 8: getFileType returns file type ===" +result=$(icp canister call backend getFileType '("test.txt")') && \ + echo "$result" && \ + echo "$result" | grep -q 'text/plain' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 9: deleteFile removes the file ===" +result=$(icp canister call backend deleteFile '("test.txt")') && \ + echo "$result" && \ + echo "$result" | grep -q 'true' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 10: getFiles is empty after deletion ===" +result=$(icp canister call backend getFiles '()') && \ + echo "$result" && \ + echo "$result" | grep -q 'vec {}' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/flying_ninja/Makefile b/motoko/flying_ninja/Makefile deleted file mode 100644 index 56727085d..000000000 --- a/motoko/flying_ninja/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -.PHONY: test - -test: - @echo "=== Test 1: isHighScore returns true when leaderboard has fewer than 10 entries ===" - @result=$$(icp canister call backend isHighScore '(0)') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'true' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2: addLeaderboardEntry returns entry in leaderboard ===" - @result=$$(icp canister call backend addLeaderboardEntry '("Alice", 100)') && \ - echo "$$result" && \ - echo "$$result" | grep -q '"Alice"' && \ - echo "$$result" | grep -q '100' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3: getLeaderboard returns persisted entry ===" - @result=$$(icp canister call backend getLeaderboard '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q '"Alice"' && \ - echo "$$result" | grep -q '100' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 4: getRandomness returns a blob ===" - @result=$$(icp canister call backend getRandomness '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'blob' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/flying_ninja/README.md b/motoko/flying_ninja/README.md index 9b0e8b4ba..0c691c325 100644 --- a/motoko/flying_ninja/README.md +++ b/motoko/flying_ninja/README.md @@ -22,7 +22,7 @@ cd examples/motoko/flying_ninja ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` diff --git a/motoko/flying_ninja/test.sh b/motoko/flying_ninja/test.sh new file mode 100755 index 000000000..20051785e --- /dev/null +++ b/motoko/flying_ninja/test.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -e + +echo "=== Test 1: isHighScore returns true when leaderboard has fewer than 10 entries ===" +result=$(icp canister call backend isHighScore '(0)') && \ + echo "$result" && \ + echo "$result" | grep -q 'true' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2: addLeaderboardEntry returns entry in leaderboard ===" +result=$(icp canister call backend addLeaderboardEntry '("Alice", 100)') && \ + echo "$result" && \ + echo "$result" | grep -q '"Alice"' && \ + echo "$result" | grep -q '100' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3: getLeaderboard returns persisted entry ===" +result=$(icp canister call backend getLeaderboard '()') && \ + echo "$result" && \ + echo "$result" | grep -q '"Alice"' && \ + echo "$result" | grep -q '100' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 4: getRandomness returns a blob ===" +result=$(icp canister call backend getRandomness '()') && \ + echo "$result" && \ + echo "$result" | grep -q 'blob' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/hello_cycles/Makefile b/motoko/hello_cycles/Makefile deleted file mode 100644 index 7c76347c5..000000000 --- a/motoko/hello_cycles/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -.PHONY: test - -test: - @echo "=== Test 1: getBalance returns the canister's cycle balance ===" - @result=$$(icp canister call --query backend getBalance '()') && \ - echo "$$result" && \ - echo "$$result" | grep -qE '^\([0-9][0-9_]* : nat\)$$' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2: acceptCycles accepts 1M cycles sent via the proxy canister ===" - @PROXY=$$(icp network status --json | jq -r .proxy_canister_principal) && \ - result=$$(icp canister call backend acceptCycles '()' --proxy "$$PROXY" --cycles 1_000_000) && \ - echo "$$result" && \ - echo "$$result" | grep -qE 'accepted = [1-9]' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3: sendCycles forwards 5M to itself — within limit, refunded = 0 ===" - @# The canister calls its own acceptCycles as receiver (inter-canister self-call). - @# 5M offered < 10M limit, so all cycles are accepted and none are refunded. - @BACKEND_ID=$$(icp canister status backend -i) && \ - result=$$(icp canister call backend sendCycles "(func \"$$BACKEND_ID\".\"acceptCycles\", 5_000_000)") && \ - echo "$$result" && \ - echo "$$result" | grep -q 'refunded = 0' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 4: sendCycles forwards 15M to itself — over limit, refunded = 5_000_000 ===" - @# 15M offered > 10M limit, so 10M are accepted and exactly 5M are refunded. - @BACKEND_ID=$$(icp canister status backend -i) && \ - result=$$(icp canister call backend sendCycles "(func \"$$BACKEND_ID\".\"acceptCycles\", 15_000_000)") && \ - echo "$$result" && \ - echo "$$result" | grep -q 'refunded = 5_000_000' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/hello_cycles/README.md b/motoko/hello_cycles/README.md index 88a6d58b4..85220ac9c 100644 --- a/motoko/hello_cycles/README.md +++ b/motoko/hello_cycles/README.md @@ -23,7 +23,7 @@ Operations 2 and 3 are two perspectives on the same transaction: - Node.js - icp-cli: `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` - ic-mops: `npm install -g ic-mops` -- jq (used in `make test` to read the proxy canister principal) +- jq (used in `bash test.sh` to read the proxy canister principal) ### Install @@ -37,7 +37,7 @@ cd examples/motoko/hello_cycles ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` diff --git a/motoko/hello_cycles/test.sh b/motoko/hello_cycles/test.sh new file mode 100755 index 000000000..39ca2bba8 --- /dev/null +++ b/motoko/hello_cycles/test.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -e + +echo "=== Test 1: getBalance returns the canister's cycle balance ===" +result=$(icp canister call --query backend getBalance '()') && \ + echo "$result" && \ + echo "$result" | grep -qE '^\([0-9][0-9_]* : nat\)$' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2: acceptCycles accepts 1M cycles sent via the proxy canister ===" +PROXY=$(icp network status --json | jq -r .proxy_canister_principal) && \ + result=$(icp canister call backend acceptCycles '()' --proxy "$PROXY" --cycles 1_000_000) && \ + echo "$result" && \ + echo "$result" | grep -qE 'accepted = [1-9]' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3: sendCycles forwards 5M to itself — within limit, refunded = 0 ===" +# The canister calls its own acceptCycles as receiver (inter-canister self-call). +# 5M offered < 10M limit, so all cycles are accepted and none are refunded. +BACKEND_ID=$(icp canister status backend -i) && \ + result=$(icp canister call backend sendCycles "(func \"$BACKEND_ID\".\"acceptCycles\", 5_000_000)") && \ + echo "$result" && \ + echo "$result" | grep -q 'refunded = 0' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 4: sendCycles forwards 15M to itself — over limit, refunded = 5_000_000 ===" +# 15M offered > 10M limit, so 10M are accepted and exactly 5M are refunded. +BACKEND_ID=$(icp canister status backend -i) && \ + result=$(icp canister call backend sendCycles "(func \"$BACKEND_ID\".\"acceptCycles\", 15_000_000)") && \ + echo "$result" && \ + echo "$result" | grep -q 'refunded = 5_000_000' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/hello_world/Makefile b/motoko/hello_world/Makefile deleted file mode 100644 index 7f538e890..000000000 --- a/motoko/hello_world/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -.PHONY: test - -test: - @echo "--- Testing default greeting ---" - @result=$$(icp canister call backend greet '("World")') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'Hello, World!' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "--- Testing setGreeting ---" - @icp canister call backend setGreeting '("Hi, ")' - @result=$$(icp canister call backend greet '("Alice")') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'Hi, Alice!' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/hello_world/test.sh b/motoko/hello_world/test.sh new file mode 100755 index 000000000..0131c8887 --- /dev/null +++ b/motoko/hello_world/test.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -e + +echo "--- Testing default greeting ---" +result=$(icp canister call backend greet '("World")') +echo "$result" +echo "$result" | grep -q 'Hello, World!' && echo "PASS" || (echo "FAIL" && exit 1) + +echo "--- Testing setGreeting ---" +icp canister call backend setGreeting '("Hi, ")' +result=$(icp canister call backend greet '("Alice")') +echo "$result" +echo "$result" | grep -q 'Hi, Alice!' && echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/icp_transfer/Makefile b/motoko/icp_transfer/Makefile deleted file mode 100644 index a5da623a1..000000000 --- a/motoko/icp_transfer/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -.PHONY: test - -# Tests use a single shell block so all variables and functions stay in scope. -# Balance checks are delta-based so the tests are idempotent across re-runs. -# -# Transfer amount is 99_990_000 e8s so that amount + fee (10_000) = 100_000_000 e8s -# = exactly 1 ICP deducted per transfer. Two tests drain the 2 ICP funding to zero. -test: - @set -e; \ - \ - backend=$$(icp canister status backend -i); \ - recipient=$$(icp identity principal); \ - echo "Backend: $$backend"; \ - echo "Recipient: $$recipient"; \ - \ - get_balance() { \ - icp token balance -q --of-principal "$$1" \ - | awk '{printf "%.0f", $$1 * 100000000}'; \ - }; \ - \ - echo "=== Test 1: toAccountIdHex matches icp identity account-id ==="; \ - cli_hex=$$(icp identity account-id --format ledger); \ - backend_hex=$$(icp canister call --query backend toAccountIdHex \ - "(principal \"$$recipient\", null)" | grep -oE '[0-9a-f]{64}'); \ - echo " icp identity account-id: $$cli_hex"; \ - echo " backend toAccountIdHex: $$backend_hex"; \ - [ "$$cli_hex" = "$$backend_hex" ] || (echo "FAIL: hex values differ" && exit 1); \ - echo " PASS"; \ - \ - echo "=== Setup: fund backend with 2 ICP ==="; \ - icp token transfer 2 "$$backend"; \ - \ - echo "=== Test 2: transferToPrincipal — deducts exactly 1 ICP (99_990_000 amount + 10_000 fee) ==="; \ - backend_before=$$(get_balance "$$backend"); \ - recipient_before=$$(get_balance "$$recipient"); \ - result=$$(icp canister call backend transferToPrincipal \ - "(record { e8s = 99_990_000 : nat64 }, principal \"$$recipient\", null)"); \ - echo " result: $$result"; \ - echo "$$result" | grep -q 'ok' || (echo "FAIL: transfer rejected" && exit 1); \ - backend_after=$$(get_balance "$$backend"); \ - recipient_after=$$(get_balance "$$recipient"); \ - echo " backend: $$backend_before → $$backend_after (delta $$((backend_after - backend_before)))"; \ - echo " recipient: $$recipient_before → $$recipient_after (delta $$((recipient_after - recipient_before)))"; \ - [ "$$((backend_after - backend_before))" -eq -100000000 ] || (echo "FAIL: expected backend delta -100000000 e8s" && exit 1); \ - [ "$$((recipient_after - recipient_before))" -eq 99990000 ] || (echo "FAIL: expected recipient delta +99990000 e8s" && exit 1); \ - echo " PASS"; \ - \ - echo "=== Test 3: transferToAccountId — same recipient, same deduction ==="; \ - echo " AccountIdentifier hex: $$cli_hex"; \ - backend_before=$$(get_balance "$$backend"); \ - recipient_before=$$(get_balance "$$recipient"); \ - result=$$(icp canister call backend transferToAccountId \ - "(record { e8s = 99_990_000 : nat64 }, \"$$cli_hex\")"); \ - echo " result: $$result"; \ - echo "$$result" | grep -q 'ok' || (echo "FAIL: transfer rejected" && exit 1); \ - backend_after=$$(get_balance "$$backend"); \ - recipient_after=$$(get_balance "$$recipient"); \ - echo " backend: $$backend_before → $$backend_after (delta $$((backend_after - backend_before)))"; \ - echo " recipient: $$recipient_before → $$recipient_after (delta $$((recipient_after - recipient_before)))"; \ - [ "$$((backend_after - backend_before))" -eq -100000000 ] || (echo "FAIL: expected backend delta -100000000 e8s" && exit 1); \ - [ "$$((recipient_after - recipient_before))" -eq 99990000 ] || (echo "FAIL: expected recipient delta +99990000 e8s" && exit 1); \ - echo " PASS — same recipient reached via AccountIdentifier hex as via principal" diff --git a/motoko/icp_transfer/README.md b/motoko/icp_transfer/README.md index ae0804b57..79f9d736a 100644 --- a/motoko/icp_transfer/README.md +++ b/motoko/icp_transfer/README.md @@ -27,11 +27,11 @@ The example exposes three functions to make this concrete: ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` -`make test` funds the backend with 2 ICP, then: +`bash test.sh` funds the backend with 2 ICP, then: 1. Compares `icp identity account-id --format ledger` with `toAccountIdHex` to verify the CLI and the backend compute the same AccountIdentifier. 2. Calls `transferToPrincipal` — transfers 99_990_000 e8s (amount) + 10_000 e8s (fee) = exactly 1 ICP deducted from the backend; confirms both sides via `icp token balance`. 3. Calls `transferToAccountId` with the hex string from step 1 — same 1 ICP deduction, confirming both transfer paths reach the same account and the backend balance reaches zero. diff --git a/motoko/icp_transfer/test.sh b/motoko/icp_transfer/test.sh new file mode 100755 index 000000000..a8951a14d --- /dev/null +++ b/motoko/icp_transfer/test.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +set -e + +# Tests use a single shell block so all variables and functions stay in scope. +# Balance checks are delta-based so the tests are idempotent across re-runs. +# +# Transfer amount is 99_990_000 e8s so that amount + fee (10_000) = 100_000_000 e8s +# = exactly 1 ICP deducted per transfer. Two tests drain the 2 ICP funding to zero. + +backend=$(icp canister status backend -i) +recipient=$(icp identity principal) +echo "Backend: $backend" +echo "Recipient: $recipient" + +get_balance() { + icp token balance -q --of-principal "$1" \ + | awk '{printf "%.0f", $1 * 100000000}' +} + +echo "=== Test 1: toAccountIdHex matches icp identity account-id ===" +cli_hex=$(icp identity account-id --format ledger) +backend_hex=$(icp canister call --query backend toAccountIdHex \ + "(principal \"$recipient\", null)" | grep -oE '[0-9a-f]{64}') +echo " icp identity account-id: $cli_hex" +echo " backend toAccountIdHex: $backend_hex" +[ "$cli_hex" = "$backend_hex" ] || (echo "FAIL: hex values differ" && exit 1) +echo " PASS" + +echo "=== Setup: fund backend with 2 ICP ===" +icp token transfer 2 "$backend" + +echo "=== Test 2: transferToPrincipal — deducts exactly 1 ICP (99_990_000 amount + 10_000 fee) ===" +backend_before=$(get_balance "$backend") +recipient_before=$(get_balance "$recipient") +result=$(icp canister call backend transferToPrincipal \ + "(record { e8s = 99_990_000 : nat64 }, principal \"$recipient\", null)") +echo " result: $result" +echo "$result" | grep -q 'ok' || (echo "FAIL: transfer rejected" && exit 1) +backend_after=$(get_balance "$backend") +recipient_after=$(get_balance "$recipient") +echo " backend: $backend_before → $backend_after (delta $((backend_after - backend_before)))" +echo " recipient: $recipient_before → $recipient_after (delta $((recipient_after - recipient_before)))" +[ "$((backend_after - backend_before))" -eq -100000000 ] || (echo "FAIL: expected backend delta -100000000 e8s" && exit 1) +[ "$((recipient_after - recipient_before))" -eq 99990000 ] || (echo "FAIL: expected recipient delta +99990000 e8s" && exit 1) +echo " PASS" + +echo "=== Test 3: transferToAccountId — same recipient, same deduction ===" +echo " AccountIdentifier hex: $cli_hex" +backend_before=$(get_balance "$backend") +recipient_before=$(get_balance "$recipient") +result=$(icp canister call backend transferToAccountId \ + "(record { e8s = 99_990_000 : nat64 }, \"$cli_hex\")") +echo " result: $result" +echo "$result" | grep -q 'ok' || (echo "FAIL: transfer rejected" && exit 1) +backend_after=$(get_balance "$backend") +recipient_after=$(get_balance "$recipient") +echo " backend: $backend_before → $backend_after (delta $((backend_after - backend_before)))" +echo " recipient: $recipient_before → $recipient_after (delta $((recipient_after - recipient_before)))" +[ "$((backend_after - backend_before))" -eq -100000000 ] || (echo "FAIL: expected backend delta -100000000 e8s" && exit 1) +[ "$((recipient_after - recipient_before))" -eq 99990000 ] || (echo "FAIL: expected recipient delta +99990000 e8s" && exit 1) +echo " PASS — same recipient reached via AccountIdentifier hex as via principal" diff --git a/motoko/icrc2-swap/Makefile b/motoko/icrc2-swap/Makefile deleted file mode 100644 index 5f21890bb..000000000 --- a/motoko/icrc2-swap/Makefile +++ /dev/null @@ -1,141 +0,0 @@ -.PHONY: deploy test - -# Deploy all canisters in the correct order: -# 1. Create example-specific test identities (icrc2-alice, icrc2-bob) if not present. -# 2. Deploy token_a (pre-funded for alice) and token_b (pre-funded for bob). -# 3. Deploy backend — discovers token principals automatically via env vars. -# -# Note: use `make deploy` (not `icp deploy`) — the ledger canisters require -# init args with alice/bob principals that are only available after the -# identities are created. -deploy: - @set -e; \ - MINTER=$$(icp identity principal); \ - icp identity new icrc2-alice --storage plaintext 2>/dev/null || true; \ - icp identity new icrc2-bob --storage plaintext 2>/dev/null || true; \ - ALICE=$$(icp identity principal --identity icrc2-alice); \ - BOB=$$(icp identity principal --identity icrc2-bob); \ - icp deploy token_a --mode reinstall -y --args "(variant { Init = record { \ - token_name = \"Token A\"; token_symbol = \"A\"; \ - minting_account = record { owner = principal \"$$MINTER\" }; \ - initial_balances = vec { record { record { owner = principal \"$$ALICE\" }; 100_000_000_000_000 : nat } }; \ - metadata = vec {}; transfer_fee = 10_000 : nat; \ - archive_options = record { trigger_threshold = 2000 : nat64; num_blocks_to_archive = 1000 : nat64; controller_id = principal \"$$MINTER\" }; \ - feature_flags = opt record { icrc2 = true } } })"; \ - icp deploy token_b --mode reinstall -y --args "(variant { Init = record { \ - token_name = \"Token B\"; token_symbol = \"B\"; \ - minting_account = record { owner = principal \"$$MINTER\" }; \ - initial_balances = vec { record { record { owner = principal \"$$BOB\" }; 100_000_000_000_000 : nat } }; \ - metadata = vec {}; transfer_fee = 10_000 : nat; \ - archive_options = record { trigger_threshold = 2000 : nat64; num_blocks_to_archive = 1000 : nat64; controller_id = principal \"$$MINTER\" }; \ - feature_flags = opt record { icrc2 = true } } })"; \ - icp deploy backend --mode reinstall -y - -# Full integration test: icrc2-alice deposits token_a, icrc2-bob deposits token_b, -# they swap 1:1, and each withdraws the other's token. -test: - $(eval TOKEN_A := $(shell icp canister status token_a -i)) - $(eval TOKEN_B := $(shell icp canister status token_b -i)) - $(eval ALICE := $(shell icp identity principal --identity icrc2-alice)) - $(eval BOB := $(shell icp identity principal --identity icrc2-bob)) - $(eval SWAP := $(shell icp canister status backend -i)) - - @echo "=== Test 1: balances returns empty lists initially ===" - @result=$$(icp canister call --query backend balances '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'vec {}' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2: swap with no deposits returns InsufficientBalance ===" - @result=$$(icp canister call backend swap "(record { \ - user_a = principal \"$(ALICE)\"; \ - user_b = principal \"$(BOB)\" \ - })") && \ - echo "$$result" && \ - echo "$$result" | grep -q 'InsufficientBalance' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3: icrc2-alice approves and deposits token_a ===" - @# Approve amount = deposit (100_000_000) + transfer_fee (10_000) = 100_010_000. - @# The ledger charges a fee on icrc2_transfer_from, so the approval must cover it. - @icp canister call --identity icrc2-alice token_a icrc2_approve "(record { \ - amount = 100_010_000 : nat; \ - spender = record { owner = principal \"$(SWAP)\"; subaccount = null }; \ - expires_at = null; expected_allowance = null; fee = null; \ - from_subaccount = null; memo = null; created_at_time = null \ - })" - @result=$$(icp canister call --identity icrc2-alice backend deposit "(record { \ - token = principal \"$(TOKEN_A)\"; \ - from = record { owner = principal \"$(ALICE)\"; subaccount = null }; \ - amount = 100_000_000 : nat; \ - spender_subaccount = null; fee = null; memo = null; created_at_time = null \ - })") && \ - echo "$$result" && \ - echo "$$result" | grep -q 'ok' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 4: icrc2-bob approves and deposits token_b ===" - @icp canister call --identity icrc2-bob token_b icrc2_approve "(record { \ - amount = 100_010_000 : nat; \ - spender = record { owner = principal \"$(SWAP)\"; subaccount = null }; \ - expires_at = null; expected_allowance = null; fee = null; \ - from_subaccount = null; memo = null; created_at_time = null \ - })" - @result=$$(icp canister call --identity icrc2-bob backend deposit "(record { \ - token = principal \"$(TOKEN_B)\"; \ - from = record { owner = principal \"$(BOB)\"; subaccount = null }; \ - amount = 100_000_000 : nat; \ - spender_subaccount = null; fee = null; memo = null; created_at_time = null \ - })") && \ - echo "$$result" && \ - echo "$$result" | grep -q 'ok' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 5: swap alice's token_a for bob's token_b ===" - @result=$$(icp canister call backend swap "(record { \ - user_a = principal \"$(ALICE)\"; \ - user_b = principal \"$(BOB)\" \ - })") && \ - echo "$$result" && \ - echo "$$result" | grep -q 'ok' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 6: alice withdraws token_b (received via swap) ===" - @# The backend deducts (amount + transfer_fee) from alice's internal balance. - @# Internal balance = 100_000_000; withdraw 99_990_000 so deduction = 99_990_000 + 10_000 = 100_000_000. - @set -e; \ - before=$$(icp canister call --query token_b icrc1_balance_of \ - "(record { owner = principal \"$(ALICE)\"; subaccount = null })" | grep -oE '[0-9_]+' | tr -d '_'); \ - result=$$(icp canister call --identity icrc2-alice backend withdraw "(record { \ - token = principal \"$(TOKEN_B)\"; \ - to = record { owner = principal \"$(ALICE)\"; subaccount = null }; \ - amount = 99_990_000 : nat; \ - fee = null; memo = null; created_at_time = null \ - })"); \ - echo "$$result"; \ - echo "$$result" | grep -q 'ok' || (echo "FAIL" && exit 1); \ - after=$$(icp canister call --query token_b icrc1_balance_of \ - "(record { owner = principal \"$(ALICE)\"; subaccount = null })" | grep -oE '[0-9_]+' | tr -d '_'); \ - delta=$$((after - before)); \ - echo "token_b balance: before=$$before after=$$after delta=$$delta"; \ - [ "$$delta" -eq 99990000 ] || (echo "FAIL: expected delta 99990000" && exit 1); \ - echo "PASS" - - @echo "=== Test 7: bob withdraws token_a (received via swap) ===" - @set -e; \ - before=$$(icp canister call --query token_a icrc1_balance_of \ - "(record { owner = principal \"$(BOB)\"; subaccount = null })" | grep -oE '[0-9_]+' | tr -d '_'); \ - result=$$(icp canister call --identity icrc2-bob backend withdraw "(record { \ - token = principal \"$(TOKEN_A)\"; \ - to = record { owner = principal \"$(BOB)\"; subaccount = null }; \ - amount = 99_990_000 : nat; \ - fee = null; memo = null; created_at_time = null \ - })"); \ - echo "$$result"; \ - echo "$$result" | grep -q 'ok' || (echo "FAIL" && exit 1); \ - after=$$(icp canister call --query token_a icrc1_balance_of \ - "(record { owner = principal \"$(BOB)\"; subaccount = null })" | grep -oE '[0-9_]+' | tr -d '_'); \ - delta=$$((after - before)); \ - echo "token_a balance: before=$$before after=$$after delta=$$delta"; \ - [ "$$delta" -eq 99990000 ] || (echo "FAIL: expected delta 99990000" && exit 1); \ - echo "PASS" diff --git a/motoko/icrc2-swap/README.md b/motoko/icrc2-swap/README.md index ed0e818ce..388b396d5 100644 --- a/motoko/icrc2-swap/README.md +++ b/motoko/icrc2-swap/README.md @@ -49,7 +49,7 @@ cd examples/motoko/icrc2-swap ```bash icp network start -d make deploy -make test +bash test.sh icp network stop ``` @@ -60,7 +60,7 @@ icp network stop 2. Deploys `token_a` pre-funded for `icrc2-alice` and `token_b` pre-funded for `icrc2-bob`. 3. Deploys `backend` — no init args needed; it discovers the token principals via injected environment variables. -`make test` runs the full swap flow with `icrc2-alice` and `icrc2-bob` as the two parties. Test 2 verifies that swapping with no deposits returns `InsufficientBalance`. Tests 6 and 7 verify the actual token balance delta in the ledger after withdrawal, confirming the full round-trip. Tests are idempotent — they can be run multiple times without redeploying. +`bash test.sh` runs the full swap flow with `icrc2-alice` and `icrc2-bob` as the two parties. Test 2 verifies that swapping with no deposits returns `InsufficientBalance`. Tests 6 and 7 verify the actual token balance delta in the ledger after withdrawal, confirming the full round-trip. Tests are idempotent — they can be run multiple times without redeploying. ## Fee handling diff --git a/motoko/icrc2-swap/test.sh b/motoko/icrc2-swap/test.sh new file mode 100755 index 000000000..b78ec0736 --- /dev/null +++ b/motoko/icrc2-swap/test.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +set -e + +TOKEN_A=$(icp canister status token_a -i) +TOKEN_B=$(icp canister status token_b -i) +ALICE=$(icp identity principal --identity icrc2-alice) +BOB=$(icp identity principal --identity icrc2-bob) +SWAP=$(icp canister status backend -i) + +echo "=== Test 1: balances returns empty lists initially ===" +result=$(icp canister call --query backend balances '()') && \ + echo "$result" && \ + echo "$result" | grep -q 'vec {}' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2: swap with no deposits returns InsufficientBalance ===" +result=$(icp canister call backend swap "(record { \ + user_a = principal \"$ALICE\"; \ + user_b = principal \"$BOB\" \ +})") && \ + echo "$result" && \ + echo "$result" | grep -q 'InsufficientBalance' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3: icrc2-alice approves and deposits token_a ===" +# Approve amount = deposit (100_000_000) + transfer_fee (10_000) = 100_010_000. +# The ledger charges a fee on icrc2_transfer_from, so the approval must cover it. +icp canister call --identity icrc2-alice token_a icrc2_approve "(record { \ + amount = 100_010_000 : nat; \ + spender = record { owner = principal \"$SWAP\"; subaccount = null }; \ + expires_at = null; expected_allowance = null; fee = null; \ + from_subaccount = null; memo = null; created_at_time = null \ +})" +result=$(icp canister call --identity icrc2-alice backend deposit "(record { \ + token = principal \"$TOKEN_A\"; \ + from = record { owner = principal \"$ALICE\"; subaccount = null }; \ + amount = 100_000_000 : nat; \ + spender_subaccount = null; fee = null; memo = null; created_at_time = null \ +})") && \ + echo "$result" && \ + echo "$result" | grep -q 'ok' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 4: icrc2-bob approves and deposits token_b ===" +icp canister call --identity icrc2-bob token_b icrc2_approve "(record { \ + amount = 100_010_000 : nat; \ + spender = record { owner = principal \"$SWAP\"; subaccount = null }; \ + expires_at = null; expected_allowance = null; fee = null; \ + from_subaccount = null; memo = null; created_at_time = null \ +})" +result=$(icp canister call --identity icrc2-bob backend deposit "(record { \ + token = principal \"$TOKEN_B\"; \ + from = record { owner = principal \"$BOB\"; subaccount = null }; \ + amount = 100_000_000 : nat; \ + spender_subaccount = null; fee = null; memo = null; created_at_time = null \ +})") && \ + echo "$result" && \ + echo "$result" | grep -q 'ok' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 5: swap alice's token_a for bob's token_b ===" +result=$(icp canister call backend swap "(record { \ + user_a = principal \"$ALICE\"; \ + user_b = principal \"$BOB\" \ +})") && \ + echo "$result" && \ + echo "$result" | grep -q 'ok' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 6: alice withdraws token_b (received via swap) ===" +# The backend deducts (amount + transfer_fee) from alice's internal balance. +# Internal balance = 100_000_000; withdraw 99_990_000 so deduction = 99_990_000 + 10_000 = 100_000_000. +before=$(icp canister call --query token_b icrc1_balance_of \ + "(record { owner = principal \"$ALICE\"; subaccount = null })" | grep -oE '[0-9_]+' | tr -d '_') +result=$(icp canister call --identity icrc2-alice backend withdraw "(record { \ + token = principal \"$TOKEN_B\"; \ + to = record { owner = principal \"$ALICE\"; subaccount = null }; \ + amount = 99_990_000 : nat; \ + fee = null; memo = null; created_at_time = null \ +})") +echo "$result" +echo "$result" | grep -q 'ok' || (echo "FAIL" && exit 1) +after=$(icp canister call --query token_b icrc1_balance_of \ + "(record { owner = principal \"$ALICE\"; subaccount = null })" | grep -oE '[0-9_]+' | tr -d '_') +delta=$((after - before)) +echo "token_b balance: before=$before after=$after delta=$delta" +[ "$delta" -eq 99990000 ] || (echo "FAIL: expected delta 99990000" && exit 1) +echo "PASS" + +echo "=== Test 7: bob withdraws token_a (received via swap) ===" +before=$(icp canister call --query token_a icrc1_balance_of \ + "(record { owner = principal \"$BOB\"; subaccount = null })" | grep -oE '[0-9_]+' | tr -d '_') +result=$(icp canister call --identity icrc2-bob backend withdraw "(record { \ + token = principal \"$TOKEN_A\"; \ + to = record { owner = principal \"$BOB\"; subaccount = null }; \ + amount = 99_990_000 : nat; \ + fee = null; memo = null; created_at_time = null \ +})") +echo "$result" +echo "$result" | grep -q 'ok' || (echo "FAIL" && exit 1) +after=$(icp canister call --query token_a icrc1_balance_of \ + "(record { owner = principal \"$BOB\"; subaccount = null })" | grep -oE '[0-9_]+' | tr -d '_') +delta=$((after - before)) +echo "token_a balance: before=$before after=$after delta=$delta" +[ "$delta" -eq 99990000 ] || (echo "FAIL: expected delta 99990000" && exit 1) +echo "PASS" diff --git a/motoko/low_wasm_memory/Makefile b/motoko/low_wasm_memory/Makefile deleted file mode 100644 index 8586bf55f..000000000 --- a/motoko/low_wasm_memory/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -.PHONY: configure test - -# Set wasm_memory_limit to 5 MiB and wasm_memory_threshold to 2 MiB. -# The low Wasm memory hook fires when remaining Wasm memory falls below the -# threshold (i.e. when usage exceeds limit - threshold = 3 MiB). -configure: - icp canister settings update backend \ - --wasm-memory-limit 5mib \ - --wasm-memory-threshold 2mib \ - -f - -test: configure - @echo "=== Polling for onLowWasmMemory hook (up to 60s) ===" - @secs=0; \ - while [ $$secs -lt 60 ]; do \ - result=$$(icp canister call --query backend getExecutedFunctionsOrder '()') || \ - { echo "FAIL: canister call failed"; exit 1; }; \ - echo "$$result"; \ - echo "$$result" | grep -q 'onLowWasmMemory' && echo "PASS" && exit 0; \ - sleep 3; secs=$$((secs + 3)); \ - done; \ - echo "FAIL: onLowWasmMemory hook did not fire within 60s"; exit 1 diff --git a/motoko/low_wasm_memory/README.md b/motoko/low_wasm_memory/README.md index 237db2fa2..ebf260215 100644 --- a/motoko/low_wasm_memory/README.md +++ b/motoko/low_wasm_memory/README.md @@ -24,11 +24,11 @@ cd examples/motoko/low_wasm_memory ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` -`make test` does two things: +`bash test.sh` does two things: 1. **Configures the canister settings**: sets `wasm_memory_limit` to 5 MiB and `wasm_memory_threshold` to 2 MiB. This means the `lowmemory` hook fires when remaining Wasm memory falls below 2 MiB (i.e. when usage exceeds 3 MiB). The canister starts with ~2.3 MiB of usage after deployment, so the hook triggers after allocating roughly 0.7 MiB more. diff --git a/motoko/low_wasm_memory/test.sh b/motoko/low_wasm_memory/test.sh new file mode 100755 index 000000000..27124aa47 --- /dev/null +++ b/motoko/low_wasm_memory/test.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -e + +# Set wasm_memory_limit to 5 MiB and wasm_memory_threshold to 2 MiB. +# The low Wasm memory hook fires when remaining Wasm memory falls below the +# threshold (i.e. when usage exceeds limit - threshold = 3 MiB). +icp canister settings update backend \ + --wasm-memory-limit 5mib \ + --wasm-memory-threshold 2mib \ + -f + +echo "=== Polling for onLowWasmMemory hook (up to 60s) ===" +secs=0 +while [ $secs -lt 60 ]; do + result=$(icp canister call --query backend getExecutedFunctionsOrder '()') || \ + { echo "FAIL: canister call failed"; exit 1; } + echo "$result" + echo "$result" | grep -q 'onLowWasmMemory' && echo "PASS" && exit 0 + sleep 3; secs=$((secs + 3)) +done +echo "FAIL: onLowWasmMemory hook did not fire within 60s"; exit 1 diff --git a/motoko/parallel_calls/Makefile b/motoko/parallel_calls/Makefile deleted file mode 100644 index a3511511e..000000000 --- a/motoko/parallel_calls/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -.PHONY: test test-multi-subnet - -test: - @echo "=== Test 1: sequential_calls(10) — all 10 succeed ===" - @result=$$(icp canister call caller sequential_calls '(10)') && \ - echo "$$result" && \ - echo "$$result" | grep -q '(10 : nat)' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2: parallel_calls(10) — all 10 succeed (same result as sequential at low n) ===" - @result=$$(icp canister call caller parallel_calls '(10)') && \ - echo "$$result" && \ - echo "$$result" | grep -q '(10 : nat)' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3: sequential_calls(2000) — all succeed (one in-flight at a time) ===" - @result=$$(icp canister call caller sequential_calls '(2000)') && \ - echo "$$result" && \ - echo "$$result" | grep -q '(2_000 : nat)' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 4: parallel_calls(2000) — fewer succeed (in-flight limit exceeded) ===" - @# The replica limits in-flight calls per canister, so most parallel calls fail at n=2000. - @# Extract the number and assert it is strictly less than 2000. - @result=$$(icp canister call caller parallel_calls '(2000)') && \ - echo "$$result" && \ - n=$$(echo "$$result" | grep -oE '[0-9_]+' | head -1 | tr -d '_') && \ - [ "$$n" -lt 2000 ] && \ - echo "PASS" || (echo "FAIL" && exit 1) - -test-multi-subnet: - @echo "=== Building Motoko WASMs ===" - icp build - @echo "=== Running multi-subnet PocketIC test ===" - CALLER_WASM=.mops/.build/caller.wasm \ - CALLEE_WASM=.mops/.build/callee.wasm \ - cargo run --manifest-path multi_subnet/Cargo.toml diff --git a/motoko/parallel_calls/README.md b/motoko/parallel_calls/README.md index 6ae7e837c..49e3e4f38 100644 --- a/motoko/parallel_calls/README.md +++ b/motoko/parallel_calls/README.md @@ -55,7 +55,7 @@ cd examples/motoko/parallel_calls ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` diff --git a/motoko/parallel_calls/test.sh b/motoko/parallel_calls/test.sh new file mode 100755 index 000000000..f1b990042 --- /dev/null +++ b/motoko/parallel_calls/test.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -e + +echo "=== Test 1: sequential_calls(10) — all 10 succeed ===" +result=$(icp canister call caller sequential_calls '(10)') && \ + echo "$result" && \ + echo "$result" | grep -q '(10 : nat)' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2: parallel_calls(10) — all 10 succeed (same result as sequential at low n) ===" +result=$(icp canister call caller parallel_calls '(10)') && \ + echo "$result" && \ + echo "$result" | grep -q '(10 : nat)' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3: sequential_calls(2000) — all succeed (one in-flight at a time) ===" +result=$(icp canister call caller sequential_calls '(2000)') && \ + echo "$result" && \ + echo "$result" | grep -q '(2_000 : nat)' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 4: parallel_calls(2000) — fewer succeed (in-flight limit exceeded) ===" +# The replica limits in-flight calls per canister, so most parallel calls fail at n=2000. +# Extract the number and assert it is strictly less than 2000. +result=$(icp canister call caller parallel_calls '(2000)') && \ + echo "$result" && \ + n=$(echo "$result" | grep -oE '[0-9_]+' | head -1 | tr -d '_') && \ + [ "$n" -lt 2000 ] && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/pub-sub/Makefile b/motoko/pub-sub/Makefile deleted file mode 100644 index a00616657..000000000 --- a/motoko/pub-sub/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -.PHONY: test - -# Note: these tests assume a freshly deployed canister state. -# To re-run from scratch: icp deploy --mode reinstall -y && make test -test: - @echo "=== Test 1: subscriber registers with publisher for the 'Apples' topic ===" - @icp canister call subscriber subscribe '("Apples")' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2: initial count is zero ===" - @result=$$(icp canister call --query subscriber getCount '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q '(0 : nat)' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3: publishing to 'Apples' triggers the callback and increases the count ===" - @# publish fires callbacks asynchronously; sleep gives the callback time to arrive. - @icp canister call publisher publish '(record { topic = "Apples"; value = 2 })' && \ - sleep 2 && \ - result=$$(icp canister call --query subscriber getCount '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q '(2 : nat)' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 4: publishing to 'Bananas' is ignored (not subscribed) ===" - @icp canister call publisher publish '(record { topic = "Bananas"; value = 3 })' && \ - sleep 2 && \ - result=$$(icp canister call --query subscriber getCount '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q '(2 : nat)' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/pub-sub/README.md b/motoko/pub-sub/README.md index d6baa7cdc..1e2572950 100644 --- a/motoko/pub-sub/README.md +++ b/motoko/pub-sub/README.md @@ -26,7 +26,7 @@ The callback (`subscriber.updateCount`) is a **shared function reference** — a Note: `publish` fires callbacks asynchronously. There is a brief delay before the subscriber state is updated, which is why the tests sleep briefly after publishing. -> `make test` assumes a freshly deployed state. To re-run locally without restarting the network, reinstall the canisters first: `icp deploy --mode reinstall -y && make test`. +> `bash test.sh` assumes a freshly deployed state. To re-run locally without restarting the network, reinstall the canisters first: `icp deploy --mode reinstall -y && bash test.sh`. ## Build and deploy from the command line @@ -48,7 +48,7 @@ cd examples/motoko/pub-sub ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` diff --git a/motoko/pub-sub/test.sh b/motoko/pub-sub/test.sh new file mode 100755 index 000000000..52db7760e --- /dev/null +++ b/motoko/pub-sub/test.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -e + +# Note: these tests assume a freshly deployed canister state. +# To re-run from scratch: icp deploy --mode reinstall -y && bash test.sh + +echo "=== Test 1: subscriber registers with publisher for the 'Apples' topic ===" +icp canister call subscriber subscribe '("Apples")' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2: initial count is zero ===" +result=$(icp canister call --query subscriber getCount '()') && \ + echo "$result" && \ + echo "$result" | grep -q '(0 : nat)' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3: publishing to 'Apples' triggers the callback and increases the count ===" +# publish fires callbacks asynchronously; sleep gives the callback time to arrive. +icp canister call publisher publish '(record { topic = "Apples"; value = 2 })' && \ + sleep 2 && \ + result=$(icp canister call --query subscriber getCount '()') && \ + echo "$result" && \ + echo "$result" | grep -q '(2 : nat)' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 4: publishing to 'Bananas' is ignored (not subscribed) ===" +icp canister call publisher publish '(record { topic = "Bananas"; value = 3 })' && \ + sleep 2 && \ + result=$(icp canister call --query subscriber getCount '()') && \ + echo "$result" && \ + echo "$result" | grep -q '(2 : nat)' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/query_stats/Makefile b/motoko/query_stats/Makefile deleted file mode 100644 index 732cad3d9..000000000 --- a/motoko/query_stats/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -.PHONY: test test-stats - -# Fast structural test — verifies the API shape and that load() works. -# Query stats will show 0 due to the 2-epoch aggregation delay; use -# `make test-stats` to wait for aggregation and verify non-zero values. -test: - @echo "=== Test 1/2: load() returns a non-zero timestamp ===" - @# --query ensures this call is recorded in query_stats (update calls are not tracked) - @result=$$(icp canister call --query backend load '()') && \ - echo "$$result" && \ - echo "$$result" | grep -qE '\([0-9][0-9_]* : int\)' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2/2: get_current_query_stats_as_string() returns the four expected fields ===" - @result=$$(icp canister call backend get_current_query_stats_as_string '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'Number of calls' && \ - echo "$$result" | grep -q 'Number of instructions' && \ - echo "$$result" | grep -q 'Request payload bytes' && \ - echo "$$result" | grep -q 'Response payload bytes' && \ - echo "PASS" || (echo "FAIL" && exit 1) - -# Full demonstration — continuously makes query calls until stats become non-zero. -# -# Key requirements: -# 1. Only --query calls count (update calls not tracked in query_stats) -# 2. PocketIC uses integer division (num_calls /= 13 nodes) — need 13+ calls per round -# 3. set_epoch_from_height is only called DURING query execution, so queries must -# keep running to flush stats when epoch boundaries are crossed -test-stats: - @echo "=== Polling query stats (making 13 --query calls every 3s, up to 30s) ===" - @secs=0; \ - while [ $$secs -lt 30 ]; do \ - for i in $$(seq 1 13); do \ - icp canister call --query backend load '()' > /dev/null; \ - done; \ - result=$$(icp canister call backend get_current_query_stats_as_string '()'); \ - echo "$$result" | grep -qE 'Number of calls: [1-9]' && \ - echo "$$result" && echo "PASS: query stats are non-zero (after ~$${secs}s)" && exit 0; \ - sleep 3; \ - secs=$$(($$secs + 3)); \ - done; \ - result=$$(icp canister call backend get_current_query_stats_as_string '()'); \ - echo "$$result"; \ - echo "FAIL: stats still 0 after 30s" && exit 1 diff --git a/motoko/query_stats/README.md b/motoko/query_stats/README.md index 8c5c14acc..43f3de7cb 100644 --- a/motoko/query_stats/README.md +++ b/motoko/query_stats/README.md @@ -9,7 +9,7 @@ Query stats are **aggregated with a 2-epoch delay**, not updated per call: - Each epoch is **60 blocks** on local PocketIC (vs 600 on mainnet) - Blocks advance every ~100ms with auto-progress enabled - Stats for epoch N are only committed once 2/3+ of nodes have submitted records for epoch N+1 -- Minimum wait: **2 epochs × 60 blocks × 100ms ≈ 12 seconds**; `make test-stats` polls up to 30 seconds to accommodate slower machines +- Minimum wait: **2 epochs × 60 blocks × 100ms ≈ 12 seconds**; `bash test-stats.sh` polls up to 30 seconds to accommodate slower machines Only **query calls** are tracked — calls made without `--query` go through consensus as update calls and are not counted in `query_stats.num_calls_total`. @@ -40,7 +40,7 @@ cd examples/motoko/query_stats ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` @@ -48,11 +48,11 @@ icp network stop ```bash icp network start -d icp deploy -make test-stats +bash test-stats.sh icp network stop ``` -`make test-stats` calls `load()` 13 times with `--query` every 3 seconds (up to 30 seconds total), verifying non-zero stats once they appear. +`bash test-stats.sh` calls `load()` 13 times with `--query` every 3 seconds (up to 30 seconds total), verifying non-zero stats once they appear. ## Security considerations and best practices diff --git a/motoko/query_stats/test.sh b/motoko/query_stats/test.sh new file mode 100755 index 000000000..db83d3b0e --- /dev/null +++ b/motoko/query_stats/test.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -e + +echo "=== Test 1/2: load() returns a non-zero timestamp ===" +# --query ensures this call is recorded in query_stats (update calls are not tracked) +result=$(icp canister call --query backend load '()') && \ + echo "$result" && \ + echo "$result" | grep -qE '\([0-9][0-9_]* : int\)' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2/2: get_current_query_stats_as_string() returns the four expected fields ===" +result=$(icp canister call backend get_current_query_stats_as_string '()') && \ + echo "$result" && \ + echo "$result" | grep -q 'Number of calls' && \ + echo "$result" | grep -q 'Number of instructions' && \ + echo "$result" | grep -q 'Request payload bytes' && \ + echo "$result" | grep -q 'Response payload bytes' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/random_maze/Makefile b/motoko/random_maze/Makefile deleted file mode 100644 index 3bc04bd90..000000000 --- a/motoko/random_maze/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -.PHONY: test - -test: - @echo "=== Test 1: generate returns a maze string with wall characters ===" - @result=$$(icp canister call backend generate '(8)') && \ - echo "$$result" && \ - echo "$$result" | grep -q '🟥' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2: generate with size 1 returns a minimal maze ===" - @result=$$(icp canister call backend generate '(1)') && \ - echo "$$result" && \ - echo "$$result" | grep -q '🟥' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3: generate with size 16 returns a larger maze ===" - @result=$$(icp canister call backend generate '(16)') && \ - echo "$$result" && \ - echo "$$result" | grep -q '🟥' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/random_maze/README.md b/motoko/random_maze/README.md index 8efbcdd38..50b7f60b2 100644 --- a/motoko/random_maze/README.md +++ b/motoko/random_maze/README.md @@ -22,7 +22,7 @@ cd examples/motoko/random_maze ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` diff --git a/motoko/random_maze/test.sh b/motoko/random_maze/test.sh new file mode 100755 index 000000000..4c698d369 --- /dev/null +++ b/motoko/random_maze/test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -e + +echo "=== Test 1: generate returns a maze string with wall characters ===" +result=$(icp canister call backend generate '(8)') && \ + echo "$result" && \ + echo "$result" | grep -q '🟥' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2: generate with size 1 returns a minimal maze ===" +result=$(icp canister call backend generate '(1)') && \ + echo "$result" && \ + echo "$result" | grep -q '🟥' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3: generate with size 16 returns a larger maze ===" +result=$(icp canister call backend generate '(16)') && \ + echo "$result" && \ + echo "$result" | grep -q '🟥' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/send_http_get/Makefile b/motoko/send_http_get/Makefile deleted file mode 100644 index 48dc24608..000000000 --- a/motoko/send_http_get/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -.PHONY: test - -test: - @echo "=== Test 1/1: send_http_get_request returns JSON with greeting field ===" - @result=$$(icp canister call backend send_http_get_request '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'hello-from-icp' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/send_http_get/README.md b/motoko/send_http_get/README.md index a86509694..b611137a8 100644 --- a/motoko/send_http_get/README.md +++ b/motoko/send_http_get/README.md @@ -23,7 +23,7 @@ cd examples/motoko/send_http_get ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` diff --git a/motoko/send_http_get/test.sh b/motoko/send_http_get/test.sh new file mode 100755 index 000000000..c05079159 --- /dev/null +++ b/motoko/send_http_get/test.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -e + +echo "=== Test 1/1: send_http_get_request returns JSON with greeting field ===" +result=$(icp canister call backend send_http_get_request '()') && \ + echo "$result" && \ + echo "$result" | grep -q 'hello-from-icp' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/send_http_post/Makefile b/motoko/send_http_post/Makefile deleted file mode 100644 index a0e1a2993..000000000 --- a/motoko/send_http_post/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -.PHONY: test - -test: - @echo "=== Test 1/1: send_http_post_request returns POST echo ===" - @result=$$(icp canister call backend send_http_post_request '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'POST request from an ICP canister' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/send_http_post/README.md b/motoko/send_http_post/README.md index 4ad80c799..ce4df048e 100644 --- a/motoko/send_http_post/README.md +++ b/motoko/send_http_post/README.md @@ -21,7 +21,7 @@ cd examples/motoko/send_http_post ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` diff --git a/motoko/send_http_post/test.sh b/motoko/send_http_post/test.sh new file mode 100755 index 000000000..5a8732214 --- /dev/null +++ b/motoko/send_http_post/test.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -e + +echo "=== Test 1/1: send_http_post_request returns POST echo ===" +result=$(icp canister call backend send_http_post_request '()') && \ + echo "$result" && \ + echo "$result" | grep -q 'POST request from an ICP canister' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/superheroes/Makefile b/motoko/superheroes/Makefile deleted file mode 100644 index 4c528ffaf..000000000 --- a/motoko/superheroes/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -.PHONY: test - -# Tests capture the ID from create so they are idempotent across re-runs -# (the backend uses an auto-incrementing counter, so the ID differs each run). -test: - @echo "=== Test 1: create a superhero ===" - @set -e; \ - out=$$(icp canister call backend create '(record { name = "Superman"; superpowers = vec { "invulnerability"; "superhuman strength" } })'); \ - echo "$$out"; \ - id=$$(echo "$$out" | grep -oE '[0-9]+' | head -1); \ - [ -n "$$id" ] || (echo "FAIL: could not parse created ID" && exit 1); \ - echo "Created ID: $$id"; \ - echo "PASS"; \ - \ - echo "=== Test 2: read the created superhero ==="; \ - result=$$(icp canister call --query backend read "($$id : nat32)"); \ - echo "$$result"; \ - echo "$$result" | grep -q 'Superman' && echo "PASS" || (echo "FAIL" && exit 1); \ - \ - echo "=== Test 3: update the superhero ==="; \ - result=$$(icp canister call backend update "($$id : nat32, record { name = \"Superman\"; superpowers = vec { \"invulnerability\"; \"superhuman strength\"; \"flight\"; \"x-ray vision\" } })"); \ - echo "$$result"; \ - echo "$$result" | grep -q 'true' && echo "PASS" || (echo "FAIL" && exit 1); \ - \ - echo "=== Test 4: read updated superhero to verify state change ==="; \ - result=$$(icp canister call --query backend read "($$id : nat32)"); \ - echo "$$result"; \ - echo "$$result" | grep -q 'x-ray vision' && echo "PASS" || (echo "FAIL" && exit 1); \ - \ - echo "=== Test 5: delete the superhero ==="; \ - result=$$(icp canister call backend delete "($$id : nat32)"); \ - echo "$$result"; \ - echo "$$result" | grep -q 'true' && echo "PASS" || (echo "FAIL" && exit 1); \ - \ - echo "=== Test 6: delete non-existent superhero returns false ==="; \ - result=$$(icp canister call backend delete "($$id : nat32)"); \ - echo "$$result"; \ - echo "$$result" | grep -q 'false' && echo "PASS" || (echo "FAIL" && exit 1); \ - \ - echo "=== Test 7: read deleted superhero returns null ==="; \ - result=$$(icp canister call --query backend read "($$id : nat32)"); \ - echo "$$result"; \ - echo "$$result" | grep -q 'null' && echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/superheroes/README.md b/motoko/superheroes/README.md index 4e8ebfaa0..44a5f6673 100644 --- a/motoko/superheroes/README.md +++ b/motoko/superheroes/README.md @@ -24,11 +24,11 @@ cd examples/motoko/superheroes ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` -`make test` creates a superhero, exercises all CRUD operations, and deletes it — using the returned ID for all subsequent calls, so tests are idempotent and can be re-run multiple times without redeploying. +`bash test.sh` creates a superhero, exercises all CRUD operations, and deletes it — using the returned ID for all subsequent calls, so tests are idempotent and can be re-run multiple times without redeploying. The frontend is served by the asset canister. To run the Vite dev server with hot reload during frontend development: diff --git a/motoko/superheroes/test.sh b/motoko/superheroes/test.sh new file mode 100755 index 000000000..8645cc380 --- /dev/null +++ b/motoko/superheroes/test.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -e + +# Tests capture the ID from create so they are idempotent across re-runs +# (the backend uses an auto-incrementing counter, so the ID differs each run). + +echo "=== Test 1: create a superhero ===" +out=$(icp canister call backend create '(record { name = "Superman"; superpowers = vec { "invulnerability"; "superhuman strength" } })') +echo "$out" +id=$(echo "$out" | grep -oE '[0-9]+' | head -1) +[ -n "$id" ] || (echo "FAIL: could not parse created ID" && exit 1) +echo "Created ID: $id" +echo "PASS" + +echo "=== Test 2: read the created superhero ===" +result=$(icp canister call --query backend read "($id : nat32)") +echo "$result" +echo "$result" | grep -q 'Superman' && echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3: update the superhero ===" +result=$(icp canister call backend update "($id : nat32, record { name = \"Superman\"; superpowers = vec { \"invulnerability\"; \"superhuman strength\"; \"flight\"; \"x-ray vision\" } })") +echo "$result" +echo "$result" | grep -q 'true' && echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 4: read updated superhero to verify state change ===" +result=$(icp canister call --query backend read "($id : nat32)") +echo "$result" +echo "$result" | grep -q 'x-ray vision' && echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 5: delete the superhero ===" +result=$(icp canister call backend delete "($id : nat32)") +echo "$result" +echo "$result" | grep -q 'true' && echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 6: delete non-existent superhero returns false ===" +result=$(icp canister call backend delete "($id : nat32)") +echo "$result" +echo "$result" | grep -q 'false' && echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 7: read deleted superhero returns null ===" +result=$(icp canister call --query backend read "($id : nat32)") +echo "$result" +echo "$result" | grep -q 'null' && echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/threshold-ecdsa/Makefile b/motoko/threshold-ecdsa/Makefile deleted file mode 100644 index facf69e83..000000000 --- a/motoko/threshold-ecdsa/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -.PHONY: test - -test: - @echo "=== Test 1/3: public_key() returns a hex-encoded public key ===" - @result=$$(icp canister call backend public_key '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'public_key_hex' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2/3: sign() returns a hex-encoded signature ===" - @result=$$(icp canister call backend sign '("hello world")') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'signature_hex' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3/3: signature verifies cryptographically (secp256k1) ===" - @npm install --silent - @chmod +x test.sh && ./test.sh "hello world" && echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/threshold-ecdsa/README.md b/motoko/threshold-ecdsa/README.md index 86206272c..d820bc207 100644 --- a/motoko/threshold-ecdsa/README.md +++ b/motoko/threshold-ecdsa/README.md @@ -19,7 +19,7 @@ cd examples/motoko/threshold-ecdsa ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` diff --git a/motoko/threshold-ecdsa/test.sh b/motoko/threshold-ecdsa/test.sh index e8410136e..656b70fcd 100755 --- a/motoko/threshold-ecdsa/test.sh +++ b/motoko/threshold-ecdsa/test.sh @@ -1,14 +1,28 @@ #!/usr/bin/env bash -set -euo pipefail +set -e + +echo "=== Test 1/3: public_key() returns a hex-encoded public key ===" +result=$(icp canister call backend public_key '()') && \ + echo "$result" && \ + echo "$result" | grep -q 'public_key_hex' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2/3: sign() returns a hex-encoded signature ===" +result=$(icp canister call backend sign '("hello world")') && \ + echo "$result" && \ + echo "$result" | grep -q 'signature_hex' && \ + echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3/3: signature verifies cryptographically (secp256k1) ===" +npm install --silent + export LC_ALL=C function get_text_in_double_quotes() { printf "$(echo "$1" | sed -e 's/^[^"]*"//' -e 's/".*//g')" } -test -z "${1:-}" && echo "USAGE: $0 " && exit 1 - -message="$1" +message="hello world" echo "message=$message" signature_hex=$(get_text_in_double_quotes "$(icp canister call backend sign "(\"$message\")" | grep signature_hex)") @@ -29,3 +43,4 @@ const verified = secp256k1.ecdsaVerify(signature, message_hash, public_key); console.log("verified =", verified); if (!verified) process.exit(1); END +echo "PASS" diff --git a/motoko/threshold-schnorr/Makefile b/motoko/threshold-schnorr/Makefile deleted file mode 100644 index 27b4bd7e9..000000000 --- a/motoko/threshold-schnorr/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -.PHONY: test - -test: - @echo "=== Test 1/5: public_key returns hex for bip340secp256k1 ===" - @result=$$(icp canister call backend public_key '(variant { bip340secp256k1 })') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'public_key_hex' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2/5: public_key returns hex for ed25519 ===" - @result=$$(icp canister call backend public_key '(variant { ed25519 })') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'public_key_hex' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3/5: sign returns signature_hex for bip340secp256k1 ===" - @result=$$(icp canister call backend sign '("hello world of BIP340-secp256k1!", variant { bip340secp256k1 }, null)') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'signature_hex' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 4/5: sign returns signature_hex for ed25519 ===" - @result=$$(icp canister call backend sign '("hello world", variant { ed25519 }, null)') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'signature_hex' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 5/5: all three signature types verify cryptographically ===" - @npm install --silent - @chmod +x test.sh && ./test.sh "hello world of BIP340-secp256k1!" && echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/threshold-schnorr/README.md b/motoko/threshold-schnorr/README.md index f44656af4..36c9db73d 100644 --- a/motoko/threshold-schnorr/README.md +++ b/motoko/threshold-schnorr/README.md @@ -19,7 +19,7 @@ cd examples/motoko/threshold-schnorr ```bash icp network start -d icp deploy -make test +bash test.sh icp network stop ``` diff --git a/motoko/threshold-schnorr/test.sh b/motoko/threshold-schnorr/test.sh index 86afaf6d7..54ccca0c6 100755 --- a/motoko/threshold-schnorr/test.sh +++ b/motoko/threshold-schnorr/test.sh @@ -1,79 +1,30 @@ #!/usr/bin/env bash -set -euo pipefail -export LC_ALL=C - -function get_text_in_double_quotes() { - echo -n "$1" | sed -e 's/^[^"]*"//' -e 's/"//g' -e 's/;//g' -} - -test -z "${1:-}" && echo "USAGE: $0 " && exit 1 - -# BIP340 requires the message to be exactly 32 bytes; ed25519 accepts any length. -# Pass a 32-byte ASCII string so the same value works for all three algorithms. -message="${1}" - -echo "message=$message (${#message} bytes)" - -# --- ed25519 --- -echo "--- ed25519 ---" -ed25519_sign_cmd="icp canister call backend sign '(\"${message}\" ,(variant { ed25519 }), null)'" -ed25519_sig_hex=$(get_text_in_double_quotes "$(eval "${ed25519_sign_cmd}" | grep signature_hex)") -echo "ed25519_signature_hex=$ed25519_sig_hex" -ed25519_pubkey_hex=$(get_text_in_double_quotes "$(icp canister call backend public_key '(variant { ed25519 })' | grep public_key_hex)") -echo "ed25519_public_key_hex=$ed25519_pubkey_hex" - -node < new Uint8Array(crypto.createHash('sha512').update(ed.etc.concatBytes(...m)).digest()); -const sig = Buffer.from("${ed25519_sig_hex}", "hex"); -const pubkey = Buffer.from("${ed25519_pubkey_hex}", "hex"); -const msg = Buffer.from("${message}", "utf8"); -const ok = ed.verify(sig, msg, pubkey); -console.log("ed25519 verified:", ok); -if (!ok) { console.error("ed25519 verification FAILED"); process.exit(1); } -END - -# --- bip340secp256k1 --- -echo "--- bip340secp256k1 ---" -bip340_sign_cmd="icp canister call backend sign '(\"${message}\" ,(variant { bip340secp256k1 }), null)'" -bip340_sig_hex=$(get_text_in_double_quotes "$(eval "${bip340_sign_cmd}" | grep signature_hex)") -echo "bip340_signature_hex=$bip340_sig_hex" -bip340_pubkey_hex=$(get_text_in_double_quotes "$(icp canister call backend public_key '(variant { bip340secp256k1 })' | grep public_key_hex)") -echo "bip340_public_key_hex=$bip340_pubkey_hex" - -node <" && exit 1 + +# BIP340 requires the message to be exactly 32 bytes; ed25519 accepts any length. +# Pass a 32-byte ASCII string so the same value works for all three algorithms. +message="${1}" + +echo "message=$message (${#message} bytes)" + +# --- ed25519 --- +echo "--- ed25519 ---" +ed25519_sign_cmd="icp canister call backend sign '(\"${message}\" ,(variant { ed25519 }), null)'" +ed25519_sig_hex=$(get_text_in_double_quotes "$(eval "${ed25519_sign_cmd}" | grep signature_hex)") +echo "ed25519_signature_hex=$ed25519_sig_hex" +ed25519_pubkey_hex=$(get_text_in_double_quotes "$(icp canister call backend public_key '(variant { ed25519 })' | grep public_key_hex)") +echo "ed25519_public_key_hex=$ed25519_pubkey_hex" + +node < new Uint8Array(crypto.createHash('sha512').update(ed.etc.concatBytes(...m)).digest()); +const sig = Buffer.from("${ed25519_sig_hex}", "hex"); +const pubkey = Buffer.from("${ed25519_pubkey_hex}", "hex"); +const msg = Buffer.from("${message}", "utf8"); +const ok = ed.verify(sig, msg, pubkey); +console.log("ed25519 verified:", ok); +if (!ok) { console.error("ed25519 verification FAILED"); process.exit(1); } +END + +# --- bip340secp256k1 --- +echo "--- bip340secp256k1 ---" +bip340_sign_cmd="icp canister call backend sign '(\"${message}\" ,(variant { bip340secp256k1 }), null)'" +bip340_sig_hex=$(get_text_in_double_quotes "$(eval "${bip340_sign_cmd}" | grep signature_hex)") +echo "bip340_signature_hex=$bip340_sig_hex" +bip340_pubkey_hex=$(get_text_in_double_quotes "$(icp canister call backend public_key '(variant { bip340secp256k1 })' | grep public_key_hex)") +echo "bip340_public_key_hex=$bip340_pubkey_hex" + +node < Date: Wed, 17 Jun 2026 19:09:42 +0200 Subject: [PATCH 2/9] fix(chore/update-merged): icrc2-swap deploy.sh + basic_bitcoin test.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - icrc2-swap: create deploy.sh (deploy target lost when Makefile was removed); update workflow from make deploy → bash deploy.sh - basic_bitcoin: convert Makefile → test.sh; update workflow make test → bash test.sh; preserve build-image and Docker container logic Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/basic_bitcoin.yml | 2 +- .github/workflows/icrc2-swap.yml | 2 +- motoko/basic_bitcoin/Makefile | 62 ----------------------------- motoko/basic_bitcoin/test.sh | 48 ++++++++++++++++++++++ motoko/icrc2-swap/deploy.sh | 35 ++++++++++++++++ 5 files changed, 85 insertions(+), 64 deletions(-) delete mode 100644 motoko/basic_bitcoin/Makefile create mode 100755 motoko/basic_bitcoin/test.sh create mode 100755 motoko/icrc2-swap/deploy.sh diff --git a/.github/workflows/basic_bitcoin.yml b/.github/workflows/basic_bitcoin.yml index 4733e1fa0..227a86f07 100644 --- a/.github/workflows/basic_bitcoin.yml +++ b/.github/workflows/basic_bitcoin.yml @@ -40,4 +40,4 @@ jobs: run: | icp network start -d icp deploy --cycles 30t - make test + bash test.sh diff --git a/.github/workflows/icrc2-swap.yml b/.github/workflows/icrc2-swap.yml index c4987d00d..186bfae10 100644 --- a/.github/workflows/icrc2-swap.yml +++ b/.github/workflows/icrc2-swap.yml @@ -24,5 +24,5 @@ jobs: working-directory: motoko/icrc2-swap run: | icp network start -d - make deploy + bash deploy.sh bash test.sh diff --git a/motoko/basic_bitcoin/Makefile b/motoko/basic_bitcoin/Makefile deleted file mode 100644 index a1509970d..000000000 --- a/motoko/basic_bitcoin/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -IMAGE_NAME = icp-cli-network-launcher-bitcoin -# Find the running container built from our custom image -BITCOIN_CONTAINER = $(shell docker ps --filter "ancestor=$(IMAGE_NAME)" --format "{{.ID}}" | head -1) - -.PHONY: build-image test topup - -build-image: - # Because we're building off of :latest, use --pull to fetch the latest image. - # Remove `--pull` if the Dockerfile is updated to pin the base image version. - docker build --pull -t $(IMAGE_NAME) . - -topup: - icp canister top-up --amount 30t backend - -test: - @echo "=== Test 1: get_p2pkh_address returns a valid Bitcoin address ===" - @result=$$(icp canister call backend get_p2pkh_address '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q '"' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 2: get_p2tr_key_only_address returns a valid Bitcoin address ===" - @result=$$(icp canister call backend get_p2tr_key_only_address '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q '"' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 3: get_p2tr_address returns a valid Bitcoin address ===" - @result=$$(icp canister call backend get_p2tr_address '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q '"' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 4: get_current_fee_percentiles returns a vec ===" - @result=$$(icp canister call backend get_current_fee_percentiles '()') && \ - echo "$$result" && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Mining 101 blocks to fund test address ===" - @[ -n "$(BITCOIN_CONTAINER)" ] || (echo "ERROR: network launcher container not running — run 'icp network start -d' first" && exit 1) - @addr=$$(icp canister call backend get_p2pkh_address '()' | grep -o '"[^"]*"' | tr -d '"') && \ - docker exec $(BITCOIN_CONTAINER) bitcoin-cli -regtest \ - -rpcuser=ic-btc-integration -rpcpassword=ic-btc-integration \ - generatetoaddress 101 "$$addr" > /dev/null && \ - echo "mined 101 blocks to $$addr" - - @echo "=== Waiting for IC to sync Bitcoin blocks ===" - @sleep 5 - - @echo "=== Test 5: get_balance returns non-zero after mining ===" - @addr=$$(icp canister call backend get_p2pkh_address '()' | grep -o '"[^"]*"' | tr -d '"') && \ - result=$$(icp canister call backend get_balance "(\"$$addr\")") && \ - echo "$$result" && \ - echo "$$result" | grep -qE '[1-9]' && \ - echo "PASS" || (echo "FAIL" && exit 1) - - @echo "=== Test 6: get_utxos returns synced chain state after mining ===" - @addr=$$(icp canister call backend get_p2pkh_address '()' | grep -o '"[^"]*"' | tr -d '"') && \ - result=$$(icp canister call backend get_utxos "(\"$$addr\")") && \ - echo "$$result" && \ - echo "$$result" | grep -q 'tip_height = 101' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/basic_bitcoin/test.sh b/motoko/basic_bitcoin/test.sh new file mode 100755 index 000000000..66b02c797 --- /dev/null +++ b/motoko/basic_bitcoin/test.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -e + +IMAGE_NAME="icp-cli-network-launcher-bitcoin" +BITCOIN_CONTAINER=$(docker ps --filter "ancestor=$IMAGE_NAME" --format "{{.ID}}" | head -1) + +echo "=== Test 1: get_p2pkh_address returns a valid Bitcoin address ===" +result=$(icp canister call backend get_p2pkh_address '()') +echo "$result" +echo "$result" | grep -q '"' && echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 2: get_p2tr_key_only_address returns a valid Bitcoin address ===" +result=$(icp canister call backend get_p2tr_key_only_address '()') +echo "$result" +echo "$result" | grep -q '"' && echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 3: get_p2tr_address returns a valid Bitcoin address ===" +result=$(icp canister call backend get_p2tr_address '()') +echo "$result" +echo "$result" | grep -q '"' && echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 4: get_current_fee_percentiles returns a vec ===" +result=$(icp canister call backend get_current_fee_percentiles '()') +echo "$result" +echo "PASS" + +echo "=== Mining 101 blocks to fund test address ===" +[ -n "$BITCOIN_CONTAINER" ] || (echo "ERROR: network launcher container not running — run 'icp network start -d' first" && exit 1) +addr=$(icp canister call backend get_p2pkh_address '()' | grep -o '"[^"]*"' | tr -d '"') +docker exec "$BITCOIN_CONTAINER" bitcoin-cli -regtest \ + -rpcuser=ic-btc-integration -rpcpassword=ic-btc-integration \ + generatetoaddress 101 "$addr" > /dev/null +echo "mined 101 blocks to $addr" + +echo "=== Waiting for IC to sync Bitcoin blocks ===" +sleep 5 + +echo "=== Test 5: get_balance returns non-zero after mining ===" +addr=$(icp canister call backend get_p2pkh_address '()' | grep -o '"[^"]*"' | tr -d '"') +result=$(icp canister call backend get_balance "(\"$addr\")") +echo "$result" +echo "$result" | grep -qE '[1-9]' && echo "PASS" || (echo "FAIL" && exit 1) + +echo "=== Test 6: get_utxos returns synced chain state after mining ===" +addr=$(icp canister call backend get_p2pkh_address '()' | grep -o '"[^"]*"' | tr -d '"') +result=$(icp canister call backend get_utxos "(\"$addr\")") +echo "$result" +echo "$result" | grep -q 'tip_height = 101' && echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/icrc2-swap/deploy.sh b/motoko/icrc2-swap/deploy.sh new file mode 100755 index 000000000..35098999e --- /dev/null +++ b/motoko/icrc2-swap/deploy.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -e + +# Deploy all canisters in the correct order: +# 1. Create example-specific test identities (icrc2-alice, icrc2-bob) if not present. +# 2. Deploy token_a (pre-funded for alice) and token_b (pre-funded for bob). +# 3. Deploy backend — discovers token principals automatically via env vars. +# +# Note: use `bash deploy.sh` (not `icp deploy`) — the ledger canisters require +# init args with alice/bob principals that are only available after the +# identities are created. + +MINTER=$(icp identity principal) +icp identity new icrc2-alice --storage plaintext 2>/dev/null || true +icp identity new icrc2-bob --storage plaintext 2>/dev/null || true +ALICE=$(icp identity principal --identity icrc2-alice) +BOB=$(icp identity principal --identity icrc2-bob) + +icp deploy token_a --mode reinstall -y --args "(variant { Init = record { \ + token_name = \"Token A\"; token_symbol = \"A\"; \ + minting_account = record { owner = principal \"$MINTER\" }; \ + initial_balances = vec { record { record { owner = principal \"$ALICE\" }; 100_000_000_000_000 : nat } }; \ + metadata = vec {}; transfer_fee = 10_000 : nat; \ + archive_options = record { trigger_threshold = 2000 : nat64; num_blocks_to_archive = 1000 : nat64; controller_id = principal \"$MINTER\" }; \ + feature_flags = opt record { icrc2 = true } } })" + +icp deploy token_b --mode reinstall -y --args "(variant { Init = record { \ + token_name = \"Token B\"; token_symbol = \"B\"; \ + minting_account = record { owner = principal \"$MINTER\" }; \ + initial_balances = vec { record { record { owner = principal \"$BOB\" }; 100_000_000_000_000 : nat } }; \ + metadata = vec {}; transfer_fee = 10_000 : nat; \ + archive_options = record { trigger_threshold = 2000 : nat64; num_blocks_to_archive = 1000 : nat64; controller_id = principal \"$MINTER\" }; \ + feature_flags = opt record { icrc2 = true } } })" + +icp deploy backend --mode reinstall -y From 5656ad83edddba76736dbc74d44e7de2885ec0a7 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 17 Jun 2026 19:11:54 +0200 Subject: [PATCH 3/9] fix(parallel_calls): create test-multi-subnet.sh; update workflow --- .github/workflows/parallel_calls.yml | 2 +- motoko/parallel_calls/test-multi-subnet.sh | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100755 motoko/parallel_calls/test-multi-subnet.sh diff --git a/.github/workflows/parallel_calls.yml b/.github/workflows/parallel_calls.yml index e2fbd5dc9..0704be9ad 100644 --- a/.github/workflows/parallel_calls.yml +++ b/.github/workflows/parallel_calls.yml @@ -36,4 +36,4 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Run multi-subnet PocketIC test working-directory: motoko/parallel_calls - run: make test-multi-subnet + run: bash test-multi-subnet.sh diff --git a/motoko/parallel_calls/test-multi-subnet.sh b/motoko/parallel_calls/test-multi-subnet.sh new file mode 100755 index 000000000..d56c782b2 --- /dev/null +++ b/motoko/parallel_calls/test-multi-subnet.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e + +echo "=== Building Motoko WASMs ===" +icp build + +echo "=== Running multi-subnet PocketIC test ===" +CALLER_WASM=.mops/.build/caller.wasm \ +CALLEE_WASM=.mops/.build/callee.wasm \ + cargo run --manifest-path multi_subnet/Cargo.toml From 86252d9192468dd9bf6aed71e8bf7a6de54dc39d Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 17 Jun 2026 19:24:01 +0200 Subject: [PATCH 4/9] fix(basic_bitcoin): add shrink+compress to recipe to reduce Wasm locals below 2000 The compiled WASM has a function with 2081 locals which exceeds the IC limit of 2000. shrink=true and compress=true enable wasm-opt passes that reduce the local count. Co-Authored-By: Claude Sonnet 4.6 --- motoko/basic_bitcoin/icp.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/motoko/basic_bitcoin/icp.yaml b/motoko/basic_bitcoin/icp.yaml index cf1e2e6fd..d957cc933 100644 --- a/motoko/basic_bitcoin/icp.yaml +++ b/motoko/basic_bitcoin/icp.yaml @@ -2,6 +2,9 @@ canisters: - name: backend recipe: type: "@dfinity/motoko@v5.0.0" + configuration: + shrink: true + compress: true networks: - name: local From 3de6cfd0a4232d936877b995e33fdb18cafa74c6 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 17 Jun 2026 19:29:48 +0200 Subject: [PATCH 5/9] fix(basic_bitcoin): pin npm packages to 1.0.0; keep shrink+compress npm install -g without pinning picked up icp-cli 1.0.0 on 2026-06-17, which appears to produce a Motoko WASM with 2081 locals in one function (IC limit is 2000). Pinning to 1.0.0 ensures consistent behavior matching the dev-env container images. shrink+compress left in icp.yaml as an additional wasm-opt pass that may help reduce the local count once the root cause is understood. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/basic_bitcoin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/basic_bitcoin.yml b/.github/workflows/basic_bitcoin.yml index 227a86f07..d358226c1 100644 --- a/.github/workflows/basic_bitcoin.yml +++ b/.github/workflows/basic_bitcoin.yml @@ -23,7 +23,7 @@ jobs: steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Install icp-cli, ic-wasm and mops - run: npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm ic-mops + run: npm install -g @icp-sdk/icp-cli@1.0.0 @icp-sdk/ic-wasm@0.9.11 ic-mops@2.14.1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - name: Build network launcher image From 19e767894a7e14f2b79ac28d753e850f8c750009 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 17 Jun 2026 19:30:13 +0200 Subject: [PATCH 6/9] =?UTF-8?q?revert(basic=5Fbitcoin):=20drop=20changes?= =?UTF-8?q?=20=E2=80=94=20pre-existing=20icp-cli=201.0.0=20regression,=20t?= =?UTF-8?q?racked=20separately?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/basic_bitcoin.yml | 4 +- motoko/basic_bitcoin/Makefile | 62 +++++++++++++++++++++++++++++ motoko/basic_bitcoin/icp.yaml | 3 -- 3 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 motoko/basic_bitcoin/Makefile diff --git a/.github/workflows/basic_bitcoin.yml b/.github/workflows/basic_bitcoin.yml index d358226c1..4733e1fa0 100644 --- a/.github/workflows/basic_bitcoin.yml +++ b/.github/workflows/basic_bitcoin.yml @@ -23,7 +23,7 @@ jobs: steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - name: Install icp-cli, ic-wasm and mops - run: npm install -g @icp-sdk/icp-cli@1.0.0 @icp-sdk/ic-wasm@0.9.11 ic-mops@2.14.1 + run: npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm ic-mops - name: Set up Docker Buildx uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - name: Build network launcher image @@ -40,4 +40,4 @@ jobs: run: | icp network start -d icp deploy --cycles 30t - bash test.sh + make test diff --git a/motoko/basic_bitcoin/Makefile b/motoko/basic_bitcoin/Makefile new file mode 100644 index 000000000..a1509970d --- /dev/null +++ b/motoko/basic_bitcoin/Makefile @@ -0,0 +1,62 @@ +IMAGE_NAME = icp-cli-network-launcher-bitcoin +# Find the running container built from our custom image +BITCOIN_CONTAINER = $(shell docker ps --filter "ancestor=$(IMAGE_NAME)" --format "{{.ID}}" | head -1) + +.PHONY: build-image test topup + +build-image: + # Because we're building off of :latest, use --pull to fetch the latest image. + # Remove `--pull` if the Dockerfile is updated to pin the base image version. + docker build --pull -t $(IMAGE_NAME) . + +topup: + icp canister top-up --amount 30t backend + +test: + @echo "=== Test 1: get_p2pkh_address returns a valid Bitcoin address ===" + @result=$$(icp canister call backend get_p2pkh_address '()') && \ + echo "$$result" && \ + echo "$$result" | grep -q '"' && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "=== Test 2: get_p2tr_key_only_address returns a valid Bitcoin address ===" + @result=$$(icp canister call backend get_p2tr_key_only_address '()') && \ + echo "$$result" && \ + echo "$$result" | grep -q '"' && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "=== Test 3: get_p2tr_address returns a valid Bitcoin address ===" + @result=$$(icp canister call backend get_p2tr_address '()') && \ + echo "$$result" && \ + echo "$$result" | grep -q '"' && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "=== Test 4: get_current_fee_percentiles returns a vec ===" + @result=$$(icp canister call backend get_current_fee_percentiles '()') && \ + echo "$$result" && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "=== Mining 101 blocks to fund test address ===" + @[ -n "$(BITCOIN_CONTAINER)" ] || (echo "ERROR: network launcher container not running — run 'icp network start -d' first" && exit 1) + @addr=$$(icp canister call backend get_p2pkh_address '()' | grep -o '"[^"]*"' | tr -d '"') && \ + docker exec $(BITCOIN_CONTAINER) bitcoin-cli -regtest \ + -rpcuser=ic-btc-integration -rpcpassword=ic-btc-integration \ + generatetoaddress 101 "$$addr" > /dev/null && \ + echo "mined 101 blocks to $$addr" + + @echo "=== Waiting for IC to sync Bitcoin blocks ===" + @sleep 5 + + @echo "=== Test 5: get_balance returns non-zero after mining ===" + @addr=$$(icp canister call backend get_p2pkh_address '()' | grep -o '"[^"]*"' | tr -d '"') && \ + result=$$(icp canister call backend get_balance "(\"$$addr\")") && \ + echo "$$result" && \ + echo "$$result" | grep -qE '[1-9]' && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "=== Test 6: get_utxos returns synced chain state after mining ===" + @addr=$$(icp canister call backend get_p2pkh_address '()' | grep -o '"[^"]*"' | tr -d '"') && \ + result=$$(icp canister call backend get_utxos "(\"$$addr\")") && \ + echo "$$result" && \ + echo "$$result" | grep -q 'tip_height = 101' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/basic_bitcoin/icp.yaml b/motoko/basic_bitcoin/icp.yaml index d957cc933..cf1e2e6fd 100644 --- a/motoko/basic_bitcoin/icp.yaml +++ b/motoko/basic_bitcoin/icp.yaml @@ -2,9 +2,6 @@ canisters: - name: backend recipe: type: "@dfinity/motoko@v5.0.0" - configuration: - shrink: true - compress: true networks: - name: local From ae0f4c42a79aee6b2f1a21d29c093c1a352a1127 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 17 Jun 2026 19:33:00 +0200 Subject: [PATCH 7/9] fix: remove leftover test.sh from motoko/basic_bitcoin Co-Authored-By: Claude Sonnet 4.6 --- motoko/basic_bitcoin/test.sh | 48 ------------------------------------ 1 file changed, 48 deletions(-) delete mode 100755 motoko/basic_bitcoin/test.sh diff --git a/motoko/basic_bitcoin/test.sh b/motoko/basic_bitcoin/test.sh deleted file mode 100755 index 66b02c797..000000000 --- a/motoko/basic_bitcoin/test.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env bash -set -e - -IMAGE_NAME="icp-cli-network-launcher-bitcoin" -BITCOIN_CONTAINER=$(docker ps --filter "ancestor=$IMAGE_NAME" --format "{{.ID}}" | head -1) - -echo "=== Test 1: get_p2pkh_address returns a valid Bitcoin address ===" -result=$(icp canister call backend get_p2pkh_address '()') -echo "$result" -echo "$result" | grep -q '"' && echo "PASS" || (echo "FAIL" && exit 1) - -echo "=== Test 2: get_p2tr_key_only_address returns a valid Bitcoin address ===" -result=$(icp canister call backend get_p2tr_key_only_address '()') -echo "$result" -echo "$result" | grep -q '"' && echo "PASS" || (echo "FAIL" && exit 1) - -echo "=== Test 3: get_p2tr_address returns a valid Bitcoin address ===" -result=$(icp canister call backend get_p2tr_address '()') -echo "$result" -echo "$result" | grep -q '"' && echo "PASS" || (echo "FAIL" && exit 1) - -echo "=== Test 4: get_current_fee_percentiles returns a vec ===" -result=$(icp canister call backend get_current_fee_percentiles '()') -echo "$result" -echo "PASS" - -echo "=== Mining 101 blocks to fund test address ===" -[ -n "$BITCOIN_CONTAINER" ] || (echo "ERROR: network launcher container not running — run 'icp network start -d' first" && exit 1) -addr=$(icp canister call backend get_p2pkh_address '()' | grep -o '"[^"]*"' | tr -d '"') -docker exec "$BITCOIN_CONTAINER" bitcoin-cli -regtest \ - -rpcuser=ic-btc-integration -rpcpassword=ic-btc-integration \ - generatetoaddress 101 "$addr" > /dev/null -echo "mined 101 blocks to $addr" - -echo "=== Waiting for IC to sync Bitcoin blocks ===" -sleep 5 - -echo "=== Test 5: get_balance returns non-zero after mining ===" -addr=$(icp canister call backend get_p2pkh_address '()' | grep -o '"[^"]*"' | tr -d '"') -result=$(icp canister call backend get_balance "(\"$addr\")") -echo "$result" -echo "$result" | grep -qE '[1-9]' && echo "PASS" || (echo "FAIL" && exit 1) - -echo "=== Test 6: get_utxos returns synced chain state after mining ===" -addr=$(icp canister call backend get_p2pkh_address '()' | grep -o '"[^"]*"' | tr -d '"') -result=$(icp canister call backend get_utxos "(\"$addr\")") -echo "$result" -echo "$result" | grep -q 'tip_height = 101' && echo "PASS" || (echo "FAIL" && exit 1) From 5dba7b4511e81a3b5dc866a384e2925ab5db1c43 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 17 Jun 2026 20:40:35 +0200 Subject: [PATCH 8/9] fix(pr1423): address Copilot review findings - Add --query to all query function calls in who_am_i, hello_world, backend_only, flying_ninja (both Motoko and Rust) - Fix printf '%s' in threshold-ecdsa/test.sh (avoids treating canister output as a printf format string) - Add motoko/query_stats/test-stats.sh (missing file referenced in README) Co-Authored-By: Claude Sonnet 4.6 --- motoko/backend_only/test.sh | 2 +- motoko/flying_ninja/test.sh | 4 ++-- motoko/hello_world/test.sh | 4 ++-- motoko/query_stats/test-stats.sh | 18 ++++++++++++++++++ motoko/threshold-ecdsa/test.sh | 2 +- motoko/who_am_i/test.sh | 6 +++--- rust/backend_only/test.sh | 2 +- rust/flying_ninja/test.sh | 4 ++-- rust/hello_world/test.sh | 4 ++-- rust/threshold-ecdsa/test.sh | 2 +- rust/who_am_i/test.sh | 6 +++--- 11 files changed, 36 insertions(+), 18 deletions(-) create mode 100755 motoko/query_stats/test-stats.sh diff --git a/motoko/backend_only/test.sh b/motoko/backend_only/test.sh index c0b398436..ef4fcc355 100755 --- a/motoko/backend_only/test.sh +++ b/motoko/backend_only/test.sh @@ -2,7 +2,7 @@ set -e echo "=== Test 1: greet returns greeting ===" -result=$(icp canister call backend greet '("World")') && \ +result=$(icp canister call --query backend greet '("World")') && \ echo "$result" && \ echo "$result" | grep -q '"Hello, World!"' && \ echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/flying_ninja/test.sh b/motoko/flying_ninja/test.sh index 20051785e..ae2517bbc 100755 --- a/motoko/flying_ninja/test.sh +++ b/motoko/flying_ninja/test.sh @@ -2,7 +2,7 @@ set -e echo "=== Test 1: isHighScore returns true when leaderboard has fewer than 10 entries ===" -result=$(icp canister call backend isHighScore '(0)') && \ +result=$(icp canister call --query backend isHighScore '(0)') && \ echo "$result" && \ echo "$result" | grep -q 'true' && \ echo "PASS" || (echo "FAIL" && exit 1) @@ -15,7 +15,7 @@ result=$(icp canister call backend addLeaderboardEntry '("Alice", 100)') && \ echo "PASS" || (echo "FAIL" && exit 1) echo "=== Test 3: getLeaderboard returns persisted entry ===" -result=$(icp canister call backend getLeaderboard '()') && \ +result=$(icp canister call --query backend getLeaderboard '()') && \ echo "$result" && \ echo "$result" | grep -q '"Alice"' && \ echo "$result" | grep -q '100' && \ diff --git a/motoko/hello_world/test.sh b/motoko/hello_world/test.sh index 0131c8887..d0b33b092 100755 --- a/motoko/hello_world/test.sh +++ b/motoko/hello_world/test.sh @@ -2,12 +2,12 @@ set -e echo "--- Testing default greeting ---" -result=$(icp canister call backend greet '("World")') +result=$(icp canister call --query backend greet '("World")') echo "$result" echo "$result" | grep -q 'Hello, World!' && echo "PASS" || (echo "FAIL" && exit 1) echo "--- Testing setGreeting ---" icp canister call backend setGreeting '("Hi, ")' -result=$(icp canister call backend greet '("Alice")') +result=$(icp canister call --query backend greet '("Alice")') echo "$result" echo "$result" | grep -q 'Hi, Alice!' && echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/query_stats/test-stats.sh b/motoko/query_stats/test-stats.sh new file mode 100755 index 000000000..edb195567 --- /dev/null +++ b/motoko/query_stats/test-stats.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -e + +echo "=== Polling query stats (making 13 --query calls every 3s, up to 30s) ===" +secs=0 +while [ "$secs" -lt 30 ]; do + for i in $(seq 1 13); do + icp canister call --query backend load '()' > /dev/null + done + result=$(icp canister call backend get_current_query_stats_as_string '()') + echo "$result" | grep -qE 'Number of calls: [1-9]' && \ + echo "$result" && echo "PASS: query stats are non-zero (after ~${secs}s)" && exit 0 + sleep 3 + secs=$((secs + 3)) +done +result=$(icp canister call backend get_current_query_stats_as_string '()') +echo "$result" +echo "FAIL: stats still 0 after 30s"; exit 1 diff --git a/motoko/threshold-ecdsa/test.sh b/motoko/threshold-ecdsa/test.sh index 656b70fcd..0045bb429 100755 --- a/motoko/threshold-ecdsa/test.sh +++ b/motoko/threshold-ecdsa/test.sh @@ -19,7 +19,7 @@ npm install --silent export LC_ALL=C function get_text_in_double_quotes() { - printf "$(echo "$1" | sed -e 's/^[^"]*"//' -e 's/".*//g')" + printf '%s' "$(echo "$1" | sed -e 's/^[^"]*"//' -e 's/".*//g')" } message="hello world" diff --git a/motoko/who_am_i/test.sh b/motoko/who_am_i/test.sh index cf52e1516..cdc2b491b 100755 --- a/motoko/who_am_i/test.sh +++ b/motoko/who_am_i/test.sh @@ -2,13 +2,13 @@ set -e echo "--- Testing whoami returns a principal ---" -result=$(icp canister call backend whoami '()') && \ +result=$(icp canister call --query backend whoami '()') && \ echo "$result" && \ echo "$result" | grep -q 'principal' && \ echo "PASS" || (echo "FAIL" && exit 1) echo "--- Testing whoami is deterministic ---" -result1=$(icp canister call backend whoami '()') && \ - result2=$(icp canister call backend whoami '()') && \ +result1=$(icp canister call --query backend whoami '()') && \ + result2=$(icp canister call --query backend whoami '()') && \ [ "$result1" = "$result2" ] && \ echo "PASS: $result1" || (echo "FAIL: $result1 != $result2" && exit 1) diff --git a/rust/backend_only/test.sh b/rust/backend_only/test.sh index ea2e483ef..243d46cf9 100755 --- a/rust/backend_only/test.sh +++ b/rust/backend_only/test.sh @@ -2,7 +2,7 @@ set -e echo "=== Test 1/1: greet() returns a greeting ===" -result=$(icp canister call backend greet '("World")') && \ +result=$(icp canister call --query backend greet '("World")') && \ echo "$result" && \ echo "$result" | grep -q 'Hello, World!' && \ echo "PASS" || (echo "FAIL" && exit 1) diff --git a/rust/flying_ninja/test.sh b/rust/flying_ninja/test.sh index 3e85fb441..441a86e91 100755 --- a/rust/flying_ninja/test.sh +++ b/rust/flying_ninja/test.sh @@ -2,7 +2,7 @@ set -e echo "=== Test 1/4: is_high_score returns true when leaderboard has fewer than 10 entries ===" -result=$(icp canister call backend is_high_score '(0 : nat)') && \ +result=$(icp canister call --query backend is_high_score '(0 : nat)') && \ echo "$result" && \ echo "$result" | grep -q 'true' && \ echo "PASS" || (echo "FAIL" && exit 1) @@ -14,7 +14,7 @@ result=$(icp canister call backend add_leaderboard_entry '("Alice", 100 : nat)') echo "PASS" || (echo "FAIL" && exit 1) echo "=== Test 3/4: get_leaderboard returns stored entries ===" -result=$(icp canister call backend get_leaderboard '()') && \ +result=$(icp canister call --query backend get_leaderboard '()') && \ echo "$result" && \ echo "$result" | grep -q 'Alice' && \ echo "PASS" || (echo "FAIL" && exit 1) diff --git a/rust/hello_world/test.sh b/rust/hello_world/test.sh index 2ae61cf9a..83ddace88 100755 --- a/rust/hello_world/test.sh +++ b/rust/hello_world/test.sh @@ -2,12 +2,12 @@ set -e echo "--- Testing default greeting ---" -result=$(icp canister call backend greet '("World")') +result=$(icp canister call --query backend greet '("World")') echo "$result" echo "$result" | grep -q 'Hello, World!' && echo "PASS" || (echo "FAIL" && exit 1) echo "--- Testing set_greeting ---" icp canister call backend set_greeting '("Hi, ")' -result=$(icp canister call backend greet '("Alice")') +result=$(icp canister call --query backend greet '("Alice")') echo "$result" echo "$result" | grep -q 'Hi, Alice!' && echo "PASS" || (echo "FAIL" && exit 1) diff --git a/rust/threshold-ecdsa/test.sh b/rust/threshold-ecdsa/test.sh index 9b29480a4..8bc8fe3df 100755 --- a/rust/threshold-ecdsa/test.sh +++ b/rust/threshold-ecdsa/test.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash export LC_ALL=C function get_text_in_double_quotes() { - printf "$(echo "$1" | sed -e 's/^[^"]*"//' -e 's/".*//g')" + printf '%s' "$(echo "$1" | sed -e 's/^[^"]*"//' -e 's/".*//g')" } test -z "$1" && echo "USAGE: $0 " && exit 1 diff --git a/rust/who_am_i/test.sh b/rust/who_am_i/test.sh index cf52e1516..cdc2b491b 100755 --- a/rust/who_am_i/test.sh +++ b/rust/who_am_i/test.sh @@ -2,13 +2,13 @@ set -e echo "--- Testing whoami returns a principal ---" -result=$(icp canister call backend whoami '()') && \ +result=$(icp canister call --query backend whoami '()') && \ echo "$result" && \ echo "$result" | grep -q 'principal' && \ echo "PASS" || (echo "FAIL" && exit 1) echo "--- Testing whoami is deterministic ---" -result1=$(icp canister call backend whoami '()') && \ - result2=$(icp canister call backend whoami '()') && \ +result1=$(icp canister call --query backend whoami '()') && \ + result2=$(icp canister call --query backend whoami '()') && \ [ "$result1" = "$result2" ] && \ echo "PASS: $result1" || (echo "FAIL: $result1 != $result2" && exit 1) From 3d8390635a7bcfbd55ecdbc297781bc77bd7dc34 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 17 Jun 2026 20:58:59 +0200 Subject: [PATCH 9/9] =?UTF-8?q?fix(threshold-schnorr):=20remove=20eval=20f?= =?UTF-8?q?rom=20verify.sh=20=E2=80=94=20inline=20icp=20canister=20call=20?= =?UTF-8?q?directly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- motoko/threshold-schnorr/verify.sh | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/motoko/threshold-schnorr/verify.sh b/motoko/threshold-schnorr/verify.sh index 86afaf6d7..1efeb92df 100755 --- a/motoko/threshold-schnorr/verify.sh +++ b/motoko/threshold-schnorr/verify.sh @@ -16,8 +16,7 @@ echo "message=$message (${#message} bytes)" # --- ed25519 --- echo "--- ed25519 ---" -ed25519_sign_cmd="icp canister call backend sign '(\"${message}\" ,(variant { ed25519 }), null)'" -ed25519_sig_hex=$(get_text_in_double_quotes "$(eval "${ed25519_sign_cmd}" | grep signature_hex)") +ed25519_sig_hex=$(get_text_in_double_quotes "$(icp canister call backend sign "(\"${message}\" ,(variant { ed25519 }), null)" | grep signature_hex)") echo "ed25519_signature_hex=$ed25519_sig_hex" ed25519_pubkey_hex=$(get_text_in_double_quotes "$(icp canister call backend public_key '(variant { ed25519 })' | grep public_key_hex)") echo "ed25519_public_key_hex=$ed25519_pubkey_hex" @@ -37,8 +36,7 @@ END # --- bip340secp256k1 --- echo "--- bip340secp256k1 ---" -bip340_sign_cmd="icp canister call backend sign '(\"${message}\" ,(variant { bip340secp256k1 }), null)'" -bip340_sig_hex=$(get_text_in_double_quotes "$(eval "${bip340_sign_cmd}" | grep signature_hex)") +bip340_sig_hex=$(get_text_in_double_quotes "$(icp canister call backend sign "(\"${message}\" ,(variant { bip340secp256k1 }), null)" | grep signature_hex)") echo "bip340_signature_hex=$bip340_sig_hex" bip340_pubkey_hex=$(get_text_in_double_quotes "$(icp canister call backend public_key '(variant { bip340secp256k1 })' | grep public_key_hex)") echo "bip340_public_key_hex=$bip340_pubkey_hex" @@ -56,8 +54,7 @@ END # --- bip341 (tweaked key) --- echo "--- bip341 ---" tweak_hex="012345678901234567890123456789012345678901234567890123456789abcd" -bip341_sign_cmd="icp canister call backend sign '(\"${message}\" ,(variant { bip340secp256k1 }), opt \"${tweak_hex}\")'" -bip341_sig_hex=$(get_text_in_double_quotes "$(eval "${bip341_sign_cmd}" | grep signature_hex)") +bip341_sig_hex=$(get_text_in_double_quotes "$(icp canister call backend sign "(\"${message}\" ,(variant { bip340secp256k1 }), opt \"${tweak_hex}\")" | grep signature_hex)") echo "bip341_signature_hex=$bip341_sig_hex" node <