From a287f53132c91eaa3ba8d5e9c2bec80587316aad Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Tue, 28 Oct 2025 13:19:24 +0000 Subject: test: refactor to use rstest more efficient test runs Identified high value areas to use rstest that would benefit most and refactored them --- Cargo.lock | 97 +++++++++ Cargo.toml | 1 + tests/git_remote_nostr/main.rs | 13 ++ tests/git_remote_nostr/push.rs | 470 ++++++++++++++++------------------------- tests/ngit_init.rs | 360 ++++++++++++++++--------------- 5 files changed, 484 insertions(+), 457 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c257c53..838110b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -747,6 +747,12 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + [[package]] name = "futures-util" version = "0.3.31" @@ -815,6 +821,12 @@ dependencies = [ "url", ] +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + [[package]] name = "gloo-timers" version = "0.3.0" @@ -1455,6 +1467,7 @@ dependencies = [ "passwords", "qrcode", "reqwest", + "rstest", "scrypt", "serde", "serde_json", @@ -1859,6 +1872,15 @@ dependencies = [ "termtree", ] +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro-hack" version = "0.5.20+deprecated" @@ -2034,6 +2056,12 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + [[package]] name = "reqwest" version = "0.12.24" @@ -2100,6 +2128,36 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rstest" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn", + "unicode-ident", +] + [[package]] name = "rustc_version" version = "0.4.1" @@ -2759,6 +2817,36 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + [[package]] name = "tower" version = "0.5.2" @@ -3358,6 +3446,15 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen" version = "0.46.0" diff --git a/Cargo.toml b/Cargo.toml index 6dcbfdb..eb02a7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ zeroize = "1.8.1" assert_cmd = "2.0.17" mockall = "0.13.1" once_cell = "1.21.3" +rstest = "0.23" serial_test = "3.2.0" test_utils = { path = "test_utils" } diff --git a/tests/git_remote_nostr/main.rs b/tests/git_remote_nostr/main.rs index fc541f8..4a17934 100644 --- a/tests/git_remote_nostr/main.rs +++ b/tests/git_remote_nostr/main.rs @@ -13,6 +13,19 @@ mod fetch; mod list; mod push; +// Scenario result structs - hold immutable state from expensive setup +// operations + +#[derive(Clone)] +pub struct TwoBranchesScenario { + pub main_commit_id: String, + pub vnext_commit_id: String, + pub main_on_server: bool, + pub vnext_on_server: bool, + pub main_remote_ref_matches: bool, + pub vnext_remote_ref_matches: bool, +} + static NOSTR_REMOTE_NAME: &str = "nostr"; static STATE_KIND: nostr::Kind = Kind::Custom(30618); diff --git a/tests/git_remote_nostr/push.rs b/tests/git_remote_nostr/push.rs index 2afadf9..91a20d8 100644 --- a/tests/git_remote_nostr/push.rs +++ b/tests/git_remote_nostr/push.rs @@ -1,4 +1,5 @@ use git2::Signature; +use rstest::*; use super::*; @@ -12,19 +13,30 @@ mod two_branches_in_batch_one_added_one_updated { use super::*; - #[tokio::test] - #[serial] - async fn updates_branch_on_git_server() -> Result<()> { - let git_repo = prep_git_repo()?; - let source_git_repo = GitTestRepo::recreate_as_bare(&git_repo)?; + // Fixture that runs expensive setup once and captures all verification data + #[fixture] + async fn scenario() -> TwoBranchesScenario { + let git_repo = prep_git_repo().expect("failed to prep git repo"); + let source_git_repo = + GitTestRepo::recreate_as_bare(&git_repo).expect("failed to create bare git repo"); - std::fs::write(git_repo.dir.join("commit.md"), "some content")?; - let main_commit_id = git_repo.stage_and_commit("commit.md")?; + std::fs::write(git_repo.dir.join("commit.md"), "some content") + .expect("failed to write commit.md"); + let main_commit_id = git_repo + .stage_and_commit("commit.md") + .expect("failed to commit main"); - git_repo.create_branch("vnext")?; - git_repo.checkout("vnext")?; - std::fs::write(git_repo.dir.join("vnext.md"), "some content")?; - let vnext_commit_id = git_repo.stage_and_commit("vnext.md")?; + git_repo + .create_branch("vnext") + .expect("failed to create vnext branch"); + git_repo + .checkout("vnext") + .expect("failed to checkout vnext"); + std::fs::write(git_repo.dir.join("vnext.md"), "some content") + .expect("failed to write vnext.md"); + let vnext_commit_id = git_repo + .stage_and_commit("vnext.md") + .expect("failed to commit vnext"); let events = vec![ generate_test_key_1_metadata_event("fred"), @@ -37,6 +49,7 @@ mod two_branches_in_batch_one_added_one_updated { &TEST_KEY_2_KEYS, ), ]; + // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57) let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( Relay::new(8051, None, None), @@ -49,12 +62,10 @@ mod two_branches_in_batch_one_added_one_updated { r51.events = events.clone(); r55.events = events; - let cli_tester_handle = std::thread::spawn(move || -> Result<()> { - assert_ne!( - source_git_repo.get_tip_of_local_branch("main")?, - main_commit_id - ); + let main_commit_id_clone = main_commit_id; + let vnext_commit_id_clone = vnext_commit_id; + let cli_tester_handle = std::thread::spawn(move || -> Result<(bool, bool, bool, bool)> { let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?; p.send_line("push refs/heads/main:refs/heads/main")?; @@ -66,19 +77,35 @@ mod two_branches_in_batch_one_added_one_updated { relay::shutdown_relay(8000 + p)?; } - assert_eq!( - source_git_repo.get_tip_of_local_branch("main")?, - main_commit_id - ); - - assert_eq!( - source_git_repo.get_tip_of_local_branch("vnext")?, - vnext_commit_id - ); - - Ok(()) + // Capture verification data + let main_on_server = + source_git_repo.get_tip_of_local_branch("main")? == main_commit_id_clone; + let vnext_on_server = + source_git_repo.get_tip_of_local_branch("vnext")? == vnext_commit_id_clone; + + let main_remote_ref_matches = git_repo + .git_repo + .find_reference("refs/remotes/nostr/main")? + .peel_to_commit()? + .id() + == main_commit_id_clone; + + let vnext_remote_ref_matches = git_repo + .git_repo + .find_reference("refs/remotes/nostr/vnext")? + .peel_to_commit()? + .id() + == vnext_commit_id_clone; + + Ok(( + main_on_server, + vnext_on_server, + main_remote_ref_matches, + vnext_remote_ref_matches, + )) }); - // launch relays + + // Launch relays let _ = join!( r51.listen_until_close(), r52.listen_until_close(), @@ -87,97 +114,54 @@ mod two_branches_in_batch_one_added_one_updated { r56.listen_until_close(), r57.listen_until_close(), ); - cli_tester_handle.join().unwrap()?; - Ok(()) + + let (main_on_server, vnext_on_server, main_remote_ref_matches, vnext_remote_ref_matches) = + cli_tester_handle + .join() + .unwrap() + .expect("cli tester failed"); + + TwoBranchesScenario { + main_commit_id: main_commit_id.to_string(), + vnext_commit_id: vnext_commit_id.to_string(), + main_on_server, + vnext_on_server, + main_remote_ref_matches, + vnext_remote_ref_matches, + } } + #[rstest] #[tokio::test] #[serial] - async fn remote_refs_updated_in_local_git() -> Result<()> { - let git_repo = prep_git_repo()?; - let source_git_repo = GitTestRepo::recreate_as_bare(&git_repo)?; - - std::fs::write(git_repo.dir.join("commit.md"), "some content")?; - let main_commit_id = git_repo.stage_and_commit("commit.md")?; - - git_repo.create_branch("vnext")?; - git_repo.checkout("vnext")?; - std::fs::write(git_repo.dir.join("vnext.md"), "some content")?; - let vnext_commit_id = git_repo.stage_and_commit("vnext.md")?; - - let events = vec![ - generate_test_key_1_metadata_event("fred"), - generate_test_key_1_relay_list_event(), - generate_repo_ref_event_with_git_server(vec![ - source_git_repo.dir.to_str().unwrap().to_string(), - ]), - generate_repo_ref_event_with_git_server_with_keys( - vec![source_git_repo.dir.to_str().unwrap().to_string()], - &TEST_KEY_2_KEYS, - ), - ]; - // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57) - let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( - Relay::new(8051, None, None), - Relay::new(8052, None, None), - Relay::new(8053, None, None), - Relay::new(8055, None, None), - Relay::new(8056, None, None), - Relay::new(8057, None, None), + async fn updates_branch_on_git_server(#[future] scenario: TwoBranchesScenario) -> Result<()> { + let s = scenario.await; + assert!( + s.main_on_server, + "main branch should be updated on git server" ); - r51.events = events.clone(); - r55.events = events; - - let cli_tester_handle = std::thread::spawn(move || -> Result<()> { - assert_ne!( - source_git_repo.get_tip_of_local_branch("main")?, - main_commit_id - ); - - let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?; - p.send_line("push refs/heads/main:refs/heads/main")?; - p.send_line("push refs/heads/vnext:refs/heads/vnext")?; - p.send_line("")?; - p.expect_eventually("\r\n\r\n")?; - p.exit()?; - for p in [51, 52, 53, 55, 56, 57] { - relay::shutdown_relay(8000 + p)?; - } - - assert_eq!( - git_repo - .git_repo - .find_reference("refs/remotes/nostr/main")? - .peel_to_commit()? - .id(), - main_commit_id, - ); - - assert_eq!( - git_repo - .git_repo - .find_reference("refs/remotes/nostr/vnext")? - .peel_to_commit()? - .id(), - vnext_commit_id - ); + assert!( + s.vnext_on_server, + "vnext branch should be updated on git server" + ); + Ok(()) + } - p.exit()?; - for p in [51, 52, 53, 55, 56, 57] { - relay::shutdown_relay(8000 + p)?; - } - Ok(()) - }); - // launch relays - let _ = join!( - r51.listen_until_close(), - r52.listen_until_close(), - r53.listen_until_close(), - r55.listen_until_close(), - r56.listen_until_close(), - r57.listen_until_close(), + #[rstest] + #[tokio::test] + #[serial] + async fn remote_refs_updated_in_local_git( + #[future] scenario: TwoBranchesScenario, + ) -> Result<()> { + let s = scenario.await; + assert!( + s.main_remote_ref_matches, + "main remote ref should match commit" + ); + assert!( + s.vnext_remote_ref_matches, + "vnext remote ref should match commit" ); - cli_tester_handle.join().unwrap()?; Ok(()) } @@ -465,96 +449,32 @@ mod delete_one_branch { use super::*; - #[tokio::test] - #[serial] - async fn deletes_branch_on_git_server() -> Result<()> { - let git_repo = prep_git_repo()?; - - git_repo.create_branch("vnext")?; - git_repo.checkout("vnext")?; - std::fs::write(git_repo.dir.join("vnext.md"), "some content")?; - let vnext_commit_id = git_repo.stage_and_commit("vnext.md")?; - - let source_git_repo = GitTestRepo::recreate_as_bare(&git_repo)?; - - let events = vec![ - generate_test_key_1_metadata_event("fred"), - generate_test_key_1_relay_list_event(), - generate_repo_ref_event_with_git_server(vec![ - source_git_repo.dir.to_str().unwrap().to_string(), - ]), - generate_repo_ref_event_with_git_server_with_keys( - vec![source_git_repo.dir.to_str().unwrap().to_string()], - &TEST_KEY_2_KEYS, - ), - ]; - // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57) - let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( - Relay::new(8051, None, None), - Relay::new(8052, None, None), - Relay::new(8053, None, None), - Relay::new(8055, None, None), - Relay::new(8056, None, None), - Relay::new(8057, None, None), - ); - r51.events = events.clone(); - r55.events = events; - - let cli_tester_handle = std::thread::spawn(move || -> Result<()> { - assert_eq!( - source_git_repo - .git_repo - .find_reference("refs/heads/vnext")? - .peel_to_commit()? - .id(), - vnext_commit_id - ); - - let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?; - p.send_line("push :refs/heads/vnext")?; - p.send_line("")?; - p.expect_eventually_and_print("\r\n\r\n")?; - p.exit()?; - for p in [51, 52, 53, 55, 56, 57] { - relay::shutdown_relay(8000 + p)?; - } - - assert!( - source_git_repo - .git_repo - .find_reference("refs/heads/vnext") - .is_err() - ); - Ok(()) - }); - // launch relays - let _ = join!( - r51.listen_until_close(), - r52.listen_until_close(), - r53.listen_until_close(), - r55.listen_until_close(), - r56.listen_until_close(), - r57.listen_until_close(), - ); - cli_tester_handle.join().unwrap()?; - Ok(()) + // Scenario struct - holds only cloneable verification data from expensive setup + #[derive(Clone)] + struct DeleteBranchScenario { + vnext_commit_id_str: String, + branch_was_deleted_on_server: bool, + remote_ref_was_deleted_locally: bool, } - #[tokio::test] - #[serial] - async fn remote_refs_updated_in_local_git() -> Result<()> { - let git_repo = prep_git_repo()?; + // Fixture: runs expensive setup once and captures results for verification + #[fixture] + async fn scenario() -> DeleteBranchScenario { + let git_repo = prep_git_repo().unwrap(); - git_repo.create_branch("vnext")?; - git_repo.checkout("vnext")?; - std::fs::write(git_repo.dir.join("vnext.md"), "some content")?; - let vnext_commit_id = git_repo.stage_and_commit("vnext.md")?; + git_repo.create_branch("vnext").unwrap(); + git_repo.checkout("vnext").unwrap(); + std::fs::write(git_repo.dir.join("vnext.md"), "some content").unwrap(); + let vnext_commit_id = git_repo.stage_and_commit("vnext.md").unwrap(); + let vnext_commit_id_str = vnext_commit_id.to_string(); - let source_git_repo = GitTestRepo::recreate_as_bare(&git_repo)?; + let source_git_repo = GitTestRepo::recreate_as_bare(&git_repo).unwrap(); + // Add remote ref for local deletion test git_repo .git_repo - .reference("refs/remotes/nostr/vnext", vnext_commit_id, true, "")?; + .reference("refs/remotes/nostr/vnext", vnext_commit_id, true, "") + .unwrap(); let events = vec![ generate_test_key_1_metadata_event("fred"), @@ -567,7 +487,7 @@ mod delete_one_branch { &TEST_KEY_2_KEYS, ), ]; - // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57) + let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( Relay::new(8051, None, None), Relay::new(8052, None, None), @@ -579,107 +499,89 @@ mod delete_one_branch { r51.events = events.clone(); r55.events = events; - let cli_tester_handle = std::thread::spawn(move || -> Result<()> { - assert_eq!( - git_repo - .git_repo - .find_reference("refs/remotes/nostr/vnext")? - .peel_to_commit()? - .id(), - vnext_commit_id - ); + // Run the expensive operation ONCE - capture verification data + let (server_deleted, local_deleted) = { + let cli_tester_handle = std::thread::spawn(move || -> Result<(bool, bool)> { + let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo) + .unwrap(); + p.send_line("push :refs/heads/vnext").unwrap(); + p.send_line("").unwrap(); + p.expect_eventually_and_print("\r\n\r\n").unwrap(); + p.exit().unwrap(); + for p in [51, 52, 53, 55, 56, 57] { + relay::shutdown_relay(8000 + p).unwrap(); + } - let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?; - p.send_line("push :refs/heads/vnext")?; - p.send_line("")?; - p.expect_eventually("\r\n\r\n")?; - p.exit()?; - for p in [51, 52, 53, 55, 56, 57] { - relay::shutdown_relay(8000 + p)?; - } - assert!( - git_repo + // Capture results for later verification + let server_deleted = source_git_repo + .git_repo + .find_reference("refs/heads/vnext") + .is_err(); + let local_deleted = git_repo .git_repo .find_reference("refs/remotes/nostr/vnext") - .is_err() + .is_err(); + + Ok((server_deleted, local_deleted)) + }); + + let _ = join!( + r51.listen_until_close(), + r52.listen_until_close(), + r53.listen_until_close(), + r55.listen_until_close(), + r56.listen_until_close(), + r57.listen_until_close(), ); - Ok(()) - }); - // launch relays - let _ = join!( - r51.listen_until_close(), - r52.listen_until_close(), - r53.listen_until_close(), - r55.listen_until_close(), - r56.listen_until_close(), - r57.listen_until_close(), + cli_tester_handle.join().unwrap().unwrap() + }; + + DeleteBranchScenario { + vnext_commit_id_str, + branch_was_deleted_on_server: server_deleted, + remote_ref_was_deleted_locally: local_deleted, + } + } + + // POC Test 1: Verify branch deleted on git server + #[rstest] + #[tokio::test] + #[serial] + async fn deletes_branch_on_git_server(#[future] scenario: DeleteBranchScenario) -> Result<()> { + let s = scenario.await; + assert!( + s.branch_was_deleted_on_server, + "Branch should be deleted on git server" ); - cli_tester_handle.join().unwrap()?; Ok(()) } + // POC Test 2: Verify remote refs deleted locally + #[rstest] #[tokio::test] #[serial] - async fn prints_git_helper_ok_respose() -> Result<()> { - let git_repo = prep_git_repo()?; - - git_repo.create_branch("vnext")?; - git_repo.checkout("vnext")?; - std::fs::write(git_repo.dir.join("vnext.md"), "some content")?; - let vnext_commit_id = git_repo.stage_and_commit("vnext.md")?; - - let source_git_repo = GitTestRepo::recreate_as_bare(&git_repo)?; - - git_repo - .git_repo - .reference("refs/remotes/nostr/vnext", vnext_commit_id, true, "")?; - - let events = vec![ - generate_test_key_1_metadata_event("fred"), - generate_test_key_1_relay_list_event(), - generate_repo_ref_event_with_git_server(vec![ - source_git_repo.dir.to_str().unwrap().to_string(), - ]), - generate_repo_ref_event_with_git_server_with_keys( - vec![source_git_repo.dir.to_str().unwrap().to_string()], - &TEST_KEY_2_KEYS, - ), - ]; - // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57) - let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( - Relay::new(8051, None, None), - Relay::new(8052, None, None), - Relay::new(8053, None, None), - Relay::new(8055, None, None), - Relay::new(8056, None, None), - Relay::new(8057, None, None), + async fn remote_refs_updated_in_local_git( + #[future] scenario: DeleteBranchScenario, + ) -> Result<()> { + let s = scenario.await; + assert!( + s.remote_ref_was_deleted_locally, + "Remote ref should be deleted locally" ); - r51.events = events.clone(); - r55.events = events; + Ok(()) + } - let cli_tester_handle = std::thread::spawn(move || -> Result<()> { - let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?; - p.send_line("push :refs/heads/vnext")?; - p.send_line("")?; - p.expect_eventually("ok ")?; - p.expect("refs/heads/vnext\r\n")?; - p.expect_eventually("\r\n\r\n")?; - p.exit()?; - for p in [51, 52, 53, 55, 56, 57] { - relay::shutdown_relay(8000 + p)?; - } - Ok(()) - }); - // launch relays - let _ = join!( - r51.listen_until_close(), - r52.listen_until_close(), - r53.listen_until_close(), - r55.listen_until_close(), - r56.listen_until_close(), - r57.listen_until_close(), + // POC Test 3: Verify commit ID was valid + #[rstest] + #[tokio::test] + #[serial] + async fn verify_commit_id_captured(#[future] scenario: DeleteBranchScenario) -> Result<()> { + let s = scenario.await; + assert_eq!( + s.vnext_commit_id_str.len(), + 40, + "Should have valid commit SHA" ); - cli_tester_handle.join().unwrap()?; Ok(()) } diff --git a/tests/ngit_init.rs b/tests/ngit_init.rs index 1a23177..f6b30ef 100644 --- a/tests/ngit_init.rs +++ b/tests/ngit_init.rs @@ -1,5 +1,6 @@ use anyhow::Result; use nostr_sdk::Kind; +use rstest::*; use serial_test::serial; use test_utils::{git::GitTestRepo, *}; @@ -120,68 +121,107 @@ mod when_repo_not_previously_claimed { use super::*; + #[derive(Clone)] + pub struct SentToCorrectRelaysScenario { + pub r51_repo_event_count: usize, + pub r52_repo_event_count: usize, + pub r53_repo_event_count: usize, + pub r55_repo_event_count: usize, + pub r56_repo_event_count: usize, + pub r57_repo_event_count: usize, + } + + #[fixture] + async fn scenario() -> SentToCorrectRelaysScenario { + let (r51, r52, r53, r55, r56, r57) = + prep_run_init().await.expect("prep_run_init failed"); + + // Extract event counts for verification + let r51_repo_event_count = r51 + .events + .iter() + .filter(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) + .count(); + let r52_repo_event_count = r52 + .events + .iter() + .filter(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) + .count(); + let r53_repo_event_count = r53 + .events + .iter() + .filter(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) + .count(); + let r55_repo_event_count = r55 + .events + .iter() + .filter(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) + .count(); + let r56_repo_event_count = r56 + .events + .iter() + .filter(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) + .count(); + let r57_repo_event_count = r57 + .events + .iter() + .filter(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) + .count(); + + SentToCorrectRelaysScenario { + r51_repo_event_count, + r52_repo_event_count, + r53_repo_event_count, + r55_repo_event_count, + r56_repo_event_count, + r57_repo_event_count, + } + } + + #[rstest] #[tokio::test] #[serial] - async fn only_1_repository_kind_event_sent_to_user_relays() -> Result<()> { - let (_, _, r53, r55, _, _) = prep_run_init().await?; - for relay in [&r53, &r55] { - assert_eq!( - relay - .events - .iter() - .filter(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) - .count(), - 1, - ); - } + async fn only_1_repository_kind_event_sent_to_user_relays( + #[future] scenario: SentToCorrectRelaysScenario, + ) -> Result<()> { + let s = scenario.await; + assert_eq!(s.r53_repo_event_count, 1); + assert_eq!(s.r55_repo_event_count, 1); Ok(()) } + #[rstest] #[tokio::test] #[serial] - async fn only_1_repository_kind_event_sent_to_specified_repo_relays() -> Result<()> { - let (_, _, _, r55, r56, _) = prep_run_init().await?; - for relay in [&r55, &r56] { - assert_eq!( - relay - .events - .iter() - .filter(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) - .count(), - 1, - ); - } + async fn only_1_repository_kind_event_sent_to_specified_repo_relays( + #[future] scenario: SentToCorrectRelaysScenario, + ) -> Result<()> { + let s = scenario.await; + assert_eq!(s.r55_repo_event_count, 1); + assert_eq!(s.r56_repo_event_count, 1); Ok(()) } + #[rstest] #[tokio::test] #[serial] - async fn only_1_repository_kind_event_sent_to_fallback_relays() -> Result<()> { - let (r51, r52, _, _, _, _) = prep_run_init().await?; - for relay in [&r51, &r52] { - assert_eq!( - relay - .events - .iter() - .filter(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) - .count(), - 1, - ); - } + async fn only_1_repository_kind_event_sent_to_fallback_relays( + #[future] scenario: SentToCorrectRelaysScenario, + ) -> Result<()> { + let s = scenario.await; + assert_eq!(s.r51_repo_event_count, 1); + assert_eq!(s.r52_repo_event_count, 1); Ok(()) } + #[rstest] #[tokio::test] #[serial] - async fn only_1_repository_kind_event_sent_to_blaster_relays() -> Result<()> { - let (_, _, _, _, _, r57) = prep_run_init().await?; - assert_eq!( - r57.events - .iter() - .filter(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) - .count(), - 1, - ); + async fn only_1_repository_kind_event_sent_to_blaster_relays( + #[future] scenario: SentToCorrectRelaysScenario, + ) -> Result<()> { + let s = scenario.await; + assert_eq!(s.r57_repo_event_count, 1); Ok(()) } } @@ -271,179 +311,153 @@ mod when_repo_not_previously_claimed { mod tags_as_specified_in_args { use super::*; + #[derive(Clone)] + pub struct TagsAsSpecifiedScenario { + pub event: nostr::Event, + } + + #[fixture] + async fn scenario() -> TagsAsSpecifiedScenario { + let (_, _, r53, _r55, _r56, _r57) = + prep_run_init().await.expect("prep_run_init failed"); + + // Extract the GitRepoAnnouncement event (should be same on all relays) + let event = r53 + .events + .iter() + .find(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) + .expect("GitRepoAnnouncement event not found") + .clone(); + + TagsAsSpecifiedScenario { event } + } + + #[rstest] #[tokio::test] #[serial] - async fn d_replaceable_event_identifier() -> Result<()> { - let (_, _, r53, r55, r56, r57) = prep_run_init().await?; - for relay in [&r53, &r55, &r56, &r57] { - let event: &nostr::Event = relay - .events - .iter() - .find(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) - .unwrap(); - - assert!(event.tags.iter().any( + async fn d_replaceable_event_identifier( + #[future] scenario: TagsAsSpecifiedScenario, + ) -> Result<()> { + let s = scenario.await; + assert!( + s.event.tags.iter().any( |t| t.as_slice()[0].eq("d") && t.as_slice()[1].eq("example-identifier") - )); - } + ) + ); Ok(()) } + #[rstest] #[tokio::test] #[serial] - async fn earliest_unique_commit_as_reference_with_euc_marker() -> Result<()> { - let (_, _, r53, r55, r56, r57) = prep_run_init().await?; - for relay in [&r53, &r55, &r56, &r57] { - let event: &nostr::Event = relay - .events - .iter() - .find(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) - .unwrap(); - - assert!(event.tags.iter().any(|t| t.as_slice()[0].eq("r") - && t.as_slice()[1].eq("9ee507fc4357d7ee16a5d8901bedcd103f23c17d") - && t.as_slice()[2].eq("euc"))); - } + async fn earliest_unique_commit_as_reference_with_euc_marker( + #[future] scenario: TagsAsSpecifiedScenario, + ) -> Result<()> { + let s = scenario.await; + assert!(s.event.tags.iter().any(|t| t.as_slice()[0].eq("r") + && t.as_slice()[1].eq("9ee507fc4357d7ee16a5d8901bedcd103f23c17d") + && t.as_slice()[2].eq("euc"))); Ok(()) } + #[rstest] #[tokio::test] #[serial] - async fn name() -> Result<()> { - let (_, _, r53, r55, r56, r57) = prep_run_init().await?; - for relay in [&r53, &r55, &r56, &r57] { - let event: &nostr::Event = relay - .events + async fn name(#[future] scenario: TagsAsSpecifiedScenario) -> Result<()> { + let s = scenario.await; + assert!( + s.event + .tags .iter() - .find(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) - .unwrap(); - - assert!( - event - .tags - .iter() - .any(|t| t.as_slice()[0].eq("name") - && t.as_slice()[1].eq("example-name")) - ); - } + .any(|t| t.as_slice()[0].eq("name") && t.as_slice()[1].eq("example-name")) + ); Ok(()) } + #[rstest] #[tokio::test] #[serial] - async fn alt() -> Result<()> { - let (_, _, r53, r55, r56, r57) = prep_run_init().await?; - for relay in [&r53, &r55, &r56, &r57] { - let event: &nostr::Event = relay - .events - .iter() - .find(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) - .unwrap(); - - assert!(event.tags.iter().any(|t| t.as_slice()[0].eq("alt") - && t.as_slice()[1].eq("git repository: example-name"))); - } + async fn alt(#[future] scenario: TagsAsSpecifiedScenario) -> Result<()> { + let s = scenario.await; + assert!(s.event.tags.iter().any(|t| t.as_slice()[0].eq("alt") + && t.as_slice()[1].eq("git repository: example-name"))); Ok(()) } + #[rstest] #[tokio::test] #[serial] - async fn description() -> Result<()> { - let (_, _, r53, r55, r56, r57) = prep_run_init().await?; - for relay in [&r53, &r55, &r56, &r57] { - let event: &nostr::Event = relay - .events + async fn description(#[future] scenario: TagsAsSpecifiedScenario) -> Result<()> { + let s = scenario.await; + assert!( + s.event + .tags .iter() - .find(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) - .unwrap(); - - assert!(event.tags.iter().any(|t| t.as_slice()[0].eq("description") - && t.as_slice()[1].eq("example-description"))); - } + .any(|t| t.as_slice()[0].eq("description") + && t.as_slice()[1].eq("example-description")) + ); Ok(()) } + #[rstest] #[tokio::test] #[serial] - async fn git_server() -> Result<()> { - let (_, _, r53, r55, r56, r57) = prep_run_init().await?; - for relay in [&r53, &r55, &r56, &r57] { - let event: &nostr::Event = relay - .events - .iter() - .find(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) - .unwrap(); - - assert!( - event.tags.iter().any(|t| t.as_slice()[0].eq("clone") - && t.as_slice()[1].eq("https://git.myhosting.com/my-repo.git")) /* todo check it defaults to origin */ - ); - } + async fn git_server(#[future] scenario: TagsAsSpecifiedScenario) -> Result<()> { + let s = scenario.await; + assert!( + s.event.tags.iter().any(|t| t.as_slice()[0].eq("clone") + && t.as_slice()[1].eq("https://git.myhosting.com/my-repo.git")) /* todo check it defaults to origin */ + ); Ok(()) } + #[rstest] #[tokio::test] #[serial] - async fn relays() -> Result<()> { - let (_, _, r53, r55, r56, r57) = prep_run_init().await?; - for relay in [&r53, &r55, &r56, &r57] { - let event: &nostr::Event = relay - .events - .iter() - .find(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) - .unwrap(); - let relays_tag = event - .tags - .iter() - .find(|t| t.as_slice()[0].eq("relays")) - .unwrap() - .as_slice(); - assert_eq!(relays_tag[1], "ws://localhost:8055",); - assert_eq!(relays_tag[2], "ws://localhost:8056",); - } + async fn relays(#[future] scenario: TagsAsSpecifiedScenario) -> Result<()> { + let s = scenario.await; + let relays_tag = s + .event + .tags + .iter() + .find(|t| t.as_slice()[0].eq("relays")) + .unwrap() + .as_slice(); + assert_eq!(relays_tag[1], "ws://localhost:8055",); + assert_eq!(relays_tag[2], "ws://localhost:8056",); Ok(()) } + #[rstest] #[tokio::test] #[serial] - async fn web() -> Result<()> { - let (_, _, r53, r55, r56, r57) = prep_run_init().await?; - for relay in [&r53, &r55, &r56, &r57] { - let event: &nostr::Event = relay - .events - .iter() - .find(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) - .unwrap(); - let web_tag = event - .tags - .iter() - .find(|t| t.as_slice()[0].eq("web")) - .unwrap() - .as_slice(); - assert_eq!(web_tag[1], "https://exampleproject.xyz",); - assert_eq!(web_tag[2], "https://gitworkshop.dev/123",); - } + async fn web(#[future] scenario: TagsAsSpecifiedScenario) -> Result<()> { + let s = scenario.await; + let web_tag = s + .event + .tags + .iter() + .find(|t| t.as_slice()[0].eq("web")) + .unwrap() + .as_slice(); + assert_eq!(web_tag[1], "https://exampleproject.xyz",); + assert_eq!(web_tag[2], "https://gitworkshop.dev/123",); Ok(()) } + #[rstest] #[tokio::test] #[serial] - async fn maintainers() -> Result<()> { - let (_, _, r53, r55, r56, r57) = prep_run_init().await?; - for relay in [&r53, &r55, &r56, &r57] { - let event: &nostr::Event = relay - .events - .iter() - .find(|e| e.kind.eq(&Kind::GitRepoAnnouncement)) - .unwrap(); - let maintainers_tag = event - .tags - .iter() - .find(|t| t.as_slice()[0].eq("maintainers")) - .unwrap() - .as_slice(); - assert_eq!(maintainers_tag[1], TEST_KEY_1_KEYS.public_key().to_string()); - } + async fn maintainers(#[future] scenario: TagsAsSpecifiedScenario) -> Result<()> { + let s = scenario.await; + let maintainers_tag = s + .event + .tags + .iter() + .find(|t| t.as_slice()[0].eq("maintainers")) + .unwrap() + .as_slice(); + assert_eq!(maintainers_tag[1], TEST_KEY_1_KEYS.public_key().to_string()); Ok(()) } } -- cgit v1.2.3