diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000000..30558265a3 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[alias] +generate-test-db = "run --manifest-path ./xtask/generate-test-db/Cargo.toml --" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5e7fe51af..1e592376fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,8 @@ jobs: name: dojo-bins path: /tmp/bins - run: | + tar -xzf spawn-and-move-db.tar.gz -C /tmp/ + tar -xzf types-test-db.tar.gz -C /tmp/ chmod +x /tmp/bins/katana KATANA_RUNNER_BIN=/tmp/bins/katana cargo llvm-cov nextest --no-report --all-features --workspace --exclude katana --build-jobs 20 cargo llvm-cov nextest --no-report -p katana diff --git a/.gitignore b/.gitignore index 09a5b8fd5f..a789cfea6e 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ crates/benches/bench_results.txt .vscode bindings justfile +spawn-and-move-db +types-test-db diff --git a/Cargo.lock b/Cargo.lock index fe58f736fe..596d6f0e78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12865,6 +12865,7 @@ dependencies = [ "num-bigint", "num-integer", "prettytable-rs", + "regex", "reqwest 0.12.5", "rpassword", "scarb", @@ -16217,6 +16218,18 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852" +[[package]] +name = "xtask-generate-test-db" +version = "1.0.0-alpha.4" +dependencies = [ + "dojo-test-utils", + "dojo-world", + "katana-runner", + "scarb", + "sozo-ops", + "tokio", +] + [[package]] name = "xxhash-rust" version = "0.8.11" diff --git a/Cargo.toml b/Cargo.toml index e98f4df435..14d19b2013 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ members = [ "crates/torii/server", "crates/torii/types-test", "examples/spawn-and-move", + "xtask/generate-test-db", ] [workspace.package] diff --git a/bin/sozo/Cargo.toml b/bin/sozo/Cargo.toml index c7a5b018e4..c742c862df 100644 --- a/bin/sozo/Cargo.toml +++ b/bin/sozo/Cargo.toml @@ -41,6 +41,7 @@ notify = "6.0.1" num-bigint = "0.4.3" num-integer = "0.1.45" prettytable-rs = "0.10.0" +regex.workspace = true rpassword.workspace = true scarb-ui.workspace = true scarb.workspace = true diff --git a/bin/sozo/src/commands/clean.rs b/bin/sozo/src/commands/clean.rs index 5bf8ea47a6..c793380dad 100644 --- a/bin/sozo/src/commands/clean.rs +++ b/bin/sozo/src/commands/clean.rs @@ -105,6 +105,8 @@ mod tests { let temp_project_dir = config.manifest_path().parent().unwrap().to_path_buf(); + println!("temp_project_dir: {:?}", temp_project_dir); + let clean_cmd = CleanArgs { full: false, all_profiles: false }; clean_cmd.run(&config).unwrap(); @@ -143,7 +145,7 @@ mod tests { ); assert!( fs::read_dir(&dev_manifests_abis_depl_dir).is_ok(), - "Expected 'manifests/dev/deployment/abis' to not be empty" + "Expected 'manifests/dev/deployment/abis' to be non empty" ); // we expect release profile to be not affected @@ -214,7 +216,7 @@ mod tests { ); assert!( fs::read_dir(&dev_manifests_abis_depl_dir).is_ok(), - "Expected 'manifests/dev/deployment/abis' to not be empty" + "Expected 'manifests/dev/deployment/abis' to be empty" ); assert!( diff --git a/bin/sozo/tests/register_test.rs b/bin/sozo/tests/register_test.rs index b882b873c9..4a5c234848 100644 --- a/bin/sozo/tests/register_test.rs +++ b/bin/sozo/tests/register_test.rs @@ -1,13 +1,11 @@ mod utils; +use camino::Utf8PathBuf; use dojo_test_utils::compiler::CompilerTestSetup; -use dojo_test_utils::migration::prepare_migration; -use dojo_world::metadata::{dojo_metadata_from_workspace, get_default_namespace_from_ws}; -use dojo_world::migration::TxnConfig; -use katana_runner::KatanaRunner; +use dojo_test_utils::migration::{copy_spawn_and_move_db, prepare_migration_with_world_and_seed}; +use katana_runner::{KatanaRunner, KatanaRunnerConfig}; use scarb::compiler::Profile; use scarb::ops; -use sozo_ops::migration::execute_strategy; use starknet::accounts::Account; use starknet::core::types::{BlockId, BlockTag}; use utils::snapbox::get_snapbox; @@ -19,36 +17,33 @@ async fn reregister_models() { let ws = ops::read_workspace(config.manifest_path(), &config) .unwrap_or_else(|op| panic!("Error building workspace: {op:?}")); - let dojo_metadata = - dojo_metadata_from_workspace(&ws).expect("No current package with dojo metadata found."); + let manifest_path = Utf8PathBuf::from(config.manifest_path().parent().unwrap()); let target_path = ws.target_dir().path_existent().unwrap().join(ws.config().profile().to_string()); - let default_namespace = get_default_namespace_from_ws(&ws).unwrap(); + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Failed to start runner."); - let migration = prepare_migration( - config.manifest_path().parent().unwrap().into(), + let (strat, _) = prepare_migration_with_world_and_seed( + manifest_path, target_path, - dojo_metadata.skip_migration, - &default_namespace, + None, + "dojo_examples", + "dojo_examples", ) .unwrap(); - let sequencer = KatanaRunner::new().expect("Failed to start runner."); - let mut account = sequencer.account(0); account.set_block_id(BlockId::Tag(BlockTag::Pending)); - execute_strategy(&ws, &migration, &account, TxnConfig::init_wait()).await.unwrap(); - let world_address = &format!("0x{:x}", &migration.world_address); + let world_address = &format!("0x{:x}", &strat.world_address); let account_address = &format!("0x{:x}", account.address()); let private_key = &format!("0x{:x}", sequencer.account_data(0).private_key.as_ref().unwrap().secret_scalar()); let rpc_url = &sequencer.url().to_string(); - let moves_model = - migration.models.iter().find(|m| m.diff.tag == "dojo_examples-Moves").unwrap(); + let moves_model = strat.models.iter().find(|m| m.diff.tag == "dojo_examples-Moves").unwrap(); let moves_model_class_hash = &format!("0x{:x}", moves_model.diff.local_class_hash); let args_vec = [ "register", diff --git a/bin/sozo/tests/test_migrate.rs b/bin/sozo/tests/test_migrate.rs index c8683758a0..b1f672b929 100644 --- a/bin/sozo/tests/test_migrate.rs +++ b/bin/sozo/tests/test_migrate.rs @@ -1,7 +1,8 @@ use std::fs; use dojo_test_utils::compiler::CompilerTestSetup; -use katana_runner::KatanaRunner; +use dojo_test_utils::migration::copy_spawn_and_move_db; +use katana_runner::{KatanaRunner, KatanaRunnerConfig}; use scarb::compiler::Profile; use starknet::accounts::Account; use starknet::core::types::{BlockId, BlockTag}; @@ -55,33 +56,14 @@ async fn test_migrate_then_upgrade() { let config = setup.build_test_config("spawn-and-move", Profile::DEV); let tmp_dir = config.manifest_path().parent().unwrap(); - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Failed to start runner."); let mut account = sequencer.account(0); account.set_block_id(BlockId::Tag(BlockTag::Pending)); - let account_address = &format!("0x{:x}", account.address()); - let private_key = - &format!("0x{:x}", sequencer.account_data(0).private_key.as_ref().unwrap().secret_scalar()); let rpc_url = &sequencer.url().to_string(); - let args_vec = [ - "migrate", - "apply", - "--account-address", - account_address, - "--rpc-url", - rpc_url, - "--private-key", - private_key, - "--manifest-path", - config.manifest_path().as_ref(), - ]; - - get_snapbox().args(args_vec.iter()).assert().success(); - - println!("tmp_dir: {:?}", tmp_dir); - // Modify the actions contracts to have a new class hash. let actions_path = tmp_dir.join("src/actions.cairo"); let mut actions_content = fs::read_to_string(&actions_path).unwrap(); @@ -92,8 +74,17 @@ async fn test_migrate_then_upgrade() { get_snapbox().args(build_vec.iter()).assert().success(); - let assert = get_snapbox().args(args_vec.iter()).assert().success(); - let output = format!("{:#?}", assert.get_output()); + let plan_args = [ + "migrate", + "plan", + "--rpc-url", + rpc_url, + "--manifest-path", + config.manifest_path().as_ref(), + ]; + + let plan_assert = get_snapbox().args(plan_args.iter()).assert().success(); + let plan_output = format!("{:#?}", plan_assert.get_output()); - assert!(output.contains("Contracts (1)")); + assert!(plan_output.contains("Contracts (1)")); } diff --git a/crates/dojo-test-utils/src/compiler.rs b/crates/dojo-test-utils/src/compiler.rs index c91d44fb13..6fe6340e2f 100644 --- a/crates/dojo-test-utils/src/compiler.rs +++ b/crates/dojo-test-utils/src/compiler.rs @@ -68,6 +68,41 @@ impl CompilerTestSetup { } } +/// Copies a directory into a temporary directory. +/// +/// # Returns +/// +/// A [`Utf8PathBuf`] object pointing to the copied directory. +pub fn copy_tmp_dir(source_dir: &Utf8PathBuf) -> Utf8PathBuf { + let temp_project_dir = Utf8PathBuf::from( + assert_fs::TempDir::new().unwrap().to_path_buf().to_string_lossy().to_string(), + ); + + fn copy_dir_recursively(src: &PathBuf, dst: &PathBuf) -> io::Result<()> { + if src.is_dir() { + fs::create_dir_all(dst)?; + for entry in fs::read_dir(src)? { + let entry = entry?; + let path = entry.path(); + let dst_path = dst.join(path.file_name().unwrap()); + if path.is_dir() { + copy_dir_recursively(&path, &dst_path)?; + } else { + fs::copy(&path, &dst_path)?; + } + } + } else { + fs::copy(src, dst)?; + } + Ok(()) + } + + copy_dir_recursively(&source_dir.to_path_buf().into(), &temp_project_dir.to_path_buf().into()) + .unwrap_or_else(|e| panic!("Failed to copy directory: {}", e)); + + temp_project_dir +} + /// Copies a project into a temporary directory and loads a config from the copied project. /// /// # Returns diff --git a/crates/dojo-test-utils/src/migration.rs b/crates/dojo-test-utils/src/migration.rs index 37c9a8e550..2578e762a8 100644 --- a/crates/dojo-test-utils/src/migration.rs +++ b/crates/dojo-test-utils/src/migration.rs @@ -7,6 +7,21 @@ use starknet::core::types::Felt; use starknet::core::utils::cairo_short_string_to_felt; use starknet::macros::felt; +pub const SPAWN_AND_MOVE_TEST_DB_DIR: &str = "/tmp/spawn-and-move-db"; +pub const TYPES_TEST_DB_DIR: &str = "/tmp/types-test-db"; + +/// Copies the spawn and move test database to a temporary directory and returns the path to the +/// temporary directory. Must be used if the test is going to modify the database. +pub fn copy_spawn_and_move_db() -> Utf8PathBuf { + crate::compiler::copy_tmp_dir(&Utf8PathBuf::from(SPAWN_AND_MOVE_TEST_DB_DIR)) +} + +/// Copies the types test database to a temporary directory and returns the path to the temporary +/// directory. Must be used if the test is going to modify the database. +pub fn copy_types_test_db() -> Utf8PathBuf { + crate::compiler::copy_tmp_dir(&Utf8PathBuf::from(TYPES_TEST_DB_DIR)) +} + pub fn prepare_migration( manifest_dir: Utf8PathBuf, target_dir: Utf8PathBuf, diff --git a/crates/dojo-world/src/contracts/model_test.rs b/crates/dojo-world/src/contracts/model_test.rs index cdaa500878..e5dd5fed8d 100644 --- a/crates/dojo-world/src/contracts/model_test.rs +++ b/crates/dojo-world/src/contracts/model_test.rs @@ -1,20 +1,22 @@ +use camino::Utf8PathBuf; use dojo_test_utils::compiler::CompilerTestSetup; +use dojo_test_utils::migration::{copy_spawn_and_move_db, prepare_migration_with_world_and_seed}; use dojo_types::primitive::Primitive; use dojo_types::schema::{Enum, EnumOption, Member, Struct, Ty}; -use katana_runner::KatanaRunner; +use katana_runner::{KatanaRunner, KatanaRunnerConfig}; use scarb::compiler::Profile; use starknet::accounts::ConnectedAccount; use starknet::macros::felt; use crate::contracts::model::ModelReader; -use crate::contracts::world::test::deploy_world; use crate::contracts::world::WorldContractReader; -use crate::metadata::dojo_metadata_from_workspace; #[tokio::test(flavor = "multi_thread")] async fn test_model() { - let runner = KatanaRunner::new().expect("Fail to set runner"); - let account = runner.account(0); + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Failed to start runner."); + + let account = sequencer.account(0); let provider = account.provider(); let setup = CompilerTestSetup::from_examples("../dojo-core", "../../examples/"); @@ -23,22 +25,16 @@ async fn test_model() { let manifest_dir = config.manifest_path().parent().unwrap(); let target_dir = manifest_dir.join("target").join("dev"); - let ws = scarb::ops::read_workspace(config.manifest_path(), &config).unwrap(); - let dojo_metadata = - dojo_metadata_from_workspace(&ws).expect("No current package with dojo metadata found."); - - let default_namespace = ws.current_package().unwrap().id.name.to_string(); - - let world_address = deploy_world( - &runner, - &manifest_dir.into(), - &target_dir, - dojo_metadata.skip_migration, - &default_namespace, + let (strat, _) = prepare_migration_with_world_and_seed( + Utf8PathBuf::from(&manifest_dir), + Utf8PathBuf::from(&target_dir), + None, + "dojo_examples", + "dojo_examples", ) - .await; + .unwrap(); - let world = WorldContractReader::new(world_address, provider); + let world = WorldContractReader::new(strat.world_address, provider); let position = world.model_reader("dojo_examples", "Position").await.unwrap(); let schema = position.schema().await.unwrap(); diff --git a/crates/dojo-world/src/contracts/world_test.rs b/crates/dojo-world/src/contracts/world_test.rs index 16e0955b13..229746717f 100644 --- a/crates/dojo-world/src/contracts/world_test.rs +++ b/crates/dojo-world/src/contracts/world_test.rs @@ -1,151 +1,36 @@ -use std::time::Duration; - -use camino::Utf8PathBuf; use dojo_test_utils::compiler::CompilerTestSetup; -use katana_runner::KatanaRunner; +use dojo_test_utils::migration::{copy_spawn_and_move_db, prepare_migration_with_world_and_seed}; +use katana_runner::{KatanaRunner, KatanaRunnerConfig}; use scarb::compiler::Profile; -use starknet::accounts::{Account, ConnectedAccount}; -use starknet::core::types::{BlockId, BlockTag, Felt}; +use starknet::accounts::ConnectedAccount; +use starknet::core::types::{BlockId, BlockTag}; -use super::{WorldContract, WorldContractReader}; -use crate::manifest::{BaseManifest, OverlayManifest, BASE_DIR, MANIFESTS_DIR, OVERLAYS_DIR}; -use crate::metadata::dojo_metadata_from_workspace; -use crate::migration::strategy::prepare_for_migration; -use crate::migration::world::WorldDiff; -use crate::migration::{Declarable, Deployable, TxnConfig}; -use crate::utils::TransactionExt; +use super::WorldContractReader; #[tokio::test(flavor = "multi_thread")] async fn test_world_contract_reader() { - let runner = KatanaRunner::new().expect("Fail to set runner"); - let setup = CompilerTestSetup::from_examples("../dojo-core", "../../examples/"); let config = setup.build_test_config("spawn-and-move", Profile::DEV); - let ws = scarb::ops::read_workspace(config.manifest_path(), &config).unwrap(); - - let default_namespace = ws.current_package().unwrap().id.name.to_string(); - let manifest_dir = config.manifest_path().parent().unwrap(); let target_dir = manifest_dir.join("target").join("dev"); - let mut account = runner.account(0); + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Failed to start runner."); + + let mut account = sequencer.account(0); account.set_block_id(BlockId::Tag(BlockTag::Pending)); let provider = account.provider(); - let ws = scarb::ops::read_workspace(config.manifest_path(), &config).unwrap(); - let dojo_metadata = - dojo_metadata_from_workspace(&ws).expect("No current package with dojo metadata found."); - - let world_address = deploy_world( - &runner, - &manifest_dir.to_path_buf(), - &target_dir.to_path_buf(), - dojo_metadata.skip_migration, - &default_namespace, - ) - .await; - - let _world = WorldContractReader::new(world_address, provider); -} - -pub async fn deploy_world( - sequencer: &KatanaRunner, - manifest_dir: &Utf8PathBuf, - target_dir: &Utf8PathBuf, - skip_migration: Option>, - default_namespace: &str, -) -> Felt { - // Dev profile is used by default for testing: - let profile_name = "dev"; - - let mut manifest = BaseManifest::load_from_path( - &manifest_dir.join(MANIFESTS_DIR).join(profile_name).join(BASE_DIR), + let (strat, _) = prepare_migration_with_world_and_seed( + manifest_dir.to_path_buf(), + target_dir.to_path_buf(), + None, + "dojo_examples", + "dojo_examples", ) .unwrap(); - if let Some(skip_manifests) = skip_migration { - manifest.remove_tags(skip_manifests); - } - - let overlay_dir = manifest_dir.join(OVERLAYS_DIR).join(profile_name); - if overlay_dir.exists() { - let overlay_manifest = OverlayManifest::load_from_path(&overlay_dir, &manifest).unwrap(); - manifest.merge(overlay_manifest); - } - - let world = WorldDiff::compute(manifest.clone(), None, default_namespace).unwrap(); - - let account = sequencer.account(0); - - let strategy = - prepare_for_migration(None, Felt::from_hex("0x12345").unwrap(), target_dir, world).unwrap(); - - let base_class_hash = - strategy.base.unwrap().declare(&account, &TxnConfig::init_wait()).await.unwrap().class_hash; - - let world_address = strategy - .world - .unwrap() - .deploy( - manifest.clone().world.inner.class_hash, - vec![base_class_hash], - &account, - &TxnConfig::init_wait(), - ) - .await - .unwrap() - .contract_address; - - let mut declare_output = vec![]; - for model in strategy.models { - let res = model.declare(&account, &TxnConfig::init_wait()).await.unwrap(); - declare_output.push(res); - } - - let world = WorldContract::new(world_address, &account); - - let calls = vec![ - world.register_namespace_getcall( - &cainome::cairo_serde::ByteArray::from_string("dojo_examples").unwrap(), - ), - world.register_namespace_getcall( - &cainome::cairo_serde::ByteArray::from_string("dojo_examples_foes").unwrap(), - ), - world.register_namespace_getcall( - &cainome::cairo_serde::ByteArray::from_string("dojo_examples_weapons").unwrap(), - ), - ]; - - let _ = account.execute_v1(calls).send_with_cfg(&TxnConfig::init_wait()).await.unwrap(); - - // Wondering why the `init_wait` is not enough and causes a nonce error. - // May be to a delay to create the block as we are in instant mining. - tokio::time::sleep(Duration::from_millis(2000)).await; - - let calls = declare_output - .iter() - .map(|o| world.register_model_getcall(&o.class_hash.into())) - .collect::>(); - - let _ = account.execute_v1(calls).send_with_cfg(&TxnConfig::init_wait()).await.unwrap(); - - for contract in strategy.contracts { - let declare_res = contract.declare(&account, &TxnConfig::default()).await.unwrap(); - contract - .deploy_dojo_contract( - world_address, - declare_res.class_hash, - base_class_hash, - &account, - &TxnConfig::init_wait(), - &contract.diff.init_calldata, - &contract.diff.tag, - ) - .await - .unwrap(); - } - - world_address + let _world = WorldContractReader::new(strat.world_address, provider); } diff --git a/crates/dojo-world/src/manifest/manifest_test.rs b/crates/dojo-world/src/manifest/manifest_test.rs index fea5baabc7..cf6a126ec8 100644 --- a/crates/dojo-world/src/manifest/manifest_test.rs +++ b/crates/dojo-world/src/manifest/manifest_test.rs @@ -3,8 +3,9 @@ use std::io::Write; use cainome::cairo_serde::{ByteArray, CairoSerde}; use camino::Utf8PathBuf; use dojo_test_utils::compiler::CompilerTestSetup; +use dojo_test_utils::migration::{copy_spawn_and_move_db, prepare_migration_with_world_and_seed}; use dojo_test_utils::rpc::MockJsonRpcTransport; -use katana_runner::KatanaRunner; +use katana_runner::{KatanaRunner, KatanaRunnerConfig}; use scarb::compiler::Profile; use serde_json::json; use starknet::accounts::ConnectedAccount; @@ -18,7 +19,6 @@ use super::{ OverlayManifest, }; use crate::contracts::naming::{get_filename_from_tag, get_tag}; -use crate::contracts::world::test::deploy_world; use crate::manifest::{ parse_models_events, AbstractManifestError, DeploymentManifest, Manifest, OverlayClass, OverlayDojoModel, BASE_DIR, MANIFESTS_DIR, OVERLAYS_DIR, @@ -299,9 +299,10 @@ fn events_without_block_number_arent_parsed() { #[test] fn fetch_remote_manifest() { - let runner = KatanaRunner::new().expect("Fail to set runner"); + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Failed to start runner."); - let account = runner.account(0); + let account = sequencer.account(0); let provider = account.provider(); let setup = CompilerTestSetup::from_examples("../dojo-core", "../../examples/"); @@ -309,27 +310,22 @@ fn fetch_remote_manifest() { let profile_name = Profile::DEV.to_string(); let ws = scarb::ops::read_workspace(config.manifest_path(), &config).unwrap(); + let manifest_path = Utf8PathBuf::from(config.manifest_path().parent().unwrap()); + let target_dir = Utf8PathBuf::from(ws.target_dir().to_string()).join("dev"); let dojo_metadata = dojo_metadata_from_workspace(&ws).expect("No current package with dojo metadata found."); - let temp_project_dir = config.manifest_path().parent().unwrap(); - let artifacts_path = temp_project_dir.join(format!("target/{profile_name}")); - - let default_namespace = ws.current_package().unwrap().id.name.to_string(); - - let world_address = config.tokio_handle().block_on(async { - deploy_world( - &runner, - &temp_project_dir.to_path_buf(), - &artifacts_path.to_path_buf(), - dojo_metadata.skip_migration.clone(), - &default_namespace, - ) - .await - }); + let (strat, _) = prepare_migration_with_world_and_seed( + manifest_path.clone(), + target_dir, + None, + "dojo_examples", + "dojo_examples", + ) + .unwrap(); let mut local_manifest = BaseManifest::load_from_path( - &temp_project_dir.join(MANIFESTS_DIR).join(&profile_name).join(BASE_DIR), + &manifest_path.join(MANIFESTS_DIR).join(&profile_name).join(BASE_DIR), ) .unwrap(); @@ -337,7 +333,7 @@ fn fetch_remote_manifest() { local_manifest.remove_tags(skip_manifests); } - let overlay_dir = temp_project_dir.join(OVERLAYS_DIR).join(&profile_name); + let overlay_dir = manifest_path.join(OVERLAYS_DIR).join(&profile_name); if overlay_dir.exists() { let overlay_manifest = OverlayManifest::load_from_path(&overlay_dir, &local_manifest).unwrap(); @@ -346,7 +342,7 @@ fn fetch_remote_manifest() { } let remote_manifest = config.tokio_handle().block_on(async { - DeploymentManifest::load_from_remote(provider, world_address).await.unwrap() + DeploymentManifest::load_from_remote(provider, strat.world_address).await.unwrap() }); assert_eq!(local_manifest.models.len(), 10); diff --git a/crates/katana/runner/src/lib.rs b/crates/katana/runner/src/lib.rs index 2e09aa6b77..0cba8572c0 100644 --- a/crates/katana/runner/src/lib.rs +++ b/crates/katana/runner/src/lib.rs @@ -45,6 +45,8 @@ pub struct KatanaRunnerConfig { pub log_path: Option, /// The messaging config file pub messaging: Option, + /// The path to the database dir. + pub db_dir: Option, } impl Default for KatanaRunnerConfig { @@ -58,10 +60,18 @@ impl Default for KatanaRunnerConfig { run_name: None, log_path: None, messaging: None, + db_dir: None, } } } +impl KatanaRunnerConfig { + pub fn with_db_dir(mut self, db_dir: &str) -> Self { + self.db_dir = Some(PathBuf::from(db_dir)); + self + } +} + impl KatanaRunner { /// Creates a new KatanaRunner with default values. pub fn new() -> Result { @@ -99,6 +109,10 @@ impl KatanaRunner { builder = builder.messaging(messaging_file); } + if let Some(path) = config.db_dir { + builder = builder.db_dir(path); + } + let mut katana = builder.spawn(); let stdout = diff --git a/crates/sozo/ops/src/test_utils/setup.rs b/crates/sozo/ops/src/test_utils/setup.rs index 7018cb47ec..eac994e824 100644 --- a/crates/sozo/ops/src/test_utils/setup.rs +++ b/crates/sozo/ops/src/test_utils/setup.rs @@ -50,7 +50,7 @@ pub fn setup_ws(config: &Config) -> Workspace<'_> { /// # Returns /// /// A [`MigrationStrategy`] to execute to migrate the full spawn-and-moves project. -pub fn setup_migration(config: &Config) -> Result<(MigrationStrategy, WorldDiff)> { +pub fn setup_migration(config: &Config, seed: &str) -> Result<(MigrationStrategy, WorldDiff)> { let ws = setup_ws(config); let manifest_path = config.manifest_path(); @@ -63,7 +63,7 @@ pub fn setup_migration(config: &Config) -> Result<(MigrationStrategy, WorldDiff) base_dir.into(), target_dir.into(), None, - "sozo_test", + seed, &default_namespace, ) } @@ -84,7 +84,7 @@ pub async fn setup( let config = load_config(); let ws = setup_ws(&config); - let (migration, _) = setup_migration(&config)?; + let (migration, _) = setup_migration(&config, "dojo_examples")?; let mut account = sequencer.account(0); account.set_block_id(BlockId::Tag(BlockTag::Pending)); @@ -102,3 +102,29 @@ pub async fn setup( Ok(world) } + +/// Setups the project from an runner starting with an existing world. +/// +/// # Arguments +/// +/// * `sequencer` - The sequencer used for tests. +/// +/// # Returns +/// +/// A [`WorldContract`] initialized with the migrator account, +/// the account 0 of the sequencer. +pub async fn setup_with_world( + sequencer: &KatanaRunner, +) -> Result, LocalWallet>>> { + let config = load_config(); + + let (migration, _) = setup_migration(&config, "dojo_examples")?; + + let mut account = sequencer.account(0); + account.set_block_id(BlockId::Tag(BlockTag::Pending)); + + let world = WorldContract::new(migration.world_address, account) + .with_block(BlockId::Tag(BlockTag::Pending)); + + Ok(world) +} diff --git a/crates/sozo/ops/src/tests/auth.rs b/crates/sozo/ops/src/tests/auth.rs index 195a0ec0ed..c2399d324d 100644 --- a/crates/sozo/ops/src/tests/auth.rs +++ b/crates/sozo/ops/src/tests/auth.rs @@ -1,8 +1,9 @@ use std::str::FromStr; +use dojo_test_utils::migration::copy_spawn_and_move_db; use dojo_world::contracts::world::WorldContract; use dojo_world::migration::TxnConfig; -use katana_runner::KatanaRunner; +use katana_runner::{KatanaRunner, KatanaRunnerConfig}; use scarb_ui::{OutputFormat, Ui, Verbosity}; use starknet::accounts::{Account, ConnectedAccount}; use starknet::core::types::{BlockId, BlockTag}; @@ -16,9 +17,10 @@ const DEFAULT_NAMESPACE: &str = "dojo_examples"; #[tokio::test(flavor = "multi_thread")] async fn auth_grant_writer_ok() { - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(config).expect("Failed to start runner."); - let world = setup::setup(&sequencer).await.unwrap(); + let world = setup::setup_with_world(&sequencer).await.unwrap(); // Shouldn't have any permission at this point. let account2 = sequencer.account(1); @@ -56,9 +58,10 @@ async fn auth_grant_writer_ok() { #[tokio::test(flavor = "multi_thread")] async fn auth_revoke_writer_ok() { - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(config).expect("Failed to start runner."); - let world = setup::setup(&sequencer).await.unwrap(); + let world = setup::setup_with_world(&sequencer).await.unwrap(); // Shouldn't have any permission at this point. let account2 = sequencer.account(1); @@ -113,9 +116,10 @@ async fn auth_revoke_writer_ok() { #[tokio::test(flavor = "multi_thread")] async fn auth_grant_owner_ok() { - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(config).expect("Failed to start runner."); - let world = setup::setup(&sequencer).await.unwrap(); + let world = setup::setup_with_world(&sequencer).await.unwrap(); // Shouldn't have any permission at this point. let account_2 = sequencer.account(1); @@ -153,9 +157,10 @@ async fn auth_grant_owner_ok() { #[tokio::test(flavor = "multi_thread")] async fn auth_revoke_owner_ok() { - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(config).expect("Failed to start runner."); - let world = setup::setup(&sequencer).await.unwrap(); + let world = setup::setup_with_world(&sequencer).await.unwrap(); // Shouldn't have any permission at this point. let account_2 = sequencer.account(1); @@ -223,7 +228,5 @@ async fn execute_spawn( ) .await; - println!("ERR {:?}", r); - r.is_ok() } diff --git a/crates/sozo/ops/src/tests/call.rs b/crates/sozo/ops/src/tests/call.rs index d5a58e4b1a..addb2b4e96 100644 --- a/crates/sozo/ops/src/tests/call.rs +++ b/crates/sozo/ops/src/tests/call.rs @@ -1,5 +1,5 @@ use dojo_world::contracts::WorldContractReader; -use katana_runner::KatanaRunner; +use katana_runner::{KatanaRunner, KatanaRunnerConfig}; use starknet::accounts::SingleOwnerAccount; use starknet::core::types::Felt; use starknet::providers::jsonrpc::HttpTransport; @@ -12,14 +12,12 @@ use crate::{call, utils}; const CONTRACT_TAG: &str = "dojo_examples-actions"; const ENTRYPOINT: &str = "get_player_position"; -// TODO: we should work on a lazy static init for the runner for all the call tests, -// as the state will not change, we only read and check the result. - #[tokio::test] async fn call_with_bad_address() { - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let config = KatanaRunnerConfig::default().with_db_dir("/tmp/spawn-and-move-db"); + let sequencer = KatanaRunner::new_with_config(config).expect("Failed to start runner."); - let world = setup::setup(&sequencer).await.unwrap(); + let world = setup::setup_with_world(&sequencer).await.unwrap(); let provider = sequencer.provider(); let world_reader = WorldContractReader::new(world.address, provider); @@ -38,9 +36,10 @@ async fn call_with_bad_address() { #[tokio::test] async fn call_with_bad_name() { - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let config = KatanaRunnerConfig::default().with_db_dir("/tmp/spawn-and-move-db"); + let sequencer = KatanaRunner::new_with_config(config).expect("Failed to start runner."); - let world = setup::setup(&sequencer).await.unwrap(); + let world = setup::setup_with_world(&sequencer).await.unwrap(); let provider = sequencer.provider(); let world_reader = WorldContractReader::new(world.address, provider); @@ -59,9 +58,10 @@ async fn call_with_bad_name() { #[tokio::test] async fn call_with_bad_entrypoint() { - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let config = KatanaRunnerConfig::default().with_db_dir("/tmp/spawn-and-move-db"); + let sequencer = KatanaRunner::new_with_config(config).expect("Failed to start runner."); - let world = setup::setup(&sequencer).await.unwrap(); + let world = setup::setup_with_world(&sequencer).await.unwrap(); let provider = sequencer.provider(); let world_reader = WorldContractReader::new(world.address, provider); @@ -80,9 +80,10 @@ async fn call_with_bad_entrypoint() { #[tokio::test] async fn call_with_bad_calldata() { - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let config = KatanaRunnerConfig::default().with_db_dir("/tmp/spawn-and-move-db"); + let sequencer = KatanaRunner::new_with_config(config).expect("Failed to start runner."); - let world = setup::setup(&sequencer).await.unwrap(); + let world = setup::setup_with_world(&sequencer).await.unwrap(); let provider = sequencer.provider(); let world_reader = WorldContractReader::new(world.address, provider); @@ -101,9 +102,10 @@ async fn call_with_bad_calldata() { #[tokio::test] async fn call_with_contract_name() { - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let config = KatanaRunnerConfig::default().with_db_dir("/tmp/spawn-and-move-db"); + let sequencer = KatanaRunner::new_with_config(config).expect("Failed to start runner."); - let world = setup::setup(&sequencer).await.unwrap(); + let world = setup::setup_with_world(&sequencer).await.unwrap(); let provider = sequencer.provider(); let world_reader = WorldContractReader::new(world.address, provider); @@ -116,9 +118,10 @@ async fn call_with_contract_name() { #[tokio::test] async fn call_with_contract_address() { - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let config = KatanaRunnerConfig::default().with_db_dir("/tmp/spawn-and-move-db"); + let sequencer = KatanaRunner::new_with_config(config).expect("Failed to start runner."); - let world = setup::setup(&sequencer).await.unwrap(); + let world = setup::setup_with_world(&sequencer).await.unwrap(); let provider = sequencer.provider(); let world_reader = WorldContractReader::new(world.address, provider); diff --git a/crates/sozo/ops/src/tests/migration.rs b/crates/sozo/ops/src/tests/migration.rs index 8099f9db2c..91e565245c 100644 --- a/crates/sozo/ops/src/tests/migration.rs +++ b/crates/sozo/ops/src/tests/migration.rs @@ -3,7 +3,7 @@ use std::str; use cainome::cairo_serde::ContractAddress; use camino::Utf8Path; -use dojo_test_utils::migration::prepare_migration_with_world_and_seed; +use dojo_test_utils::migration::{copy_spawn_and_move_db, prepare_migration_with_world_and_seed}; use dojo_world::contracts::naming::compute_selector_from_tag; use dojo_world::contracts::{WorldContract, WorldContractReader}; use dojo_world::manifest::{ @@ -60,7 +60,7 @@ async fn migrate_with_auto_mine() { let config = setup::load_config(); let ws = setup::setup_ws(&config); - let (migration, _) = setup::setup_migration(&config).unwrap(); + let (migration, _) = setup::setup_migration(&config, "dojo_examples").unwrap(); let sequencer = KatanaRunner::new().expect("Fail to start runner"); @@ -75,7 +75,7 @@ async fn migrate_with_block_time() { let config = setup::load_config(); let ws = setup::setup_ws(&config); - let (migration, _) = setup::setup_migration(&config).unwrap(); + let (migration, _) = setup::setup_migration(&config, "dojo_examples").unwrap(); let sequencer = KatanaRunner::new_with_config(KatanaRunnerConfig { block_time: Some(1000), @@ -95,13 +95,10 @@ async fn migrate_with_small_fee_multiplier_will_fail() { let config = setup::load_config(); let ws = setup::setup_ws(&config); - let (migration, _) = setup::setup_migration(&config).unwrap(); + let (migration, _) = setup::setup_migration(&config, "dojo_examples").unwrap(); - let sequencer = KatanaRunner::new_with_config(KatanaRunnerConfig { - disable_fee: true, - ..Default::default() - }) - .expect("Fail to start runner"); + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Fail to start runner"); let account = sequencer.account(0); @@ -110,7 +107,11 @@ async fn migrate_with_small_fee_multiplier_will_fail() { &ws, &migration, &account, - TxnConfig { fee_estimate_multiplier: Some(0.2f64), ..Default::default() }, + TxnConfig { + fee_estimate_multiplier: Some(0.0000000000000001), + wait: true, + ..Default::default() + }, ) .await .is_err() @@ -277,7 +278,7 @@ async fn migrate_with_metadata() { let config = setup::load_config(); let ws = setup::setup_ws(&config); - let (migration, _) = setup::setup_migration(&config).unwrap(); + let (migration, _) = setup::setup_migration(&config, "dojo_examples").unwrap(); let sequencer = KatanaRunner::new().expect("Fail to start runner"); @@ -350,7 +351,7 @@ async fn migrate_with_auto_authorize() { let config = setup::load_config(); let ws = setup::setup_ws(&config); - let (migration, diff) = setup::setup_migration(&config).unwrap(); + let (migration, diff) = setup::setup_migration(&config, "dojo_examples").unwrap(); let manifest_base = config.manifest_path().parent().unwrap(); let mut manifest = diff --git a/crates/sozo/ops/src/tests/model.rs b/crates/sozo/ops/src/tests/model.rs index e42f5aeda2..f8faf1fcaa 100644 --- a/crates/sozo/ops/src/tests/model.rs +++ b/crates/sozo/ops/src/tests/model.rs @@ -1,7 +1,8 @@ +use dojo_test_utils::migration::copy_spawn_and_move_db; use dojo_world::contracts::abi::model::{FieldLayout, Layout}; use dojo_world::contracts::world::WorldContract; use dojo_world::migration::TxnConfig; -use katana_runner::KatanaRunner; +use katana_runner::{KatanaRunner, KatanaRunnerConfig}; use scarb_ui::{OutputFormat, Ui, Verbosity}; use starknet::accounts::Account; use starknet::core::types::Felt; @@ -13,9 +14,10 @@ use crate::{execute, model}; // migration for now. Should be replaced by individual tests once Katana spinning up is enhanced. #[tokio::test(flavor = "multi_thread")] async fn test_model_ops() { - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Failed to start runner."); - let world = setup::setup(&sequencer).await.unwrap(); + let world = setup::setup_with_world(&sequencer).await.unwrap(); assert_eq!( model::model_class_hash( @@ -37,7 +39,7 @@ async fn test_model_ops() { ) .await .unwrap(), - Felt::from_hex("0x59d2704cd3ce6ea22ae73b0c68e100b80e1f85ac4d4be5cbc66f6f8b9f1c268") + Felt::from_hex("0x6d8df681bb028de94816e8003566009e7742acd9d263fa355e1105aabec16f0") .unwrap() ); diff --git a/crates/sozo/ops/src/tests/utils.rs b/crates/sozo/ops/src/tests/utils.rs index cfea42c3cc..8247ee55a3 100644 --- a/crates/sozo/ops/src/tests/utils.rs +++ b/crates/sozo/ops/src/tests/utils.rs @@ -1,6 +1,7 @@ +use dojo_test_utils::migration::copy_spawn_and_move_db; use dojo_world::contracts::world::WorldContract; use dojo_world::contracts::WorldContractReader; -use katana_runner::KatanaRunner; +use katana_runner::{KatanaRunner, KatanaRunnerConfig}; use starknet::accounts::ConnectedAccount; use starknet::core::types::{BlockId, BlockTag, Felt}; @@ -11,9 +12,10 @@ const ACTION_CONTRACT_TAG: &str = "dojo_examples-actions"; #[tokio::test(flavor = "multi_thread")] async fn get_contract_address_from_world() { - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Failed to start runner."); - let world = setup::setup(&sequencer).await.unwrap(); + let world = setup::setup_with_world(&sequencer).await.unwrap(); let contract_address = utils::get_contract_address(&world, ACTION_CONTRACT_TAG).await.unwrap(); @@ -34,9 +36,10 @@ async fn get_contract_address_from_string() { #[tokio::test(flavor = "multi_thread")] async fn get_contract_address_from_world_with_world_reader() { - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Failed to start runner."); - let world = setup::setup(&sequencer).await.unwrap(); + let world = setup::setup_with_world(&sequencer).await.unwrap(); let account = sequencer.account(0); let provider = account.provider(); let world_reader = WorldContractReader::new(world.address, provider); diff --git a/crates/torii/core/src/sql_test.rs b/crates/torii/core/src/sql_test.rs index 963ba1731f..9ab71443d2 100644 --- a/crates/torii/core/src/sql_test.rs +++ b/crates/torii/core/src/sql_test.rs @@ -1,17 +1,18 @@ use std::str::FromStr; +use camino::Utf8PathBuf; use dojo_test_utils::compiler::CompilerTestSetup; +use dojo_test_utils::migration::{copy_spawn_and_move_db, prepare_migration_with_world_and_seed}; use dojo_world::contracts::naming::compute_selector_from_names; use dojo_world::contracts::world::WorldContractReader; use dojo_world::migration::TxnConfig; use dojo_world::utils::{TransactionExt, TransactionWaiter}; -use katana_runner::KatanaRunner; +use katana_runner::{KatanaRunner, KatanaRunnerConfig}; use scarb::compiler::Profile; -use sozo_ops::migration; use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions}; use starknet::accounts::{Account, Call, ConnectedAccount}; use starknet::core::types::{BlockId, BlockTag, Felt}; -use starknet::core::utils::get_selector_from_name; +use starknet::core::utils::{get_contract_address, get_selector_from_name}; use starknet::providers::Provider; use starknet_crypto::poseidon_hash_many; use tokio::sync::broadcast; @@ -64,35 +65,34 @@ async fn test_load_from_remote() { let config = setup.build_test_config("spawn-and-move", Profile::DEV); let ws = scarb::ops::read_workspace(config.manifest_path(), &config).unwrap(); + let manifest_path = Utf8PathBuf::from(config.manifest_path().parent().unwrap()); + let target_dir = Utf8PathBuf::from(ws.target_dir().to_string()).join("dev"); - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Failed to start runner."); let account = sequencer.account(0); - let migration_output = migration::migrate( - &ws, + let (strat, _) = prepare_migration_with_world_and_seed( + manifest_path, + target_dir, None, - sequencer.url().to_string(), - account, "dojo_examples", - false, - TxnConfig::init_wait(), - None, + "dojo_examples", ) - .await - .unwrap() .unwrap(); - let account = sequencer.account(0); + let actions = strat.contracts.first().unwrap(); + let actions_address = get_contract_address( + actions.salt, + strat.base.as_ref().unwrap().diff.local_class_hash, + &[], + strat.world_address, + ); + // spawn let tx = &account .execute_v1(vec![Call { - to: migration_output - .contracts - .first() - .expect("shouldn't be empty") - .as_ref() - .expect("should be deployed") - .contract_address, + to: actions_address, selector: get_selector_from_name("spawn").unwrap(), calldata: vec![], }]) @@ -102,7 +102,7 @@ async fn test_load_from_remote() { TransactionWaiter::new(tx.transaction_hash, &account.provider()).await.unwrap(); - let world_reader = WorldContractReader::new(migration_output.world_address, account.provider()); + let world_reader = WorldContractReader::new(strat.world_address, account.provider()); let mut db = Sql::new( pool.clone(), @@ -197,35 +197,33 @@ async fn test_load_from_remote_del() { let config = setup.build_test_config("spawn-and-move", Profile::DEV); let ws = scarb::ops::read_workspace(config.manifest_path(), &config).unwrap(); + let manifest_path = Utf8PathBuf::from(config.manifest_path().parent().unwrap()); + let target_dir = Utf8PathBuf::from(ws.target_dir().to_string()).join("dev"); - let sequencer = KatanaRunner::new().expect("Failed to start runner."); + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Failed to start runner."); let account = sequencer.account(0); - let migration_output = migration::migrate( - &ws, + let (strat, _) = prepare_migration_with_world_and_seed( + manifest_path, + target_dir, None, - sequencer.url().to_string(), - account, "dojo_examples", - false, - TxnConfig::init_wait(), - None, + "dojo_examples", ) - .await - .unwrap() .unwrap(); + let actions = strat.contracts.first().unwrap(); + let actions_address = get_contract_address( + actions.salt, + strat.base.as_ref().unwrap().diff.local_class_hash, + &[], + strat.world_address, + ); - let account = sequencer.account(0); // spawn account .execute_v1(vec![Call { - to: migration_output - .contracts - .first() - .expect("shouldn't be empty") - .as_ref() - .expect("should be deployed") - .contract_address, + to: actions_address, selector: get_selector_from_name("spawn").unwrap(), calldata: vec![], }]) @@ -238,13 +236,7 @@ async fn test_load_from_remote_del() { // Set player config. account .execute_v1(vec![Call { - to: migration_output - .contracts - .first() - .expect("shouldn't be empty") - .as_ref() - .expect("should be deployed") - .contract_address, + to: actions_address, selector: get_selector_from_name("set_player_config").unwrap(), // Empty ByteArray. calldata: vec![Felt::ZERO, Felt::ZERO, Felt::ZERO], @@ -257,13 +249,7 @@ async fn test_load_from_remote_del() { account .execute_v1(vec![Call { - to: migration_output - .contracts - .first() - .expect("shouldn't be empty") - .as_ref() - .expect("should be deployed") - .contract_address, + to: actions_address, selector: get_selector_from_name("reset_player_config").unwrap(), calldata: vec![], }]) @@ -273,7 +259,7 @@ async fn test_load_from_remote_del() { tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; - let world_reader = WorldContractReader::new(migration_output.world_address, account.provider()); + let world_reader = WorldContractReader::new(strat.world_address, account.provider()); let mut db = Sql::new( pool.clone(), @@ -310,35 +296,34 @@ async fn test_get_entity_keys() { let config = setup.build_test_config("spawn-and-move", Profile::DEV); let ws = scarb::ops::read_workspace(config.manifest_path(), &config).unwrap(); + let manifest_path = Utf8PathBuf::from(config.manifest_path().parent().unwrap()); + let target_dir = Utf8PathBuf::from(ws.target_dir().to_string()).join("dev"); - let sequencer = KatanaRunner::new().expect("Failed to start runner."); - let account = sequencer.account(0); + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Failed to start runner."); - let migration_output = migration::migrate( - &ws, + let (strat, _) = prepare_migration_with_world_and_seed( + manifest_path, + target_dir, None, - sequencer.url().to_string(), - account, "dojo_examples", - false, - TxnConfig::init_wait(), - None, + "dojo_examples", ) - .await - .unwrap() .unwrap(); + let actions = strat.contracts.first().unwrap(); + let actions_address = get_contract_address( + actions.salt, + strat.base.as_ref().unwrap().diff.local_class_hash, + &[], + strat.world_address, + ); + let account = sequencer.account(0); // spawn account .execute_v1(vec![Call { - to: migration_output - .contracts - .first() - .expect("shouldn't be empty") - .as_ref() - .expect("should be deployed") - .contract_address, + to: actions_address, selector: get_selector_from_name("spawn").unwrap(), calldata: vec![], }]) @@ -348,7 +333,7 @@ async fn test_get_entity_keys() { tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; - let world_reader = WorldContractReader::new(migration_output.world_address, account.provider()); + let world_reader = WorldContractReader::new(strat.world_address, account.provider()); let mut db = Sql::new( pool.clone(), diff --git a/crates/torii/graphql/src/tests/mod.rs b/crates/torii/graphql/src/tests/mod.rs index b2eb69adb8..4b85e36de3 100644 --- a/crates/torii/graphql/src/tests/mod.rs +++ b/crates/torii/graphql/src/tests/mod.rs @@ -2,22 +2,23 @@ use std::str::FromStr; use anyhow::Result; use async_graphql::dynamic::Schema; +use camino::Utf8PathBuf; use dojo_test_utils::compiler::CompilerTestSetup; +use dojo_test_utils::migration::{copy_types_test_db, prepare_migration_with_world_and_seed}; use dojo_types::primitive::Primitive; use dojo_types::schema::{Enum, EnumOption, Member, Struct, Ty}; use dojo_world::contracts::abi::model::Layout; use dojo_world::contracts::WorldContractReader; -use dojo_world::migration::TxnConfig; use dojo_world::utils::TransactionWaiter; -use katana_runner::KatanaRunner; +use katana_runner::{KatanaRunner, KatanaRunnerConfig}; use scarb::compiler::Profile; use serde::Deserialize; use serde_json::Value; -use sozo_ops::migration; use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions}; use sqlx::SqlitePool; use starknet::accounts::{Account, Call, ConnectedAccount}; use starknet::core::types::{Felt, InvokeTransactionResult}; +use starknet::core::utils::get_contract_address; use starknet::macros::selector; use tokio::sync::broadcast; use tokio_stream::StreamExt; @@ -277,38 +278,35 @@ pub async fn spinup_types_test() -> Result { let config = setup.build_test_config("types-test", Profile::DEV); let ws = scarb::ops::read_workspace(config.manifest_path(), &config).unwrap(); + let manifest_path = Utf8PathBuf::from(config.manifest_path().parent().unwrap()); + let target_dir = Utf8PathBuf::from(ws.target_dir().to_string()).join("dev"); + + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_types_test_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Failed to start runner."); - let sequencer = KatanaRunner::new().expect("Failed to start runner."); let account = sequencer.account(0); - let migration_output = migration::migrate( - &ws, + let (strat, _) = prepare_migration_with_world_and_seed( + manifest_path, + target_dir, None, - sequencer.url().to_string(), - account, "types_test", - false, - TxnConfig::init_wait(), - None, + "types_test", ) - .await - .unwrap() .unwrap(); - let account = sequencer.account(0); - // Execute `create` and insert 11 records into storage - let records_contract = migration_output - .contracts - .iter() - .find(|contract| contract.as_ref().unwrap().tag.eq("types_test-records")) - .unwrap(); - - let record_contract_address = records_contract.as_ref().unwrap().contract_address; + let records = strat.contracts.first().unwrap(); + let records_address = get_contract_address( + records.salt, + strat.base.as_ref().unwrap().diff.local_class_hash, + &[], + strat.world_address, + ); let InvokeTransactionResult { transaction_hash } = account .execute_v1(vec![Call { calldata: vec![Felt::from_str("0xa").unwrap()], - to: record_contract_address, + to: records_address, selector: selector!("create"), }]) .send() @@ -321,7 +319,7 @@ pub async fn spinup_types_test() -> Result { let InvokeTransactionResult { transaction_hash } = account .execute_v1(vec![Call { calldata: vec![Felt::from_str("0x14").unwrap()], - to: record_contract_address, + to: records_address, selector: selector!("delete"), }]) .send() @@ -330,9 +328,9 @@ pub async fn spinup_types_test() -> Result { TransactionWaiter::new(transaction_hash, &account.provider()).await?; - let world = WorldContractReader::new(migration_output.world_address, account.provider()); + let world = WorldContractReader::new(strat.world_address, account.provider()); - let db = Sql::new(pool.clone(), migration_output.world_address, Felt::ZERO).await.unwrap(); + let db = Sql::new(pool.clone(), strat.world_address, Felt::ZERO).await.unwrap(); let (shutdown_tx, _) = broadcast::channel(1); let mut engine = Engine::new( diff --git a/crates/torii/grpc/src/server/tests/entities_test.rs b/crates/torii/grpc/src/server/tests/entities_test.rs index 682ac2226f..27ceb5a84a 100644 --- a/crates/torii/grpc/src/server/tests/entities_test.rs +++ b/crates/torii/grpc/src/server/tests/entities_test.rs @@ -1,20 +1,18 @@ use std::str::FromStr; use std::sync::Arc; +use camino::Utf8PathBuf; use dojo_test_utils::compiler::CompilerTestSetup; -use dojo_test_utils::migration::prepare_migration; +use dojo_test_utils::migration::{copy_spawn_and_move_db, prepare_migration_with_world_and_seed}; use dojo_world::contracts::WorldContractReader; -use dojo_world::metadata::{dojo_metadata_from_workspace, get_default_namespace_from_ws}; -use dojo_world::migration::TxnConfig; use dojo_world::utils::TransactionWaiter; -use katana_runner::KatanaRunner; +use katana_runner::{KatanaRunner, KatanaRunnerConfig}; use scarb::compiler::Profile; use scarb::ops; -use sozo_ops::migration::execute_strategy; use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions}; use starknet::accounts::{Account, Call}; use starknet::core::types::{BlockId, BlockTag}; -use starknet::core::utils::get_selector_from_name; +use starknet::core::utils::{get_contract_address, get_selector_from_name}; use starknet::providers::jsonrpc::HttpTransport; use starknet::providers::{JsonRpcClient, Provider}; use starknet_crypto::poseidon_hash_many; @@ -42,46 +40,39 @@ async fn test_entities_queries() { let ws = ops::read_workspace(config.manifest_path(), &config) .unwrap_or_else(|op| panic!("Error building workspace: {op:?}")); - let dojo_metadata = - dojo_metadata_from_workspace(&ws).expect("No current package with dojo metadata found."); + let manifest_path = Utf8PathBuf::from(config.manifest_path().parent().unwrap()); let target_path = ws.target_dir().path_existent().unwrap().join(config.profile().to_string()); - let default_namespace = get_default_namespace_from_ws(&ws).unwrap(); + let seq_config = KatanaRunnerConfig::default().with_db_dir(copy_spawn_and_move_db().as_str()); + let sequencer = KatanaRunner::new_with_config(seq_config).expect("Failed to start runner."); + let account = sequencer.account(0); - let migration = prepare_migration( - config.manifest_path().parent().unwrap().into(), + let (strat, _) = prepare_migration_with_world_and_seed( + manifest_path, target_path, - dojo_metadata.skip_migration, - &default_namespace, + None, + "dojo_examples", + "dojo_examples", ) .unwrap(); - let sequencer = KatanaRunner::new().expect("Fail to start runner"); - let provider = Arc::new(JsonRpcClient::new(HttpTransport::new(sequencer.url()))); - let world = WorldContractReader::new(migration.world_address, &provider); - - let account = sequencer.account(0); - - let migration_output = - execute_strategy(&ws, &migration, &account, TxnConfig::init_wait()).await.unwrap(); + let world = WorldContractReader::new(strat.world_address, &provider); - let world_address = migration_output.world_address; - - println!("output {:?}", migration_output); + let actions = strat.contracts.first().unwrap(); + let actions_address = get_contract_address( + actions.salt, + strat.base.as_ref().unwrap().diff.local_class_hash, + &[], + strat.world_address, + ); // spawn let tx = account .execute_v1(vec![Call { - to: migration_output - .contracts - .first() - .expect("shouldn't be empty") - .as_ref() - .expect("should be deployed") - .contract_address, + to: actions_address, selector: get_selector_from_name("spawn").unwrap(), calldata: vec![], }]) @@ -93,8 +84,11 @@ async fn test_entities_queries() { let db = Sql::new( pool.clone(), - world_address, - provider.get_class_hash_at(BlockId::Tag(BlockTag::Pending), world_address).await.unwrap(), + strat.world_address, + provider + .get_class_hash_at(BlockId::Tag(BlockTag::Pending), strat.world_address) + .await + .unwrap(), ) .await .unwrap(); @@ -116,7 +110,7 @@ async fn test_entities_queries() { let _ = engine.sync_to_head(0, None).await.unwrap(); let (_, receiver) = tokio::sync::mpsc::channel(1); - let grpc = DojoWorld::new(db.pool, receiver, world_address, provider.clone()); + let grpc = DojoWorld::new(db.pool, receiver, strat.world_address, provider.clone()); let entities = grpc .query_by_keys( diff --git a/scripts/rebuild_test_artifacts.sh b/scripts/rebuild_test_artifacts.sh index d52c5938ab..eac1ca2422 100755 --- a/scripts/rebuild_test_artifacts.sh +++ b/scripts/rebuild_test_artifacts.sh @@ -29,5 +29,12 @@ cargo run -r --bin sozo -- build --manifest-path examples/spawn-and-move/Scarb.t cargo run -r --bin sozo -- build --manifest-path crates/torii/types-test/Scarb.toml cargo run -r --bin sozo -- build --manifest-path crates/dojo-lang/src/manifest_test_data/compiler_cairo/Scarb.toml -# Finally, to include all the examples manifest, you should re-deploy the examples. +# Generates the database for testing by migrating the spawn and move example. +cargo generate-test-db +# Ensure the user has locally the db dir in /tmp. +rm -rf /tmp/spawn-and-move-db +rm -rf /tmp/types-test-db +tar xzf spawn-and-move-db.tar.gz -C /tmp/ +tar xzf types-test-db.tar.gz -C /tmp/ + cargo run -r --bin sozo -- --offline migrate apply --manifest-path examples/spawn-and-move/Scarb.toml diff --git a/spawn-and-move-db.tar.gz b/spawn-and-move-db.tar.gz new file mode 100644 index 0000000000..e0c7275370 Binary files /dev/null and b/spawn-and-move-db.tar.gz differ diff --git a/types-test-db.tar.gz b/types-test-db.tar.gz new file mode 100644 index 0000000000..f52c7210b0 Binary files /dev/null and b/types-test-db.tar.gz differ diff --git a/xtask/generate-test-db/Cargo.toml b/xtask/generate-test-db/Cargo.toml new file mode 100644 index 0000000000..3e488e0150 --- /dev/null +++ b/xtask/generate-test-db/Cargo.toml @@ -0,0 +1,14 @@ +[package] +edition.workspace = true +license.workspace = true +name = "xtask-generate-test-db" +repository.workspace = true +version.workspace = true + +[dependencies] +dojo-test-utils.workspace = true +dojo-world = { workspace = true, features = [ "migration" ] } +katana-runner.workspace = true +scarb.workspace = true +sozo-ops = { workspace = true, features = [ "test-utils" ] } +tokio.workspace = true diff --git a/xtask/generate-test-db/src/main.rs b/xtask/generate-test-db/src/main.rs new file mode 100644 index 0000000000..661ca14726 --- /dev/null +++ b/xtask/generate-test-db/src/main.rs @@ -0,0 +1,98 @@ +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use dojo_test_utils::compiler::CompilerTestSetup; +use dojo_world::migration::TxnConfig; +use katana_runner::{KatanaRunner, KatanaRunnerConfig}; +use scarb::compiler::Profile; +use sozo_ops::migration::{self, MigrationOutput}; +use sozo_ops::test_utils; + +type Result = std::result::Result>; + +async fn migrate_spawn_and_move(db_path: &Path) -> Result { + let cfg = KatanaRunnerConfig { db_dir: Some(db_path.to_path_buf()), ..Default::default() }; + let runner = KatanaRunner::new_with_config(cfg)?; + + // migrate the example project + let acc = runner.account(0); + + // setup scarb workspace + let setup = CompilerTestSetup::from_examples("crates/dojo-core", "examples/"); + let cfg = setup.build_test_config("spawn-and-move", Profile::DEV); + let ws = scarb::ops::read_workspace(cfg.manifest_path(), &cfg)?; + + // migrate the example project + let (strat, _) = test_utils::setup::setup_migration(&cfg, "dojo_examples")?; + let output = migration::execute_strategy(&ws, &strat, &acc, TxnConfig::init_wait()).await?; + + Ok(output) +} + +async fn migrate_types_test(db_path: &Path) -> Result { + let cfg = KatanaRunnerConfig { db_dir: Some(db_path.to_path_buf()), ..Default::default() }; + let runner = KatanaRunner::new_with_config(cfg)?; + + // migrate the example project + let acc = runner.account(0); + + // setup scarb workspace + let setup = CompilerTestSetup::from_paths("crates/dojo-core", &["crates/torii/types-test"]); + let cfg = setup.build_test_config("types-test", Profile::DEV); + let ws = scarb::ops::read_workspace(cfg.manifest_path(), &cfg)?; + + // migrate the example project + let (strat, _) = test_utils::setup::setup_migration(&cfg, "types_test")?; + let output = migration::execute_strategy(&ws, &strat, &acc, TxnConfig::init_wait()).await?; + + Ok(output) +} + +#[tokio::main] +async fn main() -> Result<()> { + let spawn_and_move_db_path = PathBuf::from("spawn-and-move-db"); + let types_test_db_path = PathBuf::from("types-test-db"); + + let spawn_and_move_compressed_path = "spawn-and-move-db.tar.gz"; + let types_test_compressed_path = "types-test-db.tar.gz"; + + // Ensures the db-dir is clean before we start to not include old data. + // `let _` is used to ignore the result of the remove_dir_all call as it may fail if the + // directory does not exist. + let _ = fs::remove_dir_all(&spawn_and_move_db_path); + fs::create_dir_all(&spawn_and_move_db_path)?; + let _ = fs::remove_dir_all(&types_test_db_path); + fs::create_dir_all(&types_test_db_path)?; + + let (_, _) = tokio::join!( + migrate_spawn_and_move(&spawn_and_move_db_path), + migrate_types_test(&types_test_db_path) + ); + + // Ensure the test-db directory have been created. + assert!(spawn_and_move_db_path.exists(), "spawn-and-move-db directory does not exist"); + assert!(types_test_db_path.exists(), "types-test-db directory does not exist"); + + compress_db(&spawn_and_move_db_path, spawn_and_move_compressed_path); + compress_db(&types_test_db_path, types_test_compressed_path); + + assert!( + PathBuf::from(spawn_and_move_compressed_path).exists(), + "spawn-and-move-db.tar.gz does not exist" + ); + assert!( + PathBuf::from(types_test_compressed_path).exists(), + "types-test-db.tar.gz does not exist" + ); + + Ok(()) +} + +/// Compresses the given db-path to a .tar.gz file. +fn compress_db(db_path: &Path, compressed_path: &str) { + Command::new("tar") + .args(["-czf", compressed_path, "-C", ".", db_path.to_string_lossy().as_ref()]) + .status() + .expect("Failed to compress test-db directory"); +}