Skip to content

Commit

Permalink
Export a registry of all integration tests (#1449)
Browse files Browse the repository at this point in the history
* create a proc macro to register tests to a global TEST_REGISTRY

* consume an annotated test

* annotate exported tests with the macro

* use a BTreeMap to store the registry of tests

* don't deploy fake actors that are already seeded into the testvm

* use correct memoryblockstore

* load placeholder code cid from manifest

* don't run tests via array in test_vm

* generate unique names for the functions including module name

* allow annotating the attribute to indicate the speed of tests

* mark an example test as slow
  • Loading branch information
alexytsu authored Oct 20, 2023
1 parent c4cdd4a commit 1e50065
Show file tree
Hide file tree
Showing 24 changed files with 272 additions and 39 deletions.
67 changes: 44 additions & 23 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions integration_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ regex = { workspace = true }
serde = { workspace = true }
thiserror = { workspace = true }
libsecp256k1 = { workspace = true }
export_macro = { path = "./macro" }
ctor = "0.2.5"

[dev-dependencies]
multihash = { workspace = true }
Expand Down
15 changes: 15 additions & 0 deletions integration_tests/macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "export_macro"
description = "Macro to decorate integration tests"
version = "1.0.0"
license = "MIT OR Apache-2.0"
edition = "2021"
publish = false

[lib]
proc-macro = true

[dependencies]
syn = "2.0.38"
quote = "1.0.33"
proc-macro2 = "1.0.69"
49 changes: 49 additions & 0 deletions integration_tests/macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use proc_macro::TokenStream;
use quote::{format_ident, quote};

/// The vm_test attribute is used to decorate tests that run on an implementation of the FVM (i.e.
/// taking vm_api::VM as an argument). Decorated tests are added to the global TEST_REGISTRY which
/// is exported for use in other environments.
/// TEST_REGISTRY acts as a single entry point for external crates/tooling to discover the suite of
/// builtin-actors' integration tests.
/// Test speed is an optional argument to the macro which must be a u8. Speed defaults to 0 indicating
/// a fast test, with value increasing for slower tests.
#[proc_macro_attribute]
pub fn vm_test(attr: TokenStream, item: TokenStream) -> TokenStream {
// Try to parse the u8 argument
let literal_arg: Result<syn::Lit, _> = syn::parse(attr.clone());

// Determine the test speed based on the provided argument
let test_category = if attr.is_empty() {
0 // Default if not provided
} else {
match literal_arg {
Ok(syn::Lit::Int(lit_int)) => {
// Attempt to parse the integer
match lit_int.base10_parse::<u8>() {
Ok(val) => val,
Err(_) => panic!("Test speed value is too large. Please use a u8."),
}
}
_ => panic!("Invalid argument for test speed. Please provide a u8 value."),
}
};

let input_fn = syn::parse_macro_input!(item as syn::ItemFn);
let fn_name = &input_fn.sig.ident;

// Generate a unique identifier for the registration function (unique within the module)
let register_fn_name = format_ident!("register_{}", fn_name);

let registry_code = quote! {
#input_fn
#[ctor::ctor]
fn #register_fn_name() {
// Registry key needs to be globally unique so we include module name
let registry_key = concat!(module_path!(), "::", stringify!(#fn_name));
crate::TEST_REGISTRY.lock().unwrap().insert(registry_key.to_string(), (#test_category, #fn_name));
}
};

registry_code.into()
}
16 changes: 16 additions & 0 deletions integration_tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ use fvm_shared::{
smooth::FilterEstimate,
ActorID,
};
use lazy_static::lazy_static;
use std::collections::BTreeMap;
use std::sync::Mutex;
use vm_api::VM;

pub mod deals;
pub mod expects;
Expand Down Expand Up @@ -56,3 +60,15 @@ pub struct NetworkStats {
pub total_provider_locked_collateral: TokenAmount,
pub total_client_storage_fee: TokenAmount,
}

pub type TestFn = fn(&dyn VM) -> ();

lazy_static! {
/// Integration tests that are marked for inclusion by the vm_test macro are inserted here
/// The tests are keyed by their fully qualified name (module_path::test_name)
/// The registry entries are a tuple (u8, TestFn). The u8 represents test speed defaulting to 0 for
/// relatively fast tests and increasing in value for slower-executing tests. It can be used by different
/// execution environments to determine/filter if a test is suitable for running (e.g. some tests
/// may be infeasibly slow to run on a real FVM implementation).
pub static ref TEST_REGISTRY: Mutex<BTreeMap<String, (u8, TestFn)>> = Mutex::new(BTreeMap::new());
}
2 changes: 2 additions & 0 deletions integration_tests/src/tests/authenticate_message_test.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use export_macro::vm_test;
use fil_actor_account::types::AuthenticateMessageParams;
use fil_actor_account::Method::AuthenticateMessageExported;
use fvm_ipld_encoding::RawBytes;
Expand All @@ -12,6 +13,7 @@ use vm_api::VM;
/// Using a deal proposal as a serialized message, we confirm that:
/// - calls to Account::authenticate_message with valid signatures succeed
/// - calls to Account::authenticate_message with invalid signatures fail
#[vm_test]
pub fn account_authenticate_message_test(v: &dyn VM) {
let addr = create_accounts(v, 1, &TokenAmount::from_whole(10_000))[0];

Expand Down
11 changes: 11 additions & 0 deletions integration_tests/src/tests/batch_onboarding.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use export_macro::vm_test;
use fil_actor_cron::Method as CronMethod;
use fil_actor_miner::SectorPreCommitOnChainInfo;
use fil_actor_miner::{power_for_sector, State as MinerState};
Expand Down Expand Up @@ -164,3 +165,13 @@ pub fn batch_onboarding_test(v: &dyn VM, v2: bool) {
&[invariant_failure_patterns::REWARD_STATE_EPOCH_MISMATCH.to_owned()],
);
}

#[vm_test]
pub fn batch_onboarding_deals_test_v2(v: &dyn VM) {
batch_onboarding_test(v, true);
}

#[vm_test]
pub fn batch_onboarding_deals_test_v1(v: &dyn VM) {
batch_onboarding_test(v, false);
}
2 changes: 2 additions & 0 deletions integration_tests/src/tests/batch_onboarding_deals_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use fvm_shared::piece::{PaddedPieceSize, PieceInfo};
use fvm_shared::sector::{RegisteredSealProof, StoragePower};
use num_traits::Zero;

use export_macro::vm_test;
use vm_api::util::{apply_ok, get_state, DynBlockstore};
use vm_api::VM;

Expand All @@ -31,6 +32,7 @@ const PRECOMMIT_V2: bool = true;
const SEAL_PROOF: RegisteredSealProof = RegisteredSealProof::StackedDRG32GiBV1P1;

// Tests batch onboarding of sectors with verified deals.
#[vm_test(1)]
pub fn batch_onboarding_deals_test(v: &dyn VM) {
let deal_duration: ChainEpoch = Policy::default().min_sector_expiration;
let sector_duration: ChainEpoch =
Expand Down
Loading

0 comments on commit 1e50065

Please sign in to comment.