upleb.uk

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

summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2024-08-05 14:15:29 +0100
committerDanConwayDev <DanConwayDev@protonmail.com>2024-08-05 14:15:29 +0100
commitf238fc8c0a122487f4fb71bb78a2e365e147d747 (patch)
tree5e8760c192f62fef67189bc82dcae4eef3ce883a /tests
parente5750b5b3dfe2c0072902c2523fdf32986aa74b8 (diff)
feat(remote): `push` handle out-of-sync servers
1. don't attempt to push to a remote which is already up-to-date 2. don't attempt to delete branch on remote if it is already deleted 3. only push when out of sync if remote tip is ancestor of pushed commit 4. force push to remote if user force pushed and remote is in sync with nostr
Diffstat (limited to 'tests')
-rw-r--r--tests/git_remote_helper.rs265
1 files changed, 181 insertions, 84 deletions
diff --git a/tests/git_remote_helper.rs b/tests/git_remote_helper.rs
index 5a6c5f5..f2fa95f 100644
--- a/tests/git_remote_helper.rs
+++ b/tests/git_remote_helper.rs
@@ -64,6 +64,19 @@ fn cli_tester_after_fetch(git_repo: &GitTestRepo) -> Result<CliTester> {
64 Ok(p) 64 Ok(p)
65} 65}
66 66
67/// git runs `list for-push` before `push`. in `push` we use the git server
68/// remote refs downloaded by `list` to assess how to push to git servers.
69/// we are therefore running it this way in our tests
70fn cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(
71 git_repo: &GitTestRepo,
72) -> Result<CliTester> {
73 let mut p = cli_tester_after_fetch(git_repo)?;
74
75 p.send_line("list for-push")?;
76 p.expect_eventually_and_print("\r\n\r\n")?;
77 Ok(p)
78}
79
67async fn generate_repo_with_state_event() -> Result<(nostr::Event, GitTestRepo)> { 80async fn generate_repo_with_state_event() -> Result<(nostr::Event, GitTestRepo)> {
68 let git_repo = prep_git_repo()?; 81 let git_repo = prep_git_repo()?;
69 git_repo.create_branch("example-branch")?; 82 git_repo.create_branch("example-branch")?;
@@ -93,12 +106,11 @@ async fn generate_repo_with_state_event() -> Result<(nostr::Event, GitTestRepo)>
93 r55.events = events; 106 r55.events = events;
94 107
95 let cli_tester_handle = std::thread::spawn(move || -> Result<()> { 108 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
96 let mut p = cli_tester_after_fetch(&git_repo)?; 109 let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?;
97 p.send_line("push refs/heads/main:refs/heads/main")?; 110 p.send_line("push refs/heads/main:refs/heads/main")?;
98 p.send_line("")?; 111 p.send_line("")?;
99 p.expect("ok refs/heads/main\r\n")?; 112 // p.expect("ok refs/heads/main\r\n")?;
100 p.expect("\r\n")?; 113 p.expect_eventually_and_print("\r\n\r\n")?;
101
102 p.exit()?; 114 p.exit()?;
103 for p in [51, 52, 53, 55, 56, 57] { 115 for p in [51, 52, 53, 55, 56, 57] {
104 relay::shutdown_relay(8000 + p)?; 116 relay::shutdown_relay(8000 + p)?;
@@ -574,19 +586,12 @@ mod push {
574 586
575 use super::*; 587 use super::*;
576 588
577 /// git runs `list for-push` before `push`. in `push` we use the git server 589 #[tokio::test]
578 /// remote refs downloaded by `list` to assess how to push to git servers. 590 #[serial]
579 /// we are therefore running it this way in our tests 591 async fn new_branch_when_no_state_event_exists() -> Result<()> {
580 fn cli_tester_after_nostr_fetch_and_sent_list_for_push_responds( 592 generate_repo_with_state_event().await?;
581 git_repo: &GitTestRepo, 593 Ok(())
582 ) -> Result<CliTester> {
583 let mut p = cli_tester_after_fetch(git_repo)?;
584
585 p.send_line("list for-push")?;
586 p.expect_eventually_and_print("\r\n\r\n")?;
587 Ok(p)
588 } 594 }
589
590 mod two_branches_in_batch_one_added_one_updated { 595 mod two_branches_in_batch_one_added_one_updated {
591 596
592 use super::*; 597 use super::*;
@@ -861,7 +866,7 @@ mod push {
861 p.send_line("push refs/heads/main:refs/heads/main")?; 866 p.send_line("push refs/heads/main:refs/heads/main")?;
862 p.send_line("push refs/heads/vnext:refs/heads/vnext")?; 867 p.send_line("push refs/heads/vnext:refs/heads/vnext")?;
863 p.send_line("")?; 868 p.send_line("")?;
864 p.expect_eventually("\r\n\r\n")?; 869 p.expect_eventually_and_print("\r\n\r\n")?;
865 p.exit()?; 870 p.exit()?;
866 for p in [51, 52, 53, 55, 56, 57] { 871 for p in [51, 52, 53, 55, 56, 57] {
867 relay::shutdown_relay(8000 + p)?; 872 relay::shutdown_relay(8000 + p)?;
@@ -1073,7 +1078,7 @@ mod push {
1073 cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?; 1078 cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?;
1074 p.send_line("push :refs/heads/vnext")?; 1079 p.send_line("push :refs/heads/vnext")?;
1075 p.send_line("")?; 1080 p.send_line("")?;
1076 p.expect_eventually("\r\n\r\n")?; 1081 p.expect_eventually_and_print("\r\n\r\n")?;
1077 p.exit()?; 1082 p.exit()?;
1078 for p in [51, 52, 53, 55, 56, 57] { 1083 for p in [51, 52, 53, 55, 56, 57] {
1079 relay::shutdown_relay(8000 + p)?; 1084 relay::shutdown_relay(8000 + p)?;
@@ -1238,80 +1243,172 @@ mod push {
1238 Ok(()) 1243 Ok(())
1239 } 1244 }
1240 1245
1241 #[tokio::test] 1246 mod when_existing_state_event {
1242 #[serial] 1247 use super::*;
1243 async fn existing_state_event_updated_with_branch_deleted_and_ok_printed() -> Result<()> {
1244 let (state_event, source_git_repo) = generate_repo_with_state_event().await?;
1245 1248
1246 let git_repo = prep_git_repo()?; 1249 #[tokio::test]
1247 let main_commit_id = git_repo.get_tip_of_local_branch("main")?.to_string(); // same as example 1250 #[serial]
1251 async fn state_event_updated_and_branch_deleted_and_ok_printed() -> Result<()> {
1252 let (state_event, source_git_repo) = generate_repo_with_state_event().await?;
1248 1253
1249 let events = vec![ 1254 let git_repo = prep_git_repo()?;
1250 generate_test_key_1_metadata_event("fred"), 1255 let main_commit_id = git_repo.get_tip_of_local_branch("main")?.to_string(); // same as example
1251 generate_test_key_1_relay_list_event(),
1252 generate_repo_ref_event_with_git_server(vec![
1253 source_git_repo.dir.to_str().unwrap().to_string(),
1254 ]),
1255 state_event.clone(),
1256 ];
1257 1256
1258 // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57) 1257 let events = vec![
1259 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( 1258 generate_test_key_1_metadata_event("fred"),
1260 Relay::new(8051, None, None), 1259 generate_test_key_1_relay_list_event(),
1261 Relay::new(8052, None, None), 1260 generate_repo_ref_event_with_git_server(vec![
1262 Relay::new(8053, None, None), 1261 source_git_repo.dir.to_str().unwrap().to_string(),
1263 Relay::new(8055, None, None), 1262 ]),
1264 Relay::new(8056, None, None), 1263 state_event.clone(),
1265 Relay::new(8057, None, None), 1264 ];
1266 );
1267 r51.events = events.clone();
1268 r55.events = events;
1269 1265
1270 let cli_tester_handle = std::thread::spawn(move || -> Result<()> { 1266 // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57)
1271 let mut p = 1267 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
1272 cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?; 1268 Relay::new(8051, None, None),
1273 p.send_line("push :refs/heads/example-branch")?; 1269 Relay::new(8052, None, None),
1274 p.send_line("")?; 1270 Relay::new(8053, None, None),
1275 p.expect("ok refs/heads/example-branch\r\n")?; 1271 Relay::new(8055, None, None),
1276 p.expect("\r\n")?; 1272 Relay::new(8056, None, None),
1277 p.exit()?; 1273 Relay::new(8057, None, None),
1278 for p in [51, 52, 53, 55, 56, 57] { 1274 );
1279 relay::shutdown_relay(8000 + p)?; 1275 r51.events = events.clone();
1280 } 1276 r55.events = events;
1281 Ok(())
1282 });
1283 // launch relays
1284 let _ = join!(
1285 r51.listen_until_close(),
1286 r52.listen_until_close(),
1287 r53.listen_until_close(),
1288 r55.listen_until_close(),
1289 r56.listen_until_close(),
1290 r57.listen_until_close(),
1291 );
1292 1277
1293 cli_tester_handle.join().unwrap()?; 1278 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
1279 let mut p =
1280 cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(&git_repo)?;
1281 p.send_line("push :refs/heads/example-branch")?;
1282 p.send_line("")?;
1283 p.expect("ok refs/heads/example-branch\r\n")?;
1284 p.expect("\r\n")?;
1285 p.exit()?;
1286 for p in [51, 52, 53, 55, 56, 57] {
1287 relay::shutdown_relay(8000 + p)?;
1288 }
1289 Ok(())
1290 });
1291 // launch relays
1292 let _ = join!(
1293 r51.listen_until_close(),
1294 r52.listen_until_close(),
1295 r53.listen_until_close(),
1296 r55.listen_until_close(),
1297 r56.listen_until_close(),
1298 r57.listen_until_close(),
1299 );
1294 1300
1295 let state_event = r56 1301 cli_tester_handle.join().unwrap()?;
1296 .events
1297 .iter()
1298 .find(|e| e.kind().eq(&STATE_KIND))
1299 .context("state event not created")?;
1300 1302
1301 // println!("{:#?}", state_event); 1303 let state_event = r56
1302 assert_eq!( 1304 .events
1303 state_event
1304 .tags
1305 .iter() 1305 .iter()
1306 .filter(|t| t.kind().to_string().as_str().ne("d")) 1306 .find(|e| e.kind().eq(&STATE_KIND))
1307 .map(|t| t.as_vec().to_vec()) 1307 .context("state event not created")?;
1308 .collect::<HashSet<Vec<String>>>(), 1308
1309 HashSet::from([ 1309 // println!("{:#?}", state_event);
1310 vec!["HEAD".to_string(), "ref: refs/heads/main".to_string()], 1310 assert_eq!(
1311 vec!["refs/heads/main".to_string(), main_commit_id.to_string()], 1311 state_event
1312 ]), 1312 .tags
1313 ); 1313 .iter()
1314 Ok(()) 1314 .filter(|t| t.kind().to_string().as_str().ne("d"))
1315 .map(|t| t.as_vec().to_vec())
1316 .collect::<HashSet<Vec<String>>>(),
1317 HashSet::from([
1318 vec!["HEAD".to_string(), "ref: refs/heads/main".to_string()],
1319 vec!["refs/heads/main".to_string(), main_commit_id.to_string()],
1320 ]),
1321 );
1322 Ok(())
1323 }
1324
1325 mod already_deleted_on_git_server {
1326 use super::*;
1327
1328 #[tokio::test]
1329 #[serial]
1330 async fn existing_state_event_updated_and_ok_printed() -> Result<()> {
1331 let (state_event, source_git_repo) = generate_repo_with_state_event().await?;
1332
1333 {
1334 // delete branch on git server
1335 let tmp_repo = GitTestRepo::clone_repo(&source_git_repo)?;
1336 let mut remote = tmp_repo.git_repo.find_remote("origin")?;
1337 remote.push(&[":refs/heads/example-branch"], None)?;
1338 }
1339
1340 let git_repo = prep_git_repo()?;
1341 let main_commit_id = git_repo.get_tip_of_local_branch("main")?.to_string(); // same as example
1342
1343 let events = vec![
1344 generate_test_key_1_metadata_event("fred"),
1345 generate_test_key_1_relay_list_event(),
1346 generate_repo_ref_event_with_git_server(vec![
1347 source_git_repo.dir.to_str().unwrap().to_string(),
1348 ]),
1349 state_event.clone(),
1350 ];
1351
1352 // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57)
1353 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
1354 Relay::new(8051, None, None),
1355 Relay::new(8052, None, None),
1356 Relay::new(8053, None, None),
1357 Relay::new(8055, None, None),
1358 Relay::new(8056, None, None),
1359 Relay::new(8057, None, None),
1360 );
1361 r51.events = events.clone();
1362 r55.events = events;
1363
1364 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
1365 let mut p = cli_tester_after_nostr_fetch_and_sent_list_for_push_responds(
1366 &git_repo,
1367 )?;
1368 p.send_line("push :refs/heads/example-branch")?;
1369 p.send_line("")?;
1370 p.expect("ok refs/heads/example-branch\r\n")?;
1371 p.expect("\r\n")?;
1372 p.exit()?;
1373 for p in [51, 52, 53, 55, 56, 57] {
1374 relay::shutdown_relay(8000 + p)?;
1375 }
1376 Ok(())
1377 });
1378 // launch relays
1379 let _ = join!(
1380 r51.listen_until_close(),
1381 r52.listen_until_close(),
1382 r53.listen_until_close(),
1383 r55.listen_until_close(),
1384 r56.listen_until_close(),
1385 r57.listen_until_close(),
1386 );
1387
1388 cli_tester_handle.join().unwrap()?;
1389
1390 let state_event = r56
1391 .events
1392 .iter()
1393 .find(|e| e.kind().eq(&STATE_KIND))
1394 .context("state event not created")?;
1395
1396 // println!("{:#?}", state_event);
1397 assert_eq!(
1398 state_event
1399 .tags
1400 .iter()
1401 .filter(|t| t.kind().to_string().as_str().ne("d"))
1402 .map(|t| t.as_vec().to_vec())
1403 .collect::<HashSet<Vec<String>>>(),
1404 HashSet::from([
1405 vec!["HEAD".to_string(), "ref: refs/heads/main".to_string()],
1406 vec!["refs/heads/main".to_string(), main_commit_id.to_string()],
1407 ]),
1408 );
1409 Ok(())
1410 }
1411 }
1315 } 1412 }
1316 } 1413 }
1317 1414