mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-08-27 04:11:08 +00:00
This PR introduces the initial Cucumber-based integration test framework for the LEZ, building on the testing-framework integration work started by @andrussal, adds the first set of Cucumber integration scenarios and establishes reusable infrastructure for future Cucumber scenarios. --------- Co-authored-by: Andrus Salumets <salumets.andrus@gmail.com> Co-authored-by: Sergio Chouhy <sergio.chouhy@gmail.com> Co-authored-by: Sergio Chouhy <41742639+schouhy@users.noreply.github.com> Co-authored-by: Roman <zajic@zajic.net> Co-authored-by: Daniil Polyakov <arjentix@gmail.com> Co-authored-by: Moudy <m.ellaz@hotmail.com> Co-authored-by: andrussal <salumets.andrus@gmail.com>
150 lines
5.1 KiB
Rust
150 lines
5.1 KiB
Rust
use std::time::Duration;
|
|
|
|
use common::HashType;
|
|
use indexer_service_protocol::HashType as IndexerHashType;
|
|
use indexer_service_rpc::RpcClient as _;
|
|
use sequencer_service_rpc::RpcClient as _;
|
|
use thiserror::Error;
|
|
|
|
use super::{LezIndexerClient, LezSequencerClient};
|
|
|
|
/// Failure modes while waiting for the indexer to reach the sequencer.
|
|
#[derive(Debug, Error)]
|
|
pub enum IndexerCatchUpError {
|
|
/// The sequencer height could not be queried.
|
|
#[error("failed to query sequencer while waiting for indexer: {message}")]
|
|
SequencerQuery {
|
|
/// Diagnostic returned by the sequencer RPC client.
|
|
message: String,
|
|
},
|
|
/// The indexer height could not be queried.
|
|
#[error("failed to query indexer while waiting for catch-up: {message}")]
|
|
IndexerQuery {
|
|
/// Diagnostic returned by the indexer RPC client.
|
|
message: String,
|
|
},
|
|
/// The indexer did not reach the target within the configured duration.
|
|
#[error(
|
|
"indexer failed to catch up to sequencer block {target}; last observed indexer block {last_observed} after {elapsed:?}"
|
|
)]
|
|
Timeout {
|
|
/// Sequencer block height the indexer was expected to reach.
|
|
target: u64,
|
|
/// Highest indexer block height observed while polling.
|
|
last_observed: u64,
|
|
/// Duration spent polling before timing out.
|
|
elapsed: Duration,
|
|
},
|
|
}
|
|
|
|
/// Polls the indexer until it reaches the sequencer's current last block.
|
|
pub async fn wait_for_indexer_to_catch_up(
|
|
indexer: &LezIndexerClient,
|
|
sequencer: &LezSequencerClient,
|
|
) -> Result<u64, IndexerCatchUpError> {
|
|
wait_for_indexer_to_catch_up_with_timeout(indexer, sequencer, Duration::from_secs(360)).await
|
|
}
|
|
|
|
/// Polls the indexer until it reaches the sequencer's current last block or the timeout elapses.
|
|
pub async fn wait_for_indexer_to_catch_up_with_timeout(
|
|
indexer: &LezIndexerClient,
|
|
sequencer: &LezSequencerClient,
|
|
timeout: Duration,
|
|
) -> Result<u64, IndexerCatchUpError> {
|
|
let block_id_to_catch_up = sequencer
|
|
.client()
|
|
.get_last_block_id()
|
|
.await
|
|
.map_err(|error| IndexerCatchUpError::SequencerQuery {
|
|
message: error.to_string(),
|
|
})?;
|
|
wait_for_indexer_to_reach_with_timeout(indexer, block_id_to_catch_up, timeout).await
|
|
}
|
|
|
|
/// Polls the indexer until it reaches a specific finalized block or the timeout elapses.
|
|
pub async fn wait_for_indexer_to_reach_with_timeout(
|
|
indexer: &LezIndexerClient,
|
|
block_id_to_reach: u64,
|
|
timeout: Duration,
|
|
) -> Result<u64, IndexerCatchUpError> {
|
|
let mut last_indexer_block = 0;
|
|
|
|
let poll = async {
|
|
loop {
|
|
let indexer_block = indexer
|
|
.client()
|
|
.get_last_finalized_block_id()
|
|
.await
|
|
.map_err(|error| error.to_string())?
|
|
.unwrap_or(0);
|
|
last_indexer_block = indexer_block;
|
|
|
|
if indexer_block >= block_id_to_reach && indexer_block > 0 {
|
|
return Ok::<u64, String>(indexer_block);
|
|
}
|
|
|
|
tokio::time::sleep(Duration::from_secs(2)).await;
|
|
}
|
|
};
|
|
|
|
match tokio::time::timeout(timeout, poll).await {
|
|
Ok(Ok(height)) => Ok(height),
|
|
Ok(Err(error)) => Err(IndexerCatchUpError::IndexerQuery { message: error }),
|
|
Err(_elapsed) => Err(IndexerCatchUpError::Timeout {
|
|
target: block_id_to_reach,
|
|
last_observed: last_indexer_block,
|
|
elapsed: timeout,
|
|
}),
|
|
}
|
|
}
|
|
|
|
/// Polls the indexer until all supplied transactions are present in its
|
|
/// finalized transaction store or the timeout elapses.
|
|
pub async fn wait_for_indexer_to_index_transactions_with_timeout(
|
|
indexer: &LezIndexerClient,
|
|
transaction_hashes: &[HashType],
|
|
target_block: u64,
|
|
timeout: Duration,
|
|
) -> Result<u64, IndexerCatchUpError> {
|
|
let mut last_indexer_block = 0;
|
|
|
|
let poll = async {
|
|
loop {
|
|
last_indexer_block = indexer
|
|
.client()
|
|
.get_last_finalized_block_id()
|
|
.await
|
|
.map_err(|error| error.to_string())?
|
|
.unwrap_or(0);
|
|
|
|
let mut all_indexed = true;
|
|
for hash in transaction_hashes {
|
|
let indexed = indexer_service_rpc::RpcClient::get_transaction(
|
|
&**indexer.client(),
|
|
IndexerHashType(hash.0),
|
|
)
|
|
.await
|
|
.map_err(|error| error.to_string())?
|
|
.is_some();
|
|
all_indexed &= indexed;
|
|
}
|
|
|
|
if all_indexed && last_indexer_block >= target_block {
|
|
return Ok::<u64, String>(last_indexer_block);
|
|
}
|
|
|
|
tokio::time::sleep(Duration::from_secs(2)).await;
|
|
}
|
|
};
|
|
|
|
match tokio::time::timeout(timeout, poll).await {
|
|
Ok(Ok(height)) => Ok(height),
|
|
Ok(Err(error)) => Err(IndexerCatchUpError::IndexerQuery { message: error }),
|
|
Err(_elapsed) => Err(IndexerCatchUpError::Timeout {
|
|
target: target_block,
|
|
last_observed: last_indexer_block,
|
|
elapsed: timeout,
|
|
}),
|
|
}
|
|
}
|