From 30e1fcd3c740d36e164c40290f5b6e84d3f39452 Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Wed, 19 Jun 2024 10:09:19 -0400 Subject: [PATCH 1/8] script to use init plus some initial changes to tests --- test/e2e/.gitignore | 1 + test/e2e/initialize.sh | 34 +++++++++++++++++ .../src/test-contract-client-constructor.js | 6 +-- test/e2e/src/test-custom-types.js | 4 +- test/e2e/src/util.js | 37 ++++++++++++++----- 5 files changed, 68 insertions(+), 14 deletions(-) diff --git a/test/e2e/.gitignore b/test/e2e/.gitignore index d8dea8c98..b2c0d97d4 100644 --- a/test/e2e/.gitignore +++ b/test/e2e/.gitignore @@ -4,3 +4,4 @@ yarn.lock contract-*.txt .soroban wasms/specs/*.json +test-contracts \ No newline at end of file diff --git a/test/e2e/initialize.sh b/test/e2e/initialize.sh index 740a90ac7..de87aa038 100755 --- a/test/e2e/initialize.sh +++ b/test/e2e/initialize.sh @@ -42,3 +42,37 @@ if [[ "$NETWORK_STATUS" != "healthy" ]]; then fi $soroban keys generate $SOROBAN_ACCOUNT + +# retrieve the contracts using soroban contract init then build them if they dont already exist +# Define directory and WASM file paths +target_dir="$dirname/test-contracts/target/wasm32-unknown-unknown/release" +wasm_files=( + "soroban_custom_types_contract.wasm" + "soroban_atomic_swap_contract.wasm" + "soroban_token_contract.wasm" + "soroban_increment_contract.wasm" + "hello_world.wasm" +) + +# Check if all WASM files exist +all_exist=true +for wasm_file in "${wasm_files[@]}"; do + if [ ! -f "$target_dir/$wasm_file" ]; then + all_exist=false + break + fi +done + +# If any WASM file is missing, initialize and build the contracts +if [ "$all_exist" = false ]; then + echo "One or more WASM files are missing. Initializing and building contracts..." + + # Initialize contracts + $soroban contract init "$dirname/test-contracts" --with-example increment custom_types atomic_swap token + + # Change directory to test-contracts and build the contracts + cd "$dirname/test-contracts" || { echo "Failed to change directory!"; exit 1; } + $soroban contract build +else + echo "All WASM files are present." +fi diff --git a/test/e2e/src/test-contract-client-constructor.js b/test/e2e/src/test-contract-client-constructor.js index c0eb015c8..67bc02e54 100644 --- a/test/e2e/src/test-contract-client-constructor.js +++ b/test/e2e/src/test-contract-client-constructor.js @@ -92,14 +92,14 @@ async function clientForFromTest(contractId, publicKey, keypair) { describe("Client", function () { before(async function () { const { client, keypair, contractId } = - await clientFromConstructor("customTypes"); + await clientFromConstructor("helloWorld"); const publicKey = keypair.publicKey(); const addr = Address.fromString(publicKey); this.context = { client, publicKey, addr, contractId, keypair }; }); - it("can be constructed with `new Client`", async function () { - const { result } = await this.context.client.hello({ hello: "tests" }); + it("can be constructed with `new Client`", async function() { + const { result } = await this.context.client.hello({ to: "tests" }); expect(result).to.equal("tests"); }); diff --git a/test/e2e/src/test-custom-types.js b/test/e2e/src/test-custom-types.js index b5c253653..ef23c01a9 100644 --- a/test/e2e/src/test-custom-types.js +++ b/test/e2e/src/test-custom-types.js @@ -16,8 +16,8 @@ describe("Custom Types Tests", function () { ).to.equal("tests"); }); - it("view method with empty keypair", async function () { - const { client: client2 } = await clientFor("customTypes", { + it("view method with empty keypair", async function() { + const { client: client2 } = await clientFor("helloWorld", { keypair: undefined, contractId: this.context.contractId, }); diff --git a/test/e2e/src/util.js b/test/e2e/src/util.js index 6d760c976..43d94ec56 100644 --- a/test/e2e/src/util.js +++ b/test/e2e/src/util.js @@ -1,6 +1,7 @@ const { spawnSync } = require("node:child_process"); const { contract, Keypair } = require("../../.."); +const basePath = `${__dirname}/../test-contracts/target/wasm32-unknown-unknown/release`; const contracts = { customTypes: { hash: spawnSync( @@ -9,11 +10,11 @@ const contracts = { "contract", "install", "--wasm", - `${__dirname}/../wasms/test_custom_types.wasm`, + `${basePath}/soroban_custom_types_contract.wasm`, ], { shell: true, encoding: "utf8" }, ).stdout.trim(), - path: `${__dirname}/../wasms/test_custom_types.wasm`, + path: `${basePath}/soroban_custom_types_contract.wasm`, }, helloWorld: { hash: spawnSync( @@ -22,19 +23,37 @@ const contracts = { "contract", "install", "--wasm", - `${__dirname}/../wasms/test_hello_world.wasm`, + `${basePath}/hello_world.wasm`, ], { shell: true, encoding: "utf8" }, ).stdout.trim(), - path: `${__dirname}/../wasms/test_hello_world.wasm`, + path: `${basePath}/hello_world.wasm`, + }, + increment: { + hash: spawnSync( + "./target/bin/soroban", + [ + "contract", + "install", + "--wasm", + `${basePath}/soroban_increment_contract.wasm`, + ], + { shell: true, encoding: "utf8" }, + ).stdout.trim(), + path: `${basePath}/soroban_increment_contract.wasm`, }, swap: { hash: spawnSync( "./target/bin/soroban", - ["contract", "install", "--wasm", `${__dirname}/../wasms/test_swap.wasm`], + [ + "contract", + "install", + "--wasm", + `${basePath}/soroban_atomic_swap_contract.wasm`, + ], { shell: true, encoding: "utf8" }, ).stdout.trim(), - path: `${__dirname}/../wasms/test_swap.wasm`, + path: `${basePath}/soroban_atomic_swap_contract.wasm`, }, token: { hash: spawnSync( @@ -43,11 +62,11 @@ const contracts = { "contract", "install", "--wasm", - `${__dirname}/../wasms/test_token.wasm`, + `${basePath}/soroban_token_contract.wasm`, ], { shell: true, encoding: "utf8" }, ).stdout.trim(), - path: `${__dirname}/../wasms/test_token.wasm`, + path: `${basePath}/soroban_token_contract.wasm`, }, }; module.exports.contracts = contracts; @@ -65,7 +84,7 @@ module.exports.friendbotUrl = friendbotUrl; async function generateFundedKeypair() { const keypair = Keypair.random(); - await fetch(`${friendbotUrl}/friendbot?addr=${keypair.publicKey()}`); + await fetch(`${friendbotUrl}/?addr=${keypair.publicKey()}`); return keypair; } module.exports.generateFundedKeypair = generateFundedKeypair; From e7c024e8bbe1c87a076bba92ec9124d9de549c29 Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Thu, 20 Jun 2024 15:12:46 -0400 Subject: [PATCH 2/8] finish getting tests working --- .../src/test-contract-client-constructor.js | 2 +- test/e2e/src/test-custom-types.js | 33 +++++++++++++++--- test/e2e/src/test-hello-world.js | 34 ------------------- test/e2e/src/test-methods-as-args.js | 2 +- test/e2e/src/util.js | 2 +- 5 files changed, 31 insertions(+), 42 deletions(-) delete mode 100644 test/e2e/src/test-hello-world.js diff --git a/test/e2e/src/test-contract-client-constructor.js b/test/e2e/src/test-contract-client-constructor.js index 67bc02e54..79479ba6c 100644 --- a/test/e2e/src/test-contract-client-constructor.js +++ b/test/e2e/src/test-contract-client-constructor.js @@ -100,7 +100,7 @@ describe("Client", function () { it("can be constructed with `new Client`", async function() { const { result } = await this.context.client.hello({ to: "tests" }); - expect(result).to.equal("tests"); + expect(result).to.deep.equal(["Hello", "tests"]); }); it("can be constructed with `from`", async function () { diff --git a/test/e2e/src/test-custom-types.js b/test/e2e/src/test-custom-types.js index ef23c01a9..14ecfdce6 100644 --- a/test/e2e/src/test-custom-types.js +++ b/test/e2e/src/test-custom-types.js @@ -17,19 +17,42 @@ describe("Custom Types Tests", function () { }); it("view method with empty keypair", async function() { - const { client: client2 } = await clientFor("helloWorld", { + const { client: client2 } = await clientFor("customTypes", { keypair: undefined, - contractId: this.context.contractId, + contractId: this.context.contractId }); - expect((await client2.hello({ hello: "anonymous" })).result).to.equal( - "anonymous", - ); + expect((await client2.i32_({ i32_: 1 })).result).to.equal(1); + }); + + it("should increment the counter correctly", async function() { + const { result: startingBalance } = await this.context.client.get_count(); + const inc = await this.context.client.inc(); + const incrementResponse = await inc.signAndSend(); + expect(incrementResponse.result).to.equal(startingBalance + 1); + expect(startingBalance).to.equal(0); // Assuming the counter starts at 0 + const { result: newBalance } = await this.context.client.get_count(); + expect(newBalance).to.equal(startingBalance + 1); + }); + + it("should accept only options object for methods with no arguments", async function() { + const inc = await this.context.client.inc({ simulate: false }); + expect(inc.simulation).to.be.undefined; }); it("woid", async function () { expect((await this.context.client.woid()).result).to.be.null; }); + it("should authenticate the user correctly", async function() { + const { result } = await this.context.client.auth({ addr: this.context.publicKey, world: "lol" }); + expect(result).to.equal(this.context.publicKey); + }); + + it("should authenticate the user correctly", async function() { + const { result } = await this.context.client.auth({ addr: this.context.publicKey, world: "lol" }); + expect(result).to.equal(this.context.publicKey); + }); + it("u32_fail_on_even", async function () { let response = await this.context.client.u32_fail_on_even({ u32_: 1 }); expect(response.result).to.deep.equal(new contract.Ok(1)); diff --git a/test/e2e/src/test-hello-world.js b/test/e2e/src/test-hello-world.js deleted file mode 100644 index ac74a4629..000000000 --- a/test/e2e/src/test-hello-world.js +++ /dev/null @@ -1,34 +0,0 @@ -const { expect } = require("chai"); -const { clientFor } = require("./util"); - -describe("helloWorld client", function () { - it("should return properly formed hello response", async function () { - const { client } = await clientFor("helloWorld"); - const response = await client.hello({ world: "tests" }); - expect(response.result).to.deep.equal(["Hello", "tests"]); - }); - - it("should authenticate the user correctly", async function () { - const { client, keypair } = await clientFor("helloWorld"); - const publicKey = keypair.publicKey(); - const { result } = await client.auth({ addr: publicKey, world: "lol" }); - expect(result).to.equal(publicKey); - }); - - it("should increment the counter correctly", async function () { - const { client } = await clientFor("helloWorld"); - const { result: startingBalance } = await client.get_count(); - const inc = await client.inc(); - const incrementResponse = await inc.signAndSend(); - expect(incrementResponse.result).to.equal(startingBalance + 1); - expect(startingBalance).to.equal(0); // Assuming the counter starts at 0 - const { result: newBalance } = await client.get_count(); - expect(newBalance).to.equal(startingBalance + 1); - }); - - it("should accept only options object for methods with no arguments", async function () { - const { client } = await clientFor("helloWorld"); - const inc = await client.inc({ simulate: false }); - expect(inc.simulation).to.be.undefined; - }); -}); diff --git a/test/e2e/src/test-methods-as-args.js b/test/e2e/src/test-methods-as-args.js index 3308e907d..97cf096c8 100644 --- a/test/e2e/src/test-methods-as-args.js +++ b/test/e2e/src/test-methods-as-args.js @@ -9,7 +9,7 @@ function callMethod(method, args) { describe("methods-as-args", function () { it("should pass methods as arguments and have them still work", async function () { const { client } = await clientFor("helloWorld"); - const { result } = await callMethod(client.hello, { world: "tests" }); + const { result } = await callMethod(client.hello, { to: "tests" }); expect(result).to.deep.equal(["Hello", "tests"]); }); }); diff --git a/test/e2e/src/util.js b/test/e2e/src/util.js index 43d94ec56..81a865ce2 100644 --- a/test/e2e/src/util.js +++ b/test/e2e/src/util.js @@ -84,7 +84,7 @@ module.exports.friendbotUrl = friendbotUrl; async function generateFundedKeypair() { const keypair = Keypair.random(); - await fetch(`${friendbotUrl}/?addr=${keypair.publicKey()}`); + await fetch(friendbotUrl.indexOf('friendbot.stellar.org') !== -1 ? `${friendbotUrl}/?addr=${keypair.publicKey()}` : `${friendbotUrl}/friendbot?addr=${keypair.publicKey()}`); return keypair; } module.exports.generateFundedKeypair = generateFundedKeypair; From 5382431617fe1a53679a7d8cfb6d3fe49b5fb85b Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Thu, 27 Jun 2024 16:56:16 -0400 Subject: [PATCH 3/8] fix security report error --- test/e2e/src/util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/src/util.js b/test/e2e/src/util.js index 81a865ce2..d5aa1d188 100644 --- a/test/e2e/src/util.js +++ b/test/e2e/src/util.js @@ -84,7 +84,7 @@ module.exports.friendbotUrl = friendbotUrl; async function generateFundedKeypair() { const keypair = Keypair.random(); - await fetch(friendbotUrl.indexOf('friendbot.stellar.org') !== -1 ? `${friendbotUrl}/?addr=${keypair.publicKey()}` : `${friendbotUrl}/friendbot?addr=${keypair.publicKey()}`); + await fetch(friendbotUrl.indexOf('https://friendbot.stellar.org') !== -1 ? `${friendbotUrl}/?addr=${keypair.publicKey()}` : `${friendbotUrl}/friendbot?addr=${keypair.publicKey()}`); return keypair; } module.exports.generateFundedKeypair = generateFundedKeypair; From 77132f6a651ee0e7f3180b33185c5c2c27658327 Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Thu, 27 Jun 2024 17:05:11 -0400 Subject: [PATCH 4/8] actually fix security issue --- test/e2e/src/util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/src/util.js b/test/e2e/src/util.js index d5aa1d188..ab769c5d9 100644 --- a/test/e2e/src/util.js +++ b/test/e2e/src/util.js @@ -84,7 +84,7 @@ module.exports.friendbotUrl = friendbotUrl; async function generateFundedKeypair() { const keypair = Keypair.random(); - await fetch(friendbotUrl.indexOf('https://friendbot.stellar.org') !== -1 ? `${friendbotUrl}/?addr=${keypair.publicKey()}` : `${friendbotUrl}/friendbot?addr=${keypair.publicKey()}`); + await fetch(friendbotUrl.startsWith('https://friendbot.stellar.org') ? `${friendbotUrl}/?addr=${keypair.publicKey()}` : `${friendbotUrl}/friendbot?addr=${keypair.publicKey()}`); return keypair; } module.exports.generateFundedKeypair = generateFundedKeypair; From e2338bfb7601da59b1e7064678a20d143b70f316 Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Thu, 27 Jun 2024 17:08:50 -0400 Subject: [PATCH 5/8] url fix --- test/e2e/src/util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/src/util.js b/test/e2e/src/util.js index ab769c5d9..5e8980173 100644 --- a/test/e2e/src/util.js +++ b/test/e2e/src/util.js @@ -84,7 +84,7 @@ module.exports.friendbotUrl = friendbotUrl; async function generateFundedKeypair() { const keypair = Keypair.random(); - await fetch(friendbotUrl.startsWith('https://friendbot.stellar.org') ? `${friendbotUrl}/?addr=${keypair.publicKey()}` : `${friendbotUrl}/friendbot?addr=${keypair.publicKey()}`); + await fetch(friendbotUrl === 'https://friendbot.stellar.org' ? `${friendbotUrl}/?addr=${keypair.publicKey()}` : `${friendbotUrl}/friendbot?addr=${keypair.publicKey()}`); return keypair; } module.exports.generateFundedKeypair = generateFundedKeypair; From 3cd94da76cf3baba0b55c82e4b96f3a486ceeedc Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Thu, 27 Jun 2024 17:18:52 -0400 Subject: [PATCH 6/8] make sure target is present on CI --- .github/workflows/e2e.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index e9a2301a8..50dbbc2e8 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -34,6 +34,7 @@ jobs: # Workaround for some `yarn` nonsense, see: # https://github.com/yarnpkg/yarn/issues/6312#issuecomment-429685210 + - run: rustup target add wasm32-unknown-unknown - run: yarn install --network-concurrency 1 - run: yarn build:prod - run: yarn test:e2e From b5e8faa35384ee23df43b5d8e62c99c9aa0281ec Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Thu, 11 Jul 2024 10:45:07 -0400 Subject: [PATCH 7/8] rerun contract init if example repo updated --- test/e2e/initialize.sh | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/test/e2e/initialize.sh b/test/e2e/initialize.sh index de87aa038..e3765cedc 100755 --- a/test/e2e/initialize.sh +++ b/test/e2e/initialize.sh @@ -36,16 +36,18 @@ echo " RPC: $SOROBAN_RPC_URL" echo " Passphrase: \"$SOROBAN_NETWORK_PASSPHRASE\"" echo " Status: $NETWORK_STATUS" -if [[ "$NETWORK_STATUS" != "healthy" ]]; then - echo "Network is not healthy (not running?), exiting" - exit 1 -fi +#if [[ "$NETWORK_STATUS" != "healthy" ]]; then +# echo "Network is not healthy (not running?), exiting" +# exit 1 +#fi -$soroban keys generate $SOROBAN_ACCOUNT +#$soroban keys generate $SOROBAN_ACCOUNT # retrieve the contracts using soroban contract init then build them if they dont already exist # Define directory and WASM file paths target_dir="$dirname/test-contracts/target/wasm32-unknown-unknown/release" +contracts_dir="$dirname/test-contracts" +repo_url="https://github.com/stellar/soroban-examples.git" wasm_files=( "soroban_custom_types_contract.wasm" "soroban_atomic_swap_contract.wasm" @@ -54,7 +56,22 @@ wasm_files=( "hello_world.wasm" ) -# Check if all WASM files exist +get_remote_git_hash() { + git ls-remote "$repo_url" HEAD | cut -f1 +} + +# Get the current git hash +current_hash=$(get_remote_git_hash) + +# Check if a stored hash exists +hash_file="$contracts_dir/.last_build_hash" +if [ -f "$hash_file" ]; then + stored_hash=$(cat "$hash_file") +else + stored_hash="" +fi + +# Check if all WASM files exist and if the git hash has changed all_exist=true for wasm_file in "${wasm_files[@]}"; do if [ ! -f "$target_dir/$wasm_file" ]; then @@ -63,16 +80,17 @@ for wasm_file in "${wasm_files[@]}"; do fi done -# If any WASM file is missing, initialize and build the contracts -if [ "$all_exist" = false ]; then - echo "One or more WASM files are missing. Initializing and building contracts..." - +# If any WASM file is missing or the git hash has changed, initialize and build the contracts +if [ "$all_exist" = false ] || [ "$current_hash" != "$stored_hash" ]; then + echo "WASM files are missing or contracts have been updated. Initializing and building contracts..." # Initialize contracts $soroban contract init "$dirname/test-contracts" --with-example increment custom_types atomic_swap token # Change directory to test-contracts and build the contracts cd "$dirname/test-contracts" || { echo "Failed to change directory!"; exit 1; } $soroban contract build + # Save git hash to file + echo "$current_hash" > "$hash_file" else - echo "All WASM files are present." + echo "All WASM files are present and up to date." fi From 28db117a93ea56e1155d5b9076d875127d7dca46 Mon Sep 17 00:00:00 2001 From: Blaine Heffron Date: Thu, 11 Jul 2024 11:06:37 -0400 Subject: [PATCH 8/8] forgot to uncomment --- test/e2e/initialize.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/e2e/initialize.sh b/test/e2e/initialize.sh index e3765cedc..ae453bbb9 100755 --- a/test/e2e/initialize.sh +++ b/test/e2e/initialize.sh @@ -36,12 +36,12 @@ echo " RPC: $SOROBAN_RPC_URL" echo " Passphrase: \"$SOROBAN_NETWORK_PASSPHRASE\"" echo " Status: $NETWORK_STATUS" -#if [[ "$NETWORK_STATUS" != "healthy" ]]; then -# echo "Network is not healthy (not running?), exiting" -# exit 1 -#fi +if [[ "$NETWORK_STATUS" != "healthy" ]]; then + echo "Network is not healthy (not running?), exiting" + exit 1 +fi -#$soroban keys generate $SOROBAN_ACCOUNT +$soroban keys generate $SOROBAN_ACCOUNT # retrieve the contracts using soroban contract init then build them if they dont already exist # Define directory and WASM file paths