upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/tests/git_remote_nostr
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-10-28 13:19:24 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-10-28 13:19:24 +0000
commita287f53132c91eaa3ba8d5e9c2bec80587316aad (patch)
tree54a3237486b435f4f798d1af01d6340c8a626bb4 /tests/git_remote_nostr
parentdcbe6f9d9e14290c856b0118ab17f3be804ac14e (diff)
test: refactor to use rstest more efficient test runs
Identified high value areas to use rstest that would benefit most and refactored them
Diffstat (limited to 'tests/git_remote_nostr')
-rw-r--r--tests/git_remote_nostr/main.rs13
-rw-r--r--tests/git_remote_nostr/push.rs470
2 files changed, 199 insertions, 284 deletions
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;
13mod list; 13mod list;
14mod push; 14mod push;
15 15
16// Scenario result structs - hold immutable state from expensive setup
17// operations
18
19#[derive(Clone)]
20pub struct TwoBranchesScenario {
21 pub main_commit_id: String,
22 pub vnext_commit_id: String,
23 pub main_on_server: bool,
24 pub vnext_on_server: bool,
25 pub main_remote_ref_matches: bool,
26 pub vnext_remote_ref_matches: bool,
27}
28
16static NOSTR_REMOTE_NAME: &str = "nostr"; 29static NOSTR_REMOTE_NAME: &str = "nostr";
17static STATE_KIND: nostr::Kind = Kind::Custom(30618); 30static STATE_KIND: nostr::Kind = Kind::Custom(30618);
18 31
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 @@
1use git2::Signature; 1use git2::Signature;
2use rstest::*;
2 3
3use super::*; 4use super::*;
4 5
@@ -12,19 +13,30 @@ mod two_branches_in_batch_one_added_one_updated {
12 13
13 use super::*; 14 use super::*;
14 15
15 #[tokio::test] 16 // Fixture that runs expensive setup once and captures all verification data
16 #[serial] 17 #[fixture]
17 async fn updates_branch_on_git_server() -> Result<()> { 18 async fn scenario() -> TwoBranchesScenario {
18 let git_repo = prep_git_repo()?; 19 let git_repo = prep_git_repo().expect("failed to prep git repo");
19 let source_git_repo = GitTestRepo::recreate_as_bare(&git_repo)?; 20 let source_git_repo =
21 GitTestRepo::recreate_as_bare(&git_repo).expect("failed to create bare git repo");
20 22
21 std::fs::write(git_repo.dir.join("commit.md"), "some content")?; 23 std::fs::write(git_repo.dir.join("commit.md"), "some content")
22 let main_commit_id = git_repo.stage_and_commit("commit.md")?; 24 .expect("failed to write commit.md");
25 let main_commit_id = git_repo
26 .stage_and_commit("commit.md")
27 .expect("failed to commit main");
23 28
24 git_repo.create_branch("vnext")?; 29 git_repo
25 git_repo.checkout("vnext")?; 30 .create_branch("vnext")
26 std::fs::write(git_repo.dir.join("vnext.md"), "some content")?; 31 .expect("failed to create vnext branch");
27 let vnext_commit_id = git_repo.stage_and_commit("vnext.md")?; 32 git_repo
33 .checkout("vnext")
34 .expect("failed to checkout vnext");
35 std::fs::write(git_repo.dir.join("vnext.md"), "some content")
36 .expect("failed to write vnext.md");
37 let vnext_commit_id = git_repo
38 .stage_and_commit("vnext.md")
39 .expect("failed to commit vnext");
28 40
29 let events = vec![ 41 let events = vec![
30 generate_test_key_1_metadata_event("fred"), 42 generate_test_key_1_metadata_event("fred"),
@@ -37,6 +49,7 @@ mod two_branches_in_batch_one_added_one_updated {
37 &TEST_KEY_2_KEYS, 49 &TEST_KEY_2_KEYS,
38 ), 50 ),
39 ]; 51 ];
52
40 // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57) 53 // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57)
41 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( 54 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
42 Relay::new(8051, None, None), 55 Relay::new(8051, None, None),
@@ -49,12 +62,10 @@ mod two_branches_in_batch_one_added_one_updated {
49 r51.events = events.clone(); 62 r51.events = events.clone();
50 r55.events = events; 63 r55.events = events;
51 64
52 let cli_tester_handle = std::thread::spawn(move || -> Result<()> { 65 let main_commit_id_clone = main_commit_id;
53 assert_ne!( 66 let vnext_commit_id_clone = vnext_commit_id;
54 source_git_repo.get_tip_of_local_branch("main")?,
55 main_commit_id
56 );
57 67
68 let cli_tester_handle = std::thread::spawn(move || -> Result<(bool, bool, bool, bool)> {
58 let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?; 69 let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?;
59 70
60 p.send_line("push refs/heads/main:refs/heads/main")?; 71 p.send_line("push refs/heads/main:refs/heads/main")?;
@@ -66,19 +77,35 @@ mod two_branches_in_batch_one_added_one_updated {
66 relay::shutdown_relay(8000 + p)?; 77 relay::shutdown_relay(8000 + p)?;
67 } 78 }
68 79
69 assert_eq!( 80 // Capture verification data
70 source_git_repo.get_tip_of_local_branch("main")?, 81 let main_on_server =
71 main_commit_id 82 source_git_repo.get_tip_of_local_branch("main")? == main_commit_id_clone;
72 ); 83 let vnext_on_server =
73 84 source_git_repo.get_tip_of_local_branch("vnext")? == vnext_commit_id_clone;
74 assert_eq!( 85
75 source_git_repo.get_tip_of_local_branch("vnext")?, 86 let main_remote_ref_matches = git_repo
76 vnext_commit_id 87 .git_repo
77 ); 88 .find_reference("refs/remotes/nostr/main")?
78 89 .peel_to_commit()?
79 Ok(()) 90 .id()
91 == main_commit_id_clone;
92
93 let vnext_remote_ref_matches = git_repo
94 .git_repo
95 .find_reference("refs/remotes/nostr/vnext")?
96 .peel_to_commit()?
97 .id()
98 == vnext_commit_id_clone;
99
100 Ok((
101 main_on_server,
102 vnext_on_server,
103 main_remote_ref_matches,
104 vnext_remote_ref_matches,
105 ))
80 }); 106 });
81 // launch relays 107
108 // Launch relays
82 let _ = join!( 109 let _ = join!(
83 r51.listen_until_close(), 110 r51.listen_until_close(),
84 r52.listen_until_close(), 111 r52.listen_until_close(),
@@ -87,97 +114,54 @@ mod two_branches_in_batch_one_added_one_updated {
87 r56.listen_until_close(), 114 r56.listen_until_close(),
88 r57.listen_until_close(), 115 r57.listen_until_close(),
89 ); 116 );
90 cli_tester_handle.join().unwrap()?; 117
91 Ok(()) 118 let (main_on_server, vnext_on_server, main_remote_ref_matches, vnext_remote_ref_matches) =
119 cli_tester_handle
120 .join()
121 .unwrap()
122 .expect("cli tester failed");
123
124 TwoBranchesScenario {
125 main_commit_id: main_commit_id.to_string(),
126 vnext_commit_id: vnext_commit_id.to_string(),
127 main_on_server,
128 vnext_on_server,
129 main_remote_ref_matches,
130 vnext_remote_ref_matches,
131 }
92 } 132 }
93 133
134 #[rstest]
94 #[tokio::test] 135 #[tokio::test]
95 #[serial] 136 #[serial]
96 async fn remote_refs_updated_in_local_git() -> Result<()> { 137 async fn updates_branch_on_git_server(#[future] scenario: TwoBranchesScenario) -> Result<()> {
97 let git_repo = prep_git_repo()?; 138 let s = scenario.await;
98 let source_git_repo = GitTestRepo::recreate_as_bare(&git_repo)?; 139 assert!(
99 140 s.main_on_server,
100 std::fs::write(git_repo.dir.join("commit.md"), "some content")?; 141 "main branch should be updated on git server"
101 let main_commit_id = git_repo.stage_and_commit("commit.md")?;
102
103 git_repo.create_branch("vnext")?;
104 git_repo.checkout("vnext")?;
105 std::fs::write(git_repo.dir.join("vnext.md"), "some content")?;
106 let vnext_commit_id = git_repo.stage_and_commit("vnext.md")?;
107
108 let events = vec![
109 generate_test_key_1_metadata_event("fred"),
110 generate_test_key_1_relay_list_event(),
111 generate_repo_ref_event_with_git_server(vec![
112 source_git_repo.dir.to_str().unwrap().to_string(),
113 ]),
114 generate_repo_ref_event_with_git_server_with_keys(
115 vec![source_git_repo.dir.to_str().unwrap().to_string()],
116 &TEST_KEY_2_KEYS,
117 ),
118 ];
119 // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57)
120 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
121 Relay::new(8051, None, None),
122 Relay::new(8052, None, None),
123 Relay::new(8053, None, None),
124 Relay::new(8055, None, None),
125 Relay::new(8056, None, None),
126 Relay::new(8057, None, None),
127 ); 142 );
128 r51.events = events.clone(); 143 assert!(
129 r55.events = events; 144 s.vnext_on_server,
130 145 "vnext branch should be updated on git server"
131 let cli_tester_handle = std::thread::spawn(move || -> Result<()> { 146 );
132 assert_ne!( 147 Ok(())
133 source_git_repo.get_tip_of_local_branch("main")?, 148 }
134 main_commit_id
135 );
136
137 let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?;
138 p.send_line("push refs/heads/main:refs/heads/main")?;
139 p.send_line("push refs/heads/vnext:refs/heads/vnext")?;
140 p.send_line("")?;
141 p.expect_eventually("\r\n\r\n")?;
142 p.exit()?;
143 for p in [51, 52, 53, 55, 56, 57] {
144 relay::shutdown_relay(8000 + p)?;
145 }
146
147 assert_eq!(
148 git_repo
149 .git_repo
150 .find_reference("refs/remotes/nostr/main")?
151 .peel_to_commit()?
152 .id(),
153 main_commit_id,
154 );
155
156 assert_eq!(
157 git_repo
158 .git_repo
159 .find_reference("refs/remotes/nostr/vnext")?
160 .peel_to_commit()?
161 .id(),
162 vnext_commit_id
163 );
164 149
165 p.exit()?; 150 #[rstest]
166 for p in [51, 52, 53, 55, 56, 57] { 151 #[tokio::test]
167 relay::shutdown_relay(8000 + p)?; 152 #[serial]
168 } 153 async fn remote_refs_updated_in_local_git(
169 Ok(()) 154 #[future] scenario: TwoBranchesScenario,
170 }); 155 ) -> Result<()> {
171 // launch relays 156 let s = scenario.await;
172 let _ = join!( 157 assert!(
173 r51.listen_until_close(), 158 s.main_remote_ref_matches,
174 r52.listen_until_close(), 159 "main remote ref should match commit"
175 r53.listen_until_close(), 160 );
176 r55.listen_until_close(), 161 assert!(
177 r56.listen_until_close(), 162 s.vnext_remote_ref_matches,
178 r57.listen_until_close(), 163 "vnext remote ref should match commit"
179 ); 164 );
180 cli_tester_handle.join().unwrap()?;
181 Ok(()) 165 Ok(())
182 } 166 }
183 167
@@ -465,96 +449,32 @@ mod delete_one_branch {
465 449
466 use super::*; 450 use super::*;
467 451
468 #[tokio::test] 452 // Scenario struct - holds only cloneable verification data from expensive setup
469 #[serial] 453 #[derive(Clone)]
470 async fn deletes_branch_on_git_server() -> Result<()> { 454 struct DeleteBranchScenario {
471 let git_repo = prep_git_repo()?; 455 vnext_commit_id_str: String,
472 456 branch_was_deleted_on_server: bool,
473 git_repo.create_branch("vnext")?; 457 remote_ref_was_deleted_locally: bool,
474 git_repo.checkout("vnext")?;
475 std::fs::write(git_repo.dir.join("vnext.md"), "some content")?;
476 let vnext_commit_id = git_repo.stage_and_commit("vnext.md")?;
477
478 let source_git_repo = GitTestRepo::recreate_as_bare(&git_repo)?;
479
480 let events = vec![
481 generate_test_key_1_metadata_event("fred"),
482 generate_test_key_1_relay_list_event(),
483 generate_repo_ref_event_with_git_server(vec![
484 source_git_repo.dir.to_str().unwrap().to_string(),
485 ]),
486 generate_repo_ref_event_with_git_server_with_keys(
487 vec![source_git_repo.dir.to_str().unwrap().to_string()],
488 &TEST_KEY_2_KEYS,
489 ),
490 ];
491 // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57)
492 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
493 Relay::new(8051, None, None),
494 Relay::new(8052, None, None),
495 Relay::new(8053, None, None),
496 Relay::new(8055, None, None),
497 Relay::new(8056, None, None),
498 Relay::new(8057, None, None),
499 );
500 r51.events = events.clone();
501 r55.events = events;
502
503 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
504 assert_eq!(
505 source_git_repo
506 .git_repo
507 .find_reference("refs/heads/vnext")?
508 .peel_to_commit()?
509 .id(),
510 vnext_commit_id
511 );
512
513 let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?;
514 p.send_line("push :refs/heads/vnext")?;
515 p.send_line("")?;
516 p.expect_eventually_and_print("\r\n\r\n")?;
517 p.exit()?;
518 for p in [51, 52, 53, 55, 56, 57] {
519 relay::shutdown_relay(8000 + p)?;
520 }
521
522 assert!(
523 source_git_repo
524 .git_repo
525 .find_reference("refs/heads/vnext")
526 .is_err()
527 );
528 Ok(())
529 });
530 // launch relays
531 let _ = join!(
532 r51.listen_until_close(),
533 r52.listen_until_close(),
534 r53.listen_until_close(),
535 r55.listen_until_close(),
536 r56.listen_until_close(),
537 r57.listen_until_close(),
538 );
539 cli_tester_handle.join().unwrap()?;
540 Ok(())
541 } 458 }
542 459
543 #[tokio::test] 460 // Fixture: runs expensive setup once and captures results for verification
544 #[serial] 461 #[fixture]
545 async fn remote_refs_updated_in_local_git() -> Result<()> { 462 async fn scenario() -> DeleteBranchScenario {
546 let git_repo = prep_git_repo()?; 463 let git_repo = prep_git_repo().unwrap();
547 464
548 git_repo.create_branch("vnext")?; 465 git_repo.create_branch("vnext").unwrap();
549 git_repo.checkout("vnext")?; 466 git_repo.checkout("vnext").unwrap();
550 std::fs::write(git_repo.dir.join("vnext.md"), "some content")?; 467 std::fs::write(git_repo.dir.join("vnext.md"), "some content").unwrap();
551 let vnext_commit_id = git_repo.stage_and_commit("vnext.md")?; 468 let vnext_commit_id = git_repo.stage_and_commit("vnext.md").unwrap();
469 let vnext_commit_id_str = vnext_commit_id.to_string();
552 470
553 let source_git_repo = GitTestRepo::recreate_as_bare(&git_repo)?; 471 let source_git_repo = GitTestRepo::recreate_as_bare(&git_repo).unwrap();
554 472
473 // Add remote ref for local deletion test
555 git_repo 474 git_repo
556 .git_repo 475 .git_repo
557 .reference("refs/remotes/nostr/vnext", vnext_commit_id, true, "")?; 476 .reference("refs/remotes/nostr/vnext", vnext_commit_id, true, "")
477 .unwrap();
558 478
559 let events = vec![ 479 let events = vec![
560 generate_test_key_1_metadata_event("fred"), 480 generate_test_key_1_metadata_event("fred"),
@@ -567,7 +487,7 @@ mod delete_one_branch {
567 &TEST_KEY_2_KEYS, 487 &TEST_KEY_2_KEYS,
568 ), 488 ),
569 ]; 489 ];
570 // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57) 490
571 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( 491 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
572 Relay::new(8051, None, None), 492 Relay::new(8051, None, None),
573 Relay::new(8052, None, None), 493 Relay::new(8052, None, None),
@@ -579,107 +499,89 @@ mod delete_one_branch {
579 r51.events = events.clone(); 499 r51.events = events.clone();
580 r55.events = events; 500 r55.events = events;
581 501
582 let cli_tester_handle = std::thread::spawn(move || -> Result<()> { 502 // Run the expensive operation ONCE - capture verification data
583 assert_eq!( 503 let (server_deleted, local_deleted) = {
584 git_repo 504 let cli_tester_handle = std::thread::spawn(move || -> Result<(bool, bool)> {
585 .git_repo 505 let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)
586 .find_reference("refs/remotes/nostr/vnext")? 506 .unwrap();
587 .peel_to_commit()? 507 p.send_line("push :refs/heads/vnext").unwrap();
588 .id(), 508 p.send_line("").unwrap();
589 vnext_commit_id 509 p.expect_eventually_and_print("\r\n\r\n").unwrap();
590 ); 510 p.exit().unwrap();
511 for p in [51, 52, 53, 55, 56, 57] {
512 relay::shutdown_relay(8000 + p).unwrap();
513 }
591 514
592 let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?; 515 // Capture results for later verification
593 p.send_line("push :refs/heads/vnext")?; 516 let server_deleted = source_git_repo
594 p.send_line("")?; 517 .git_repo
595 p.expect_eventually("\r\n\r\n")?; 518 .find_reference("refs/heads/vnext")
596 p.exit()?; 519 .is_err();
597 for p in [51, 52, 53, 55, 56, 57] { 520 let local_deleted = git_repo
598 relay::shutdown_relay(8000 + p)?;
599 }
600 assert!(
601 git_repo
602 .git_repo 521 .git_repo
603 .find_reference("refs/remotes/nostr/vnext") 522 .find_reference("refs/remotes/nostr/vnext")
604 .is_err() 523 .is_err();
524
525 Ok((server_deleted, local_deleted))
526 });
527
528 let _ = join!(
529 r51.listen_until_close(),
530 r52.listen_until_close(),
531 r53.listen_until_close(),
532 r55.listen_until_close(),
533 r56.listen_until_close(),
534 r57.listen_until_close(),
605 ); 535 );
606 Ok(()) 536 cli_tester_handle.join().unwrap().unwrap()
607 }); 537 };
608 // launch relays 538
609 let _ = join!( 539 DeleteBranchScenario {
610 r51.listen_until_close(), 540 vnext_commit_id_str,
611 r52.listen_until_close(), 541 branch_was_deleted_on_server: server_deleted,
612 r53.listen_until_close(), 542 remote_ref_was_deleted_locally: local_deleted,
613 r55.listen_until_close(), 543 }
614 r56.listen_until_close(), 544 }
615 r57.listen_until_close(), 545
546 // POC Test 1: Verify branch deleted on git server
547 #[rstest]
548 #[tokio::test]
549 #[serial]
550 async fn deletes_branch_on_git_server(#[future] scenario: DeleteBranchScenario) -> Result<()> {
551 let s = scenario.await;
552 assert!(
553 s.branch_was_deleted_on_server,
554 "Branch should be deleted on git server"
616 ); 555 );
617 cli_tester_handle.join().unwrap()?;
618 Ok(()) 556 Ok(())
619 } 557 }
620 558
559 // POC Test 2: Verify remote refs deleted locally
560 #[rstest]
621 #[tokio::test] 561 #[tokio::test]
622 #[serial] 562 #[serial]
623 async fn prints_git_helper_ok_respose() -> Result<()> { 563 async fn remote_refs_updated_in_local_git(
624 let git_repo = prep_git_repo()?; 564 #[future] scenario: DeleteBranchScenario,
625 565 ) -> Result<()> {
626 git_repo.create_branch("vnext")?; 566 let s = scenario.await;
627 git_repo.checkout("vnext")?; 567 assert!(
628 std::fs::write(git_repo.dir.join("vnext.md"), "some content")?; 568 s.remote_ref_was_deleted_locally,
629 let vnext_commit_id = git_repo.stage_and_commit("vnext.md")?; 569 "Remote ref should be deleted locally"
630
631 let source_git_repo = GitTestRepo::recreate_as_bare(&git_repo)?;
632
633 git_repo
634 .git_repo
635 .reference("refs/remotes/nostr/vnext", vnext_commit_id, true, "")?;
636
637 let events = vec![
638 generate_test_key_1_metadata_event("fred"),
639 generate_test_key_1_relay_list_event(),
640 generate_repo_ref_event_with_git_server(vec![
641 source_git_repo.dir.to_str().unwrap().to_string(),
642 ]),
643 generate_repo_ref_event_with_git_server_with_keys(
644 vec![source_git_repo.dir.to_str().unwrap().to_string()],
645 &TEST_KEY_2_KEYS,
646 ),
647 ];
648 // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57)
649 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
650 Relay::new(8051, None, None),
651 Relay::new(8052, None, None),
652 Relay::new(8053, None, None),
653 Relay::new(8055, None, None),
654 Relay::new(8056, None, None),
655 Relay::new(8057, None, None),
656 ); 570 );
657 r51.events = events.clone(); 571 Ok(())
658 r55.events = events; 572 }
659 573
660 let cli_tester_handle = std::thread::spawn(move || -> Result<()> { 574 // POC Test 3: Verify commit ID was valid
661 let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?; 575 #[rstest]
662 p.send_line("push :refs/heads/vnext")?; 576 #[tokio::test]
663 p.send_line("")?; 577 #[serial]
664 p.expect_eventually("ok ")?; 578 async fn verify_commit_id_captured(#[future] scenario: DeleteBranchScenario) -> Result<()> {
665 p.expect("refs/heads/vnext\r\n")?; 579 let s = scenario.await;
666 p.expect_eventually("\r\n\r\n")?; 580 assert_eq!(
667 p.exit()?; 581 s.vnext_commit_id_str.len(),
668 for p in [51, 52, 53, 55, 56, 57] { 582 40,
669 relay::shutdown_relay(8000 + p)?; 583 "Should have valid commit SHA"
670 }
671 Ok(())
672 });
673 // launch relays
674 let _ = join!(
675 r51.listen_until_close(),
676 r52.listen_until_close(),
677 r53.listen_until_close(),
678 r55.listen_until_close(),
679 r56.listen_until_close(),
680 r57.listen_until_close(),
681 ); 584 );
682 cli_tester_handle.join().unwrap()?;
683 Ok(()) 585 Ok(())
684 } 586 }
685 587