diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2024-08-05 14:15:29 +0100 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2024-08-05 14:15:29 +0100 |
| commit | f238fc8c0a122487f4fb71bb78a2e365e147d747 (patch) | |
| tree | 5e8760c192f62fef67189bc82dcae4eef3ce883a /tests/git_remote_helper.rs | |
| parent | e5750b5b3dfe2c0072902c2523fdf32986aa74b8 (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/git_remote_helper.rs')
| -rw-r--r-- | tests/git_remote_helper.rs | 265 |
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 | ||
| 70 | fn 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 | |||
| 67 | async fn generate_repo_with_state_event() -> Result<(nostr::Event, GitTestRepo)> { | 80 | async 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 | ||