diff --git a/.github/workflows/backend_only.yml b/.github/workflows/backend_only.yml index 370d80c7ce..fc7d58a1d2 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 04d847fade..7b90a5b138 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 52eb58c5f3..be7a1febab 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 2eed236c71..51d45efbfa 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 347b510c77..4388649077 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 3c0c06622d..760436a020 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 3ac4e453a8..a922cfdc45 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 0d9a77b567..3c5f217a72 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 b9a3330c3c..e083eb75f7 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 82e824f21c..61c9865670 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 e99ce24bcf..33f4045d00 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 293c1968a5..dba93c174b 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 536003122b..36bf2881cd 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 36792f164f..b0747c7c59 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 0bc50d8e8f..61285c501b 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 706d0514b0..186bfae10b 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: @@ -24,5 +24,5 @@ jobs: working-directory: motoko/icrc2-swap run: | icp network start -d - make deploy - make test + bash deploy.sh + bash test.sh diff --git a/.github/workflows/low_wasm_memory.yml b/.github/workflows/low_wasm_memory.yml index 4afd3eed2a..abe4a32835 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 cd32ac15d7..0704be9ad7 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,15 +25,15 @@ 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: - 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/.github/workflows/pub-sub.yml b/.github/workflows/pub-sub.yml index 286993661f..2d471f1d90 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 7a762983a7..e12ea39c56 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 e05509c75a..ed7e7c854c 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 d6952c07ce..9136c0f929 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 8ec74874de..cd969c543d 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 e063f27b7e..7a48c67ef7 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 637524a845..00db6ad881 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 60f44f5eac..ca5e85f7cd 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 a3e850047f..e38e0b617d 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 da55075fe8..132c81eb65 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 16a419b151..3c610aca36 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 87ced85254..67d60034c8 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 ad8aded29f..a166f927a5 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 c08a4713aa..79beb304da 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 19d88e0d74..9536386238 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 3103c5f5d8..c157d5cd07 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 08b2e2255a..0000000000 --- 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 94f6e160e3..59ad7616cf 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 0000000000..ef4fcc3554 --- /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 --query 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 c4159e33e5..0000000000 --- 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 6550f985b8..ade4892d23 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 0000000000..2c356dea50 --- /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 30015d288e..0000000000 --- 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 41568cd061..44de11506d 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 0000000000..e5bec6d732 --- /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 4f22d29833..0000000000 --- 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 19bda6f548..d0cd319bed 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 0000000000..ead3f3679a --- /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 c8b1ce9b8d..0000000000 --- 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 b665f8dcec..340bf03a55 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 0000000000..435dd17fba --- /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 5e8d4fa4f4..0000000000 --- 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 18796f8f77..5b8f57cba2 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 0000000000..a9d8acb2a7 --- /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 2315e99929..0000000000 --- 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 7862e07d20..9f1346a2a6 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 0000000000..eb805e1782 --- /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 56727085de..0000000000 --- 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 9b0e8b4baf..0c691c3251 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 0000000000..ae2517bbc0 --- /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 --query 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 --query 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 7c76347c53..0000000000 --- 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 88a6d58b45..85220ac9c7 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 0000000000..39ca2bba83 --- /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 7f538e8901..0000000000 --- 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 0000000000..d0b33b0928 --- /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 --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 --query 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 a5da623a1a..0000000000 --- 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 ae0804b57b..79f9d736ae 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 0000000000..a8951a14d2 --- /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 5f21890bb1..0000000000 --- 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 ed0e818cec..388b396d5f 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/deploy.sh b/motoko/icrc2-swap/deploy.sh new file mode 100755 index 0000000000..35098999e6 --- /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 diff --git a/motoko/icrc2-swap/test.sh b/motoko/icrc2-swap/test.sh new file mode 100755 index 0000000000..b78ec0736b --- /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 8586bf55fc..0000000000 --- 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 237db2fa28..ebf260215c 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 0000000000..27124aa472 --- /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 a3511511e4..0000000000 --- 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 6ae7e837cd..49e3e4f383 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-multi-subnet.sh b/motoko/parallel_calls/test-multi-subnet.sh new file mode 100755 index 0000000000..d56c782b2a --- /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 diff --git a/motoko/parallel_calls/test.sh b/motoko/parallel_calls/test.sh new file mode 100755 index 0000000000..f1b990042f --- /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 a006166574..0000000000 --- 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 d6baa7cdcc..1e25729508 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 0000000000..52db7760ec --- /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 732cad3d9f..0000000000 --- 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 8c5c14acc1..43f3de7cb0 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-stats.sh b/motoko/query_stats/test-stats.sh new file mode 100755 index 0000000000..edb1955671 --- /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/query_stats/test.sh b/motoko/query_stats/test.sh new file mode 100755 index 0000000000..db83d3b0e6 --- /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 3bc04bd904..0000000000 --- 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 8efbcdd38f..50b7f60b20 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 0000000000..4c698d3691 --- /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 48dc24608c..0000000000 --- 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 a86509694b..b611137a89 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 0000000000..c05079159c --- /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 a0e1a29934..0000000000 --- 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 4ad80c799c..ce4df048eb 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 0000000000..5a8732214b --- /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 4c528ffaf9..0000000000 --- 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 4e8ebfaa09..44a5f6673b 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 0000000000..8645cc3805 --- /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 facf69e83e..0000000000 --- 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 86206272c6..d820bc2076 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 e8410136eb..0045bb4296 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')" + printf '%s' "$(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 27b4bd7e90..0000000000 --- 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 f44656af45..36c9db73d3 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 86afaf6d7f..54ccca0c62 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_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" + +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_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" + +node <" && exit 1 diff --git a/rust/vetkeys/basic_vetkd/Makefile b/rust/vetkeys/basic_vetkd/Makefile deleted file mode 100644 index 9e6446bbef..0000000000 --- a/rust/vetkeys/basic_vetkd/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -.PHONY: test - -test: - @echo "--- Testing basic_vetkd: symmetric key verification key ---" - @result=$$(icp canister call backend symmetric_key_verification_key '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'blob' && \ - echo "PASS" || (echo "FAIL" && exit 1) - @echo "--- Testing basic_vetkd: IBE encryption key ---" - @result=$$(icp canister call backend ibe_encryption_key '()') && \ - echo "$$result" && \ - echo "$$result" | grep -q 'blob' && \ - echo "PASS" || (echo "FAIL" && exit 1) diff --git a/rust/vetkeys/basic_vetkd/test.sh b/rust/vetkeys/basic_vetkd/test.sh new file mode 100755 index 0000000000..69f61665d9 --- /dev/null +++ b/rust/vetkeys/basic_vetkd/test.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -e + +echo "--- Testing basic_vetkd: symmetric key verification key ---" +result=$(icp canister call backend symmetric_key_verification_key '()') && \ + echo "$result" && \ + echo "$result" | grep -q 'blob' && \ + echo "PASS" || (echo "FAIL" && exit 1) +echo "--- Testing basic_vetkd: IBE encryption key ---" +result=$(icp canister call backend ibe_encryption_key '()') && \ + echo "$result" && \ + echo "$result" | grep -q 'blob' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/rust/who_am_i/Makefile b/rust/who_am_i/Makefile deleted file mode 100644 index e5eba77f5c..0000000000 --- a/rust/who_am_i/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -.PHONY: test - -test: - @echo "--- Testing whoami returns a principal ---" - @result=$$(icp canister call 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" = "$$result2" ] && \ - echo "PASS: $$result1" || (echo "FAIL: $$result1 != $$result2" && exit 1) diff --git a/rust/who_am_i/test.sh b/rust/who_am_i/test.sh new file mode 100755 index 0000000000..cdc2b491b9 --- /dev/null +++ b/rust/who_am_i/test.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -e + +echo "--- Testing whoami returns a principal ---" +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 --query backend whoami '()') && \ + result2=$(icp canister call --query backend whoami '()') && \ + [ "$result1" = "$result2" ] && \ + echo "PASS: $result1" || (echo "FAIL: $result1 != $result2" && exit 1)