diff --git a/test-utils/runtime-tester/src/fuzzing.rs b/test-utils/runtime-tester/src/fuzzing.rs index 21ad952020e..4454241f6f1 100644 --- a/test-utils/runtime-tester/src/fuzzing.rs +++ b/test-utils/runtime-tester/src/fuzzing.rs @@ -43,7 +43,7 @@ impl Arbitrary<'_> for Scenario { while blocks.len() < MAX_BLOCKS && u.len() > BlockConfig::size_hint(0).0 { blocks.push(BlockConfig::arbitrary(u, &mut scope)?); } - Ok(Scenario { network_config, blocks, use_in_memory_store: true }) + Ok(Scenario { network_config, blocks, use_in_memory_store: true, home_dir: None }) } fn size_hint(_depth: usize) -> (usize, Option) { diff --git a/test-utils/runtime-tester/src/lib.rs b/test-utils/runtime-tester/src/lib.rs index ddd1637f396..63557f0a4c5 100644 --- a/test-utils/runtime-tester/src/lib.rs +++ b/test-utils/runtime-tester/src/lib.rs @@ -27,6 +27,7 @@ fn scenario_smoke_test() { network_config: NetworkConfig { seeds: seeds }, blocks: Vec::new(), use_in_memory_store: true, + home_dir: None, }; for h in 1..5 { diff --git a/test-utils/runtime-tester/src/run_test.rs b/test-utils/runtime-tester/src/run_test.rs index ec66fabb1fa..57d02fef228 100644 --- a/test-utils/runtime-tester/src/run_test.rs +++ b/test-utils/runtime-tester/src/run_test.rs @@ -3,7 +3,7 @@ use std::path::Path; use std::sync::Arc; use std::time::{Duration, Instant}; -use near_chain::{Block, ChainGenesis, Provenance, RuntimeAdapter}; +use near_chain::{Block, ChainGenesis, Provenance}; use near_chain_configs::Genesis; use near_client::test_utils::TestEnv; use near_client_primitives::types::Error; @@ -29,21 +29,25 @@ impl Scenario { ); let tempdir; - let store = if self.use_in_memory_store { - create_test_store() + let home_dir = if self.use_in_memory_store { + Path::new(".") + } else if let Some(home_dir) = &self.home_dir { + home_dir.as_path() } else { tempdir = tempfile::tempdir().map_err(|err| { Error::Other(format!("failed to create temporary directory: {}", err)) })?; - create_store(tempdir.path()) + tempdir.path() + }; + let store = if self.use_in_memory_store { + create_test_store() + } else { + create_store(&nearcore::get_store_path(home_dir)) }; - let mut env = TestEnv::new_with_runtime( - ChainGenesis::from(&genesis), - 1, - 1, - vec![Arc::new(NightshadeRuntime::new( - Path::new("."), + let mut env = TestEnv::builder(ChainGenesis::from(&genesis)) + .runtime_adapters(vec![Arc::new(NightshadeRuntime::new( + home_dir, store, &genesis, vec![], @@ -51,8 +55,8 @@ impl Scenario { None, None, RuntimeConfigStore::test(), - )) as Arc], - ); + ))]) + .build(); let mut last_block = env.clients[0].chain.get_block_by_height(0).unwrap().clone(); @@ -86,6 +90,26 @@ pub struct Scenario { pub network_config: NetworkConfig, pub blocks: Vec, pub use_in_memory_store: bool, + + /// Path to the on-disk home directory; relevant only if + /// `use_in_memory_store` is `false`. + /// + /// If this is `None` (and scenario is configured with an on-disk store) the + /// scenario will be run with a temporary directory as home directory. Once + /// the scenario finishes, that temporary directory is deleted. On the + /// other hand, if this is set it is caller’s responsible to clean the + /// directory *before and after* the test runs. + /// + /// This is useful when wanting to save the storage on-disk and investigate + /// it after the test runs and it’s also why the directory is not cleared. + /// + /// Note that this field is not serialised thus a scenario read from file + /// won’t have this path set. This is motivated partially by security + /// considerations since if this could be stored in JSON file than user + /// might be tricked to run a test against `/home/foo/.near/mainnet` + /// directory. + #[serde(skip_serializing)] + pub home_dir: Option, } #[derive(Serialize, Deserialize)] diff --git a/test-utils/runtime-tester/src/scenario_builder.rs b/test-utils/runtime-tester/src/scenario_builder.rs index 0dbc50ee12b..13ce1f9ad7a 100644 --- a/test-utils/runtime-tester/src/scenario_builder.rs +++ b/test-utils/runtime-tester/src/scenario_builder.rs @@ -51,7 +51,12 @@ impl ScenarioBuilder { ScenarioBuilder { height: 1, nonce: 1, - scenario: Scenario { network_config, blocks: vec![], use_in_memory_store: true }, + scenario: Scenario { + network_config, + blocks: vec![], + use_in_memory_store: true, + home_dir: None, + }, } } @@ -68,6 +73,21 @@ impl ScenarioBuilder { self } + /// Changes `home_dir` to the one specified as well as setting + /// `use_in_memory_store` to `false`. + /// + /// Note that if all you want is to use on-disk store you should call + /// `in_memory_store(false)`. Setting home directory means that the caller + /// is responsible for cleaning the directory before and after the test is + /// run. This setting is intended only for one-off cases where someone + /// wants to manually inspect the store and thus does not want the home + /// directory to be deleted after the test finishes. + pub fn home_dir(mut self, home_dir: impl Into) -> Self { + self.scenario.use_in_memory_store = false; + self.scenario.home_dir = Some(home_dir.into()); + self + } + /// Adds empty block to the scenario with the next height (starting from 1). pub fn add_block(&mut self) { self.scenario.blocks.push(BlockConfig::at_height(self.height));