Skip to content

Commit 9011fd5

Browse files
authored
Merge pull request #12 from gear-foundation/lm/test-automation
test automation
2 parents 8ad948f + 87ad1cd commit 9011fd5

7 files changed

Lines changed: 286 additions & 56 deletions

File tree

.github/workflows/daily-testnet-ts.yml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
name: Daily Testnet TS
2+
run-name: Daily Testnet TS (${{ github.ref_name }})
23

34
on:
45
schedule:
@@ -12,7 +13,7 @@ concurrency:
1213
jobs:
1314
daily-testnet-ts:
1415
runs-on: ubuntu-latest
15-
timeout-minutes: 30
16+
timeout-minutes: 45
1617

1718
steps:
1819
- name: Checkout repository
@@ -77,11 +78,11 @@ jobs:
7778
else
7879
SUMMARY="AI summary unavailable."
7980
fi
81+
MESSAGE=$(printf 'Daily Testnet TS\nStatus: %s\nBranch: %s\nRun: %s\n\n%s' \
82+
"${STATUS}" \
83+
"${{ github.ref_name }}" \
84+
"${RUN_URL}" \
85+
"${SUMMARY}")
8086
curl -sS -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
8187
-d chat_id="${TELEGRAM_CHAT_ID}" \
82-
--data-urlencode text="Daily Testnet TS: ${STATUS}
83-
Repo: ${{ github.repository }}
84-
Branch: ${{ github.ref_name }}
85-
Run: ${RUN_URL}
86-
87-
${SUMMARY}"
88+
--data-urlencode "text=${MESSAGE}"

.github/workflows/daily-testnet.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
name: Daily Testnet
2+
run-name: Daily Testnet (${{ github.ref_name }})
23

34
on:
45
schedule:

Cargo.lock

Lines changed: 23 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust-sdk-tests/tests/vft_program.rs

Lines changed: 134 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@ use tokio::{
2121
};
2222
use tracing::{info, instrument};
2323

24-
use ethexe_common::gear::CodeState;
24+
use ethexe_common::{gear::CodeState, injected::Promise};
2525
use ethexe_ethereum::{TryGetReceipt, abi::IMirror};
2626
use ethexe_sdk::VaraEthApi;
2727
use gear_core::ids::prelude::CodeIdExt as _;
28-
use gprimitives::{ActorId, CodeId, H256, U256};
28+
use gprimitives::{ActorId, CodeId, H256, MessageId, U256};
2929

3030
const VFT_WASM_PATH: &str = "../target/wasm32-gear/release/extended_vft.opt.wasm";
3131
const CODE_VALIDATION_TIMEOUT: Duration = Duration::from_secs(180);
3232
const EVENT_TIMEOUT: Duration = Duration::from_secs(60);
33+
const INJECTED_PROMISE_TIMEOUT: Duration = Duration::from_secs(120);
3334
// 5 Vara
3435
const TOP_UP_AMOUNT: u128 = 5 * 1_000_000_000_000;
3536
const BURST_TOP_UP_AMOUNT: u128 = 25 * 1_000_000_000_000;
@@ -461,6 +462,22 @@ async fn mirror_mint_with_state_change(
461462
wait_for_state_hash_change(&ctx.api, ctx.program_id, previous_state_hash).await
462463
}
463464

