diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index f3c58ea0a..2ba05a6ec 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -157,8 +157,66 @@ jobs: chmod uog+x target/release/zeitgeist cd integration-tests + export NODE_OPTIONS="--require ./scripts/ws-shim.cjs" pnpm exec moonwall test zombienet_zeitgeist_upgrade --runInBand + zombienet_battery_station_upgrade: + name: Battery Station Zombienet Post-Upgrade Tests + runs-on: ubuntu-22.04 + needs: ["build_parachain"] + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install build tools + run: ./scripts/init.sh + + - uses: pnpm/action-setup@v2 + with: + version: 8 + - uses: actions/setup-node@v3 + with: + node-version: 20.x + cache: "pnpm" + cache-dependency-path: "./integration-tests/pnpm-lock.yaml" + + - name: Install pnpm packages + run: | + cd integration-tests + pnpm install + + - name: Cache Dependencies + uses: Swatinem/rust-cache@v2 + + - name: Create local folders + run: | + mkdir -p target/release/wbuild/battery-station-runtime/ + mkdir -p integration-tests/tmp + + - name: Download runtime + uses: actions/download-artifact@v4.1.8 + with: + name: runtimes + path: target/release/wbuild/battery-station-runtime/ + + - name: Download binary + uses: actions/download-artifact@v4.1.8 + with: + name: binaries + path: target/release + + - name: Display structure of downloaded files + run: ls -R + working-directory: target/ + + - name: Test battery-station runtime upgrade using Zombienet + run: | + chmod uog+x target/release/zeitgeist + + cd integration-tests + export NODE_OPTIONS="--require ./scripts/ws-shim.cjs" + pnpm exec moonwall test zombienet_battery_station_upgrade --runInBand + chopsticks_battery_station_upgrade: name: Battery Station Chopsticks Post-Upgrade Tests runs-on: ubuntu-22.04 @@ -205,6 +263,7 @@ jobs: - name: Battery Station post-upgrade tests using Chopsticks run: | cd integration-tests + export NODE_OPTIONS="--require ./scripts/ws-shim.cjs" pnpm exec moonwall test chopsticks_battery_station_upgrade --runInBand - name: Show chopsticks logs @@ -260,6 +319,7 @@ jobs: - name: Zeitgeist post-upgrade tests using Chopsticks run: | cd integration-tests + export NODE_OPTIONS="--require ./scripts/ws-shim.cjs" pnpm exec moonwall test chopsticks_zeitgeist_upgrade --runInBand - name: Show chopsticks logs diff --git a/integration-tests/scripts/ws-shim.cjs b/integration-tests/scripts/ws-shim.cjs new file mode 100644 index 000000000..5ec53eaa3 --- /dev/null +++ b/integration-tests/scripts/ws-shim.cjs @@ -0,0 +1,4 @@ +// Ensure a global WebSocket exists when running under Node. +if (typeof global.WebSocket === "undefined") { + global.WebSocket = require("ws"); +} diff --git a/integration-tests/tests/common-tests.ts b/integration-tests/tests/common-tests.ts index 29983ffc0..def155d3f 100644 --- a/integration-tests/tests/common-tests.ts +++ b/integration-tests/tests/common-tests.ts @@ -16,6 +16,7 @@ // You should have received a copy of the GNU General Public License // along with Zeitgeist. If not, see . +import "./setup-websocket"; import { expect, ChopsticksContext } from "@moonwall/cli"; import { generateKeyringPair } from "@moonwall/util"; import { ApiPromise, Keyring } from "@polkadot/api"; diff --git a/integration-tests/tests/rt-upgrade-battery-station-chopsticks/test-battery-station-chopsticks-runtime-upgrade.ts b/integration-tests/tests/rt-upgrade-battery-station-chopsticks/test-battery-station-chopsticks-runtime-upgrade.ts index f33973c74..9443caefe 100644 --- a/integration-tests/tests/rt-upgrade-battery-station-chopsticks/test-battery-station-chopsticks-runtime-upgrade.ts +++ b/integration-tests/tests/rt-upgrade-battery-station-chopsticks/test-battery-station-chopsticks-runtime-upgrade.ts @@ -16,6 +16,7 @@ // You should have received a copy of the GNU General Public License // along with Zeitgeist. If not, see . +import "../setup-websocket"; import { MoonwallContext, beforeAll, diff --git a/integration-tests/tests/rt-upgrade-zeitgeist-chopsticks/test-zeitgeist-chopsticks-runtime-upgrade.ts b/integration-tests/tests/rt-upgrade-zeitgeist-chopsticks/test-zeitgeist-chopsticks-runtime-upgrade.ts index c73a0862b..1e97492d7 100644 --- a/integration-tests/tests/rt-upgrade-zeitgeist-chopsticks/test-zeitgeist-chopsticks-runtime-upgrade.ts +++ b/integration-tests/tests/rt-upgrade-zeitgeist-chopsticks/test-zeitgeist-chopsticks-runtime-upgrade.ts @@ -16,6 +16,7 @@ // You should have received a copy of the GNU General Public License // along with Zeitgeist. If not, see . +import "../setup-websocket"; import { MoonwallContext, beforeAll, diff --git a/integration-tests/tests/rt-upgrade-zombienet/test-zombienet-runtime-upgrade.ts b/integration-tests/tests/rt-upgrade-zombienet/test-zombienet-runtime-upgrade.ts index b93ac0e7e..51fd76763 100644 --- a/integration-tests/tests/rt-upgrade-zombienet/test-zombienet-runtime-upgrade.ts +++ b/integration-tests/tests/rt-upgrade-zombienet/test-zombienet-runtime-upgrade.ts @@ -16,6 +16,7 @@ // You should have received a copy of the GNU General Public License // along with Zeitgeist. If not, see . +import "../setup-websocket"; import { MoonwallContext, beforeAll, @@ -117,32 +118,67 @@ describeSuite({ ); } - const txStatus = async (tx: any, label: string) => + const txStatus = async (tx: any, label: string, timeoutMs = 120_000) => new Promise((resolve, reject) => { let unsubscribe: (() => void) | undefined; + const timeout = setTimeout(() => { + const err = new Error(`${label} timed out waiting for inclusion`); + log(err.message); + unsubscribe?.(); + reject(err); + }, timeoutMs); + + const finish = (fn: (value?: any) => void, msg?: string, err?: any) => { + clearTimeout(timeout); + if (msg) { + log(msg); + } + unsubscribe?.(); + fn(err); + }; + tx.signAndSend(alice, (result: any) => { + const status = result.status; + if (result.dispatchError) { // Dispatch errors won't throw, so surface them explicitly. const errText = result.dispatchError.toString(); - log(`${label} dispatchError=${errText}`); - reject(new Error(`${label} failed: ${errText}`)); - unsubscribe?.(); + finish(reject, `${label} dispatchError=${errText}`, new Error(errText)); return; } + log( - `${label} status=${result.status?.type ?? "unknown"}, events=${result.events + `${label} status=${status?.type ?? "unknown"}, events=${result.events ?.map((ev: any) => `${ev.event.section}.${ev.event.method}`) .join(",")}` ); - if (result.status?.isInBlock || result.status?.isFinalized) { - unsubscribe?.(); - resolve(); + + if ( + status?.isDropped || + status?.isInvalid || + status?.isUsurped || + status?.isRetracted || + status?.isFinalityTimeout + ) { + finish( + reject, + `${label} failed with status=${status?.type ?? "unknown"}`, + new Error(`${label} failed with status=${status?.type ?? "unknown"}`) + ); + return; + } + + if (status?.isInBlock || status?.isFinalized) { + finish(resolve); } }) .then((unsub: () => void) => { unsubscribe = unsub; }) - .catch(reject); + .catch((err: any) => { + clearTimeout(timeout); + reject(err); + }); }); const findCall = (callName: string) => { diff --git a/integration-tests/tests/setup-websocket.ts b/integration-tests/tests/setup-websocket.ts new file mode 100644 index 000000000..1edab3a5b --- /dev/null +++ b/integration-tests/tests/setup-websocket.ts @@ -0,0 +1,7 @@ +// Provide a global WebSocket for Node environments. +import WebSocket from "ws"; + +const g = globalThis as Record; +if (!g.WebSocket) { + g.WebSocket = WebSocket; +}