Skip to content

Commit

Permalink
feat(iota-indexer): Add WriteApi tests (#3488)
Browse files Browse the repository at this point in the history
* feat(iota-indexer): add write_api tests

* fixup! feat(iota-indexer): add write_api tests

* fixup! fixup! feat(iota-indexer): add write_api tests

* fixup! fixup! fixup! feat(iota-indexer): add write_api tests

* fixup! fixup! fixup! fixup! feat(iota-indexer): add write_api tests
  • Loading branch information
sergiupopescu199 committed Oct 31, 2024
1 parent f2433ac commit a6d44ff
Show file tree
Hide file tree
Showing 3 changed files with 282 additions and 4 deletions.
35 changes: 31 additions & 4 deletions crates/iota-indexer/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ use std::{

use iota_config::node::RunWithRange;
use iota_indexer::{
IndexerConfig,
errors::IndexerError,
indexer::Indexer,
store::{indexer_store::IndexerStore, PgIndexerStore},
test_utils::{start_test_indexer, ReaderWriterConfig},
IndexerConfig,
store::{PgIndexerStore, indexer_store::IndexerStore},
test_utils::{ReaderWriterConfig, start_test_indexer},
};
use iota_metrics::init_metrics;
use iota_types::storage::ReadStore;
use iota_types::{
base_types::{ObjectID, SequenceNumber},
storage::ReadStore,
};
use jsonrpsee::{
http_client::{HttpClient, HttpClientBuilder},
types::ErrorObject,
Expand Down Expand Up @@ -117,6 +120,30 @@ pub async fn indexer_wait_for_checkpoint(
.expect("Timeout waiting for indexer to catchup to checkpoint");
}

/// Wait for the indexer to catch up to the given object sequence number
pub async fn indexer_wait_for_object(
pg_store: &PgIndexerStore,
object_id: ObjectID,
sequence_number: SequenceNumber,
) {
tokio::time::timeout(Duration::from_secs(30), async {
loop {
if pg_store
.get_object_read(object_id, Some(sequence_number))
.await
.unwrap()
.object()
.is_ok()
{
break;
}
tokio::time::sleep(Duration::from_millis(100)).await;
}
})
.await
.expect("Timeout waiting for indexer to catchup to given object's sequence number");
}

/// Start an Indexer instance in `Read` mode
fn start_indexer_reader(fullnode_rpc_url: impl Into<String>) {
let config = IndexerConfig {
Expand Down
3 changes: 3 additions & 0 deletions crates/iota-indexer/tests/rpc-tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ mod indexer_api;

#[cfg(feature = "shared_test_runtime")]
mod read_api;

#[cfg(feature = "shared_test_runtime")]
mod write_api;
248 changes: 248 additions & 0 deletions crates/iota-indexer/tests/rpc-tests/write_api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use fastcrypto::encoding::Base64;
use iota_indexer::store::indexer_store::IndexerStore;
use iota_json_rpc_api::{
IndexerApiClient, ReadApiClient, TransactionBuilderClient, WriteApiClient,
};
use iota_json_rpc_types::{
IotaExecutionStatus, IotaObjectDataOptions, IotaTransactionBlockEffectsAPI,
IotaTransactionBlockResponseOptions,
};
use iota_types::{
base_types::{IotaAddress, ObjectID},
object::Owner,
programmable_transaction_builder::ProgrammableTransactionBuilder,
quorum_driver_types::ExecuteTransactionRequestType,
transaction::TransactionKind,
};
use jsonrpsee::http_client::HttpClient;
use test_cluster::TestCluster;

use crate::common::{ApiTestSetup, indexer_wait_for_checkpoint, indexer_wait_for_object};

type TxBytes = Base64;
type Signatures = Vec<Base64>;
async fn prepare_and_sign_to_transfer_first_object(
sender: IotaAddress,
receiver: IotaAddress,
cluster: &TestCluster,
client: &HttpClient,
) -> (ObjectID, TxBytes, Signatures) {
let objects = cluster
.rpc_client()
.get_owned_objects(sender, None, None, None)
.await
.unwrap()
.data;

let obj_id = objects.first().unwrap().object().unwrap().object_id;
let gas = objects.last().unwrap().object().unwrap().object_id;

let transaction_bytes = client
.transfer_object(sender, obj_id, Some(gas), 10_000_000.into(), receiver)
.await
.unwrap();

let (tx_bytes, signatures) = cluster
.wallet
.sign_transaction(&transaction_bytes.to_data().unwrap())
.to_tx_bytes_and_signatures();

(obj_id, tx_bytes, signatures)
}

#[test]
fn dev_inspect_transaction_block() {
let ApiTestSetup {
runtime,
cluster,
store,
client,
} = ApiTestSetup::get_or_init();

runtime.block_on(async {
indexer_wait_for_checkpoint(store, 1).await;

let sender = cluster.get_address_0();
let receiver = cluster.get_address_1();

let objects = cluster
.rpc_client()
.get_owned_objects(sender, None, None, None)
.await
.unwrap()
.data;

let (obj_id, seq_num, digest) = objects.first().unwrap().object().unwrap().object_ref();

let mut builder = ProgrammableTransactionBuilder::new();
builder
.transfer_object(receiver, (obj_id, seq_num, digest))
.unwrap();
let ptb = builder.finish();

let indexer_devinspect_results = client
.dev_inspect_transaction_block(
sender,
Base64::from_bytes(&bcs::to_bytes(&TransactionKind::programmable(ptb)).unwrap()),
None,
None,
None,
)
.await
.unwrap();

assert_eq!(
*indexer_devinspect_results.effects.status(),
IotaExecutionStatus::Success
);

let (new_seq_num, owner) = indexer_devinspect_results
.effects
.mutated()
.iter()
.find_map(|obj| {
(obj.reference.object_id == obj_id).then_some((obj.reference.version, obj.owner))
})
.unwrap();

assert_eq!(owner, Owner::AddressOwner(receiver));

let latest_checkpoint_seq_number = client
.get_latest_checkpoint_sequence_number()
.await
.unwrap();

indexer_wait_for_checkpoint(store, latest_checkpoint_seq_number.into_inner() + 1).await;
assert!(
store
.get_object_read(obj_id, Some(new_seq_num))
.await
.unwrap()
.object()
.is_err(),
"The actual object should not have the sequence number incremented"
);

let actual_object_info = client
.get_object(obj_id, Some(IotaObjectDataOptions::new().with_owner()))
.await
.unwrap();

assert_eq!(
actual_object_info.data.unwrap().owner.unwrap(),
Owner::AddressOwner(sender),
"The initial owner of the object should not change"
);
});
}

#[test]
fn execute_transaction_block() {
let ApiTestSetup {
runtime,
cluster,
store,
client,
} = ApiTestSetup::get_or_init();

runtime.block_on(async {
indexer_wait_for_checkpoint(store, 1).await;

let sender = cluster.get_address_0();
let receiver = cluster.get_address_1();

let (obj_id, tx_bytes, signatures) =
prepare_and_sign_to_transfer_first_object(sender, receiver, cluster, client).await;

let indexer_tx_response = client
.execute_transaction_block(
tx_bytes,
signatures,
Some(IotaTransactionBlockResponseOptions::new().with_effects()),
Some(ExecuteTransactionRequestType::WaitForLocalExecution),
)
.await
.unwrap();

assert_eq!(
*indexer_tx_response.effects.as_ref().unwrap().status(),
IotaExecutionStatus::Success
);

let (seq_num, owner) = indexer_tx_response
.effects
.unwrap()
.mutated()
.iter()
.find_map(|obj| {
(obj.reference.object_id == obj_id).then_some((obj.reference.version, obj.owner))
})
.unwrap();

assert_eq!(owner, Owner::AddressOwner(receiver));

indexer_wait_for_object(store, obj_id, seq_num).await;

let actual_object_info = client
.get_object(obj_id, Some(IotaObjectDataOptions::new().with_owner()))
.await
.unwrap();

assert_eq!(
actual_object_info.data.unwrap().owner.unwrap(),
Owner::AddressOwner(receiver)
);
});
}

#[test]
fn dry_run_transaction_block() {
let ApiTestSetup {
runtime,
cluster,
store,
client,
} = ApiTestSetup::get_or_init();

runtime.block_on(async {
indexer_wait_for_checkpoint(store, 1).await;

let sender = cluster.get_address_0();
let receiver = cluster.get_address_1();

let (_, tx_bytes, signatures) =
prepare_and_sign_to_transfer_first_object(sender, receiver, cluster, client).await;

let dry_run_tx_block_resp = client
.dry_run_transaction_block(tx_bytes.clone())
.await
.unwrap();

let indexer_tx_response = client
.execute_transaction_block(
tx_bytes,
signatures,
Some(
IotaTransactionBlockResponseOptions::new()
.with_effects()
.with_object_changes(),
),
Some(ExecuteTransactionRequestType::WaitForLocalExecution),
)
.await
.unwrap();

assert_eq!(
*indexer_tx_response.effects.as_ref().unwrap().status(),
IotaExecutionStatus::Success
);

assert_eq!(
indexer_tx_response.object_changes.unwrap(),
dry_run_tx_block_resp.object_changes
)
});
}

0 comments on commit a6d44ff

Please sign in to comment.