465+
async fn injected_watch_with_timeout(
466+
ctx: &TestVftContext,
467+
payload: Vec<u8>,
468+
label: &str,
469+
) -> Result<(MessageId, Promise)> {
470+
timeout(
471+
INJECTED_PROMISE_TIMEOUT,
472+
ctx.api
473+
.mirror(ctx.program_id)
474+
.send_message_injected_and_watch(payload, 0),
475+
)
476+
.await
477+
.with_context(|| format!("timed out while waiting for {label} injected promise"))?
478+
.with_context(|| format!("failed to send {label} injected message"))
479+
}
480+
464481
async fn assert_initial_queries(ctx: &TestVftContext) -> Result<()> {
465482
let metadata = query_metadata(&ctx.api, ctx.program_id).await?;
466483
assert_metadata(ctx, &metadata);
@@ -798,6 +815,121 @@ async fn vft_full_lifecycle_on_testnet() -> Result<()> {
798815
assert_final_state(&ctx.api, ctx.program_id, ctx.owner_actor_id, scenario.recipient).await
799816
}
800817

818+
#[tokio::test]
819+
async fn vft_injected_transfer_then_second_mint_on_testnet() -> Result<()> {
820+
init_tracing();
821+
log_step("Setup");
822+
let ctx = setup_vft_program().await?;
823+
let mirror = ctx.api.mirror(ctx.program_id);
824+
let recipient = ActorId::from(123_u64);
825+
let nonce_before_sequence = mirror.nonce().await?;
826+
827+
log_step("Mirror Mint");
828+
let mut state_hash = mirror_mint_with_state_change(&ctx, MIRROR_MINT_AMOUNT).await?;
829+
let nonce_after_mirror_mint = mirror.nonce().await?;
830+
831+
let owner_balance_after_mirror_mint =
832+
balance_of(&ctx.api, ctx.program_id, ctx.owner_actor_id).await?;
833+
let recipient_balance_after_mirror_mint = balance_of(&ctx.api, ctx.program_id, recipient).await?;
834+
let supply_after_mirror_mint = total_supply(&ctx.api, ctx.program_id).await?;
835+
836+
assert_eq!(owner_balance_after_mirror_mint, MIRROR_MINT_AMOUNT);
837+
assert_eq!(recipient_balance_after_mirror_mint, 0);
838+
assert_eq!(supply_after_mirror_mint, MIRROR_MINT_AMOUNT);
839+
assert!(
840+
nonce_after_mirror_mint > nonce_before_sequence,
841+
"mirror mint should advance mirror nonce before injected-only checks"
842+
);
843+
844+
log_step("Injected Transfer");
845+
let (_transfer_message_id, transfer_promise) = injected_watch_with_timeout(
846+
&ctx,
847+
vft_payload(
848+
"Transfer",
849+
(recipient, INJECTED_TRANSFER_AMOUNT.to_string()),
850+
),
851+
"first injected transfer",
852+
)
853+
.await?;
854+
855+
assert_manual_success(&transfer_promise.reply.code.to_bytes(), "first injected transfer");
856+
assert!(decode_sails_reply::<bool>(
857+
&transfer_promise.reply.payload,
858+
"Vft",
859+
"Transfer",
860+
)?);
861+
info!(
862+
reply_code = ?transfer_promise.reply.code.to_bytes(),
863+
"First injected transfer promise received"
864+
);
865+
866+
state_hash = wait_for_state_hash_change(&ctx.api, ctx.program_id, state_hash).await?;
867+
868+
let owner_balance_after_transfer = balance_of(&ctx.api, ctx.program_id, ctx.owner_actor_id).await?;
869+
let recipient_balance_after_transfer = balance_of(&ctx.api, ctx.program_id, recipient).await?;
870+
let supply_after_transfer = total_supply(&ctx.api, ctx.program_id).await?;
871+
872+
assert_eq!(
873+
owner_balance_after_transfer,
874+
MIRROR_MINT_AMOUNT - INJECTED_TRANSFER_AMOUNT
875+
);
876+
assert_eq!(recipient_balance_after_transfer, INJECTED_TRANSFER_AMOUNT);
877+
assert_eq!(supply_after_transfer, MIRROR_MINT_AMOUNT);
878+
879+
log_step("Second Injected Mint");
880+
let (_second_mint_message_id, second_mint_promise) = injected_watch_with_timeout(
881+
&ctx,
882+
vft_payload(
883+
"Mint",
884+
(ctx.owner_actor_id, MIRROR_MINT_AMOUNT.to_string()),
885+
),
886+
"second injected mint",
887+
)
888+
.await?;
889+
890+
assert_manual_success(&second_mint_promise.reply.code.to_bytes(), "second injected mint");
891+
assert!(decode_sails_reply::<bool>(
892+
&second_mint_promise.reply.payload,
893+
"Vft",
894+
"Mint",
895+
)?);
896+
info!(
897+
reply_code = ?second_mint_promise.reply.code.to_bytes(),
898+
"Second injected mint promise received"
899+
);
900+
901+
state_hash = wait_for_state_hash_change(&ctx.api, ctx.program_id, state_hash).await?;
902+
903+
let owner_balance_final = balance_of(&ctx.api, ctx.program_id, ctx.owner_actor_id).await?;
904+
let recipient_balance_final = balance_of(&ctx.api, ctx.program_id, recipient).await?;
905+
let supply_final = total_supply(&ctx.api, ctx.program_id).await?;
906+
let nonce_after_sequence = mirror.nonce().await?;
907+
908+
assert_eq!(
909+
owner_balance_final,
910+
MIRROR_MINT_AMOUNT - INJECTED_TRANSFER_AMOUNT + MIRROR_MINT_AMOUNT
911+
);
912+
assert_eq!(recipient_balance_final, INJECTED_TRANSFER_AMOUNT);
913+
assert_eq!(supply_final, MIRROR_MINT_AMOUNT + MIRROR_MINT_AMOUNT);
914+
assert_eq!(
915+
nonce_after_sequence,
916+
nonce_after_mirror_mint,
917+
"injected-only sequence should not advance mirror nonce beyond the mirror mint"
918+
);
919+
info!(
920+
%state_hash,
921+
owner_balance_final,
922+
recipient_balance_final,
923+
supply_final,
924+
nonce_before_sequence = %nonce_before_sequence,
925+
nonce_after_mirror_mint = %nonce_after_mirror_mint,
926+
nonce_after_sequence = %nonce_after_sequence,
927+
"Injected transfer then second mint sequence reached expected final state"
928+
);
929+
930+
Ok(())
931+
}
932+
801933
#[tokio::test]
802934
async fn vft_mirror_parallel_burst_on_testnet() -> Result<()> {
803935
init_tracing();

0 commit comments

Comments
 (0)