upleb.uk

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

summaryrefslogtreecommitdiff
path: root/tests/prs_create.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/prs_create.rs')
-rw-r--r--tests/prs_create.rs1131
1 files changed, 0 insertions, 1131 deletions
diff --git a/tests/prs_create.rs b/tests/prs_create.rs
deleted file mode 100644
index 5d55ab9..0000000
--- a/tests/prs_create.rs
+++ /dev/null
@@ -1,1131 +0,0 @@
1use anyhow::Result;
2use futures::join;
3use serial_test::serial;
4use test_utils::{git::GitTestRepo, relay::Relay, *};
5
6#[test]
7fn when_to_branch_doesnt_exist_return_error() -> Result<()> {
8 let test_repo = GitTestRepo::default();
9 test_repo.populate()?;
10 let mut p = CliTester::new_from_dir(
11 &test_repo.dir,
12 ["prs", "create", "--to-branch", "nonexistant"],
13 );
14 p.expect("Error: cannot find to_branch 'nonexistant'")?;
15 Ok(())
16}
17
18#[test]
19fn when_no_to_branch_specified_and_no_main_or_master_branch_return_error() -> Result<()> {
20 let test_repo = GitTestRepo::new("notmain")?;
21 test_repo.populate()?;
22 let mut p = CliTester::new_from_dir(&test_repo.dir, ["prs", "create"]);
23 p.expect("Error: a destination branch (to_branch) is not specified and the defaults (main or master) do not exist")?;
24 Ok(())
25}
26
27#[test]
28fn when_from_branch_doesnt_exist_return_error() -> Result<()> {
29 let test_repo = GitTestRepo::default();
30 test_repo.populate()?;
31 let mut p = CliTester::new_from_dir(
32 &test_repo.dir,
33 ["prs", "create", "--from-branch", "nonexistant"],
34 );
35 p.expect("Error: cannot find from_branch 'nonexistant'")?;
36 Ok(())
37}
38
39#[test]
40fn when_no_commits_ahead_of_main_return_error() -> Result<()> {
41 let test_repo = GitTestRepo::default();
42 test_repo.populate()?;
43 // create feature branch with 1 commit ahead
44 test_repo.create_branch("feature")?;
45 test_repo.checkout("feature")?;
46
47 let mut p = CliTester::new_from_dir(&test_repo.dir, ["prs", "create"]);
48 p.expect("Error: 'head' is 0 commits ahead of 'main' so no patches were created")?;
49 Ok(())
50}
51
52mod when_commits_behind_ask_to_proceed {
53 use super::*;
54
55 fn prep_test_repo() -> Result<GitTestRepo> {
56 let test_repo = GitTestRepo::default();
57 test_repo.populate()?;
58 // create feature branch with 2 commit ahead
59 test_repo.create_branch("feature")?;
60 test_repo.checkout("feature")?;
61 std::fs::write(test_repo.dir.join("t3.md"), "some content")?;
62 test_repo.stage_and_commit("add t3.md")?;
63 std::fs::write(test_repo.dir.join("t4.md"), "some content")?;
64 test_repo.stage_and_commit("add t4.md")?;
65 // checkout main and add 1 commit
66 test_repo.checkout("main")?;
67 std::fs::write(test_repo.dir.join("t5.md"), "some content")?;
68 test_repo.stage_and_commit("add t5.md")?;
69 // checkout feature branch
70 test_repo.checkout("feature")?;
71 Ok(test_repo)
72 }
73 static BEHIND_LEN: u8 = 1;
74 static AHEAD_LEN: u8 = 2;
75
76 fn expect_confirm_prompt(
77 p: &mut CliTester,
78 behind: u8,
79 ahead: u8,
80 ) -> Result<CliTesterConfirmPrompt> {
81 p.expect_confirm(
82 format!("'head' is {behind} commits behind 'main' and {ahead} ahead. Consider rebasing before sending patches. Proceed anyway?").as_str(),
83 Some(false),
84 )
85 }
86
87 #[test]
88 fn asked_with_default_no() -> Result<()> {
89 let test_repo = prep_test_repo()?;
90
91 let mut p = CliTester::new_from_dir(&test_repo.dir, ["prs", "create"]);
92 expect_confirm_prompt(&mut p, BEHIND_LEN, AHEAD_LEN)?;
93 p.exit()?;
94 Ok(())
95 }
96
97 #[test]
98 fn when_response_is_false_aborts() -> Result<()> {
99 let test_repo = prep_test_repo()?;
100
101 let mut p = CliTester::new_from_dir(&test_repo.dir, ["prs", "create"]);
102
103 expect_confirm_prompt(&mut p, BEHIND_LEN, AHEAD_LEN)?.succeeds_with(Some(false))?;
104
105 p.expect_end_with("Error: aborting so branch can be rebased\r\n")?;
106
107 Ok(())
108 }
109 #[test]
110 #[serial]
111 fn when_response_is_true_proceeds() -> Result<()> {
112 let test_repo = prep_test_repo()?;
113
114 let mut p = CliTester::new_from_dir(&test_repo.dir, ["prs", "create"]);
115 expect_confirm_prompt(&mut p, BEHIND_LEN, AHEAD_LEN)?.succeeds_with(Some(true))?;
116 p.expect(
117 format!("creating patch for {AHEAD_LEN} commits from 'head' that are {BEHIND_LEN} behind 'main'",)
118 .as_str(),
119 )?;
120 p.exit()?;
121 Ok(())
122 }
123}
124
125#[test]
126#[serial]
127fn cli_message_creating_patches() -> Result<()> {
128 let test_repo = GitTestRepo::default();
129 test_repo.populate()?;
130 // create feature branch with 2 commit ahead
131 test_repo.create_branch("feature")?;
132 test_repo.checkout("feature")?;
133 std::fs::write(test_repo.dir.join("t3.md"), "some content")?;
134 test_repo.stage_and_commit("add t3.md")?;
135 std::fs::write(test_repo.dir.join("t4.md"), "some content")?;
136 test_repo.stage_and_commit("add t4.md")?;
137
138 let mut p = CliTester::new_from_dir(&test_repo.dir, ["prs", "create"]);
139
140 p.expect("creating patch for 2 commits from 'head' that can be merged into 'main'")?;
141 p.exit()?;
142 Ok(())
143}
144
145fn is_cover_letter(event: &nostr::Event) -> bool {
146 event.kind.as_u64().eq(&PATCH_KIND)
147 && event.iter_tags().any(|t| t.as_vec()[1].eq("cover-letter"))
148}
149
150fn is_patch(event: &nostr::Event) -> bool {
151 event.kind.as_u64().eq(&PATCH_KIND)
152 && !event.iter_tags().any(|t| t.as_vec()[1].eq("cover-letter"))
153}
154
155fn prep_git_repo() -> Result<GitTestRepo> {
156 let test_repo = GitTestRepo::default();
157 test_repo.populate()?;
158 // create feature branch with 2 commit ahead
159 test_repo.create_branch("feature")?;
160 test_repo.checkout("feature")?;
161 std::fs::write(test_repo.dir.join("t3.md"), "some content")?;
162 test_repo.stage_and_commit("add t3.md")?;
163 std::fs::write(test_repo.dir.join("t4.md"), "some content")?;
164 test_repo.stage_and_commit("add t4.md")?;
165 Ok(test_repo)
166}
167
168fn cli_tester_create_pr(git_repo: &GitTestRepo, include_cover_letter: bool) -> CliTester {
169 let mut args = vec![
170 "--nsec",
171 TEST_KEY_1_NSEC,
172 "--password",
173 TEST_PASSWORD,
174 "--disable-cli-spinners",
175 "prs",
176 "create",
177 ];
178 if include_cover_letter {
179 for arg in [
180 "--title",
181 "exampletitle",
182 "--description",
183 "exampledescription",
184 ] {
185 args.push(arg);
186 }
187 } else {
188 args.push("--no-cover-letter");
189 }
190 CliTester::new_from_dir(&git_repo.dir, args)
191}
192
193fn expect_msgs_first(p: &mut CliTester, include_cover_letter: bool) -> Result<()> {
194 p.expect("creating patch for 2 commits from 'head' that can be merged into 'main'\r\n")?;
195 p.expect("searching for your details...\r\n")?;
196 p.expect("\r")?;
197 p.expect("logged in as fred\r\n")?;
198 p.expect(format!(
199 "posting 2 patches {} a covering letter...\r\n",
200 if include_cover_letter {
201 "with"
202 } else {
203 "without"
204 }
205 ))?;
206 Ok(())
207}
208
209async fn prep_run_create_pr(
210 include_cover_letter: bool,
211) -> Result<(
212 Relay<'static>,
213 Relay<'static>,
214 Relay<'static>,
215 Relay<'static>,
216 Relay<'static>,
217)> {
218 let git_repo = prep_git_repo()?;
219 // fallback (51,52) user write (53, 55) repo (55, 56)
220 let (mut r51, mut r52, mut r53, mut r55, mut r56) = (
221 Relay::new(
222 8051,
223 None,
224 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
225 relay.respond_events(
226 client_id,
227 &subscription_id,
228 &vec![
229 generate_test_key_1_metadata_event("fred"),
230 generate_test_key_1_relay_list_event(),
231 ],
232 )?;
233 Ok(())
234 }),
235 ),
236 Relay::new(8052, None, None),
237 Relay::new(8053, None, None),
238 Relay::new(
239 8055,
240 None,
241 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
242 relay.respond_events(
243 client_id,
244 &subscription_id,
245 &vec![generate_repo_ref_event()],
246 )?;
247 Ok(())
248 }),
249 ),
250 Relay::new(8056, None, None),
251 );
252
253 // // check relay had the right number of events
254 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
255 let mut p = cli_tester_create_pr(&git_repo, include_cover_letter);
256 p.expect_end_eventually()?;
257 for p in [51, 52, 53, 55, 56] {
258 relay::shutdown_relay(8000 + p)?;
259 }
260 Ok(())
261 });
262
263 // launch relay
264 let _ = join!(
265 r51.listen_until_close(),
266 r52.listen_until_close(),
267 r53.listen_until_close(),
268 r55.listen_until_close(),
269 r56.listen_until_close(),
270 );
271 cli_tester_handle.join().unwrap()?;
272 Ok((r51, r52, r53, r55, r56))
273}
274
275mod sends_cover_letter_and_2_patches_to_3_relays {
276
277 use super::*;
278 #[tokio::test]
279 #[serial]
280 async fn only_1_pr_kind_event_sent_to_each_relay() -> Result<()> {
281 let (_, _, r53, r55, r56) = prep_run_create_pr(true).await?;
282 for relay in [&r53, &r55, &r56] {
283 assert_eq!(
284 relay.events.iter().filter(|e| is_cover_letter(e)).count(),
285 1,
286 );
287 }
288 Ok(())
289 }
290
291 #[tokio::test]
292 #[serial]
293 async fn only_1_pr_kind_event_sent_to_user_relays() -> Result<()> {
294 let (_, _, r53, r55, _) = prep_run_create_pr(true).await?;
295 for relay in [&r53, &r55] {
296 assert_eq!(
297 relay.events.iter().filter(|e| is_cover_letter(e)).count(),
298 1,
299 );
300 }
301 Ok(())
302 }
303
304 #[tokio::test]
305 #[serial]
306 async fn only_1_pr_kind_event_sent_to_repo_relays() -> Result<()> {
307 let (_, _, _, r55, r56) = prep_run_create_pr(true).await?;
308 for relay in [&r55, &r56] {
309 assert_eq!(
310 relay.events.iter().filter(|e| is_cover_letter(e)).count(),
311 1
312 );
313 }
314 Ok(())
315 }
316
317 #[tokio::test]
318 #[serial]
319 async fn pr_not_sent_to_fallback_relay() -> Result<()> {
320 let (r51, r52, _, _, _) = prep_run_create_pr(true).await?;
321 for relay in [&r51, &r52] {
322 assert_eq!(
323 relay.events.iter().filter(|e| is_cover_letter(e)).count(),
324 0,
325 );
326 }
327 Ok(())
328 }
329
330 #[tokio::test]
331 #[serial]
332 async fn only_2_patch_kind_events_sent_to_each_relay() -> Result<()> {
333 let (_, _, r53, r55, r56) = prep_run_create_pr(true).await?;
334 for relay in [&r53, &r55, &r56] {
335 assert_eq!(relay.events.iter().filter(|e| is_patch(e)).count(), 2,);
336 }
337 Ok(())
338 }
339
340 #[tokio::test]
341 #[serial]
342 async fn patch_content_contains_patch_in_email_format_with_patch_series_numbers() -> Result<()>
343 {
344 let (_, _, r53, r55, r56) = prep_run_create_pr(true).await?;
345 for relay in [&r53, &r55, &r56] {
346 let patch_events: Vec<&nostr::Event> =
347 relay.events.iter().filter(|e| is_patch(e)).collect();
348
349 assert_eq!(
350 patch_events[1].content,
351 "\
352 From fe973a840fba2a8ab37dd505c154854a69a6505c Mon Sep 17 00:00:00 2001\n\
353 From: Joe Bloggs <joe.bloggs@pm.me>\n\
354 Date: Thu, 1 Jan 1970 00:00:00 +0000\n\
355 Subject: [PATCH 2/2] add t4.md\n\
356 \n\
357 ---\n \
358 t4.md | 1 +\n \
359 1 file changed, 1 insertion(+)\n \
360 create mode 100644 t4.md\n\
361 \n\
362 diff --git a/t4.md b/t4.md\n\
363 new file mode 100644\n\
364 index 0000000..f0eec86\n\
365 --- /dev/null\n\
366 +++ b/t4.md\n\
367 @@ -0,0 +1 @@\n\
368 +some content\n\\ \
369 No newline at end of file\n\
370 --\n\
371 libgit2 1.7.1\n\
372 \n\
373 ",
374 );
375 assert_eq!(
376 patch_events[0].content,
377 "\
378 From 232efb37ebc67692c9e9ff58b83c0d3d63971a0a Mon Sep 17 00:00:00 2001\n\
379 From: Joe Bloggs <joe.bloggs@pm.me>\n\
380 Date: Thu, 1 Jan 1970 00:00:00 +0000\n\
381 Subject: [PATCH 1/2] add t3.md\n\
382 \n\
383 ---\n \
384 t3.md | 1 +\n \
385 1 file changed, 1 insertion(+)\n \
386 create mode 100644 t3.md\n\
387 \n\
388 diff --git a/t3.md b/t3.md\n\
389 new file mode 100644\n\
390 index 0000000..f0eec86\n\
391 --- /dev/null\n\
392 +++ b/t3.md\n\
393 @@ -0,0 +1 @@\n\
394 +some content\n\\ \
395 No newline at end of file\n\
396 --\n\
397 libgit2 1.7.1\n\
398 \n\
399 ",
400 );
401 }
402 Ok(())
403 }
404
405 mod pr_tags {
406 use super::*;
407
408 #[tokio::test]
409 #[serial]
410 async fn root_commit_as_r() -> Result<()> {
411 let (_, _, r53, r55, r56) = prep_run_create_pr(true).await?;
412 for relay in [&r53, &r55, &r56] {
413 let pr_event: &nostr::Event =
414 relay.events.iter().find(|e| is_cover_letter(e)).unwrap();
415
416 assert_eq!(
417 pr_event
418 .iter_tags()
419 .find(|t| t.as_vec()[0].eq("r"))
420 .unwrap()
421 .as_vec()[1],
422 "9ee507fc4357d7ee16a5d8901bedcd103f23c17d"
423 );
424 }
425 Ok(())
426 }
427
428 #[tokio::test]
429 #[serial]
430 async fn a_tag_for_repo_event() -> Result<()> {
431 let (_, _, r53, r55, r56) = prep_run_create_pr(true).await?;
432 for relay in [&r53, &r55, &r56] {
433 let pr_event: &nostr::Event =
434 relay.events.iter().find(|e| is_cover_letter(e)).unwrap();
435 assert!(pr_event.iter_tags().any(|t| t.as_vec()[0].eq("a")
436 && t.as_vec()[1].eq(&format!(
437 "{REPOSITORY_KIND}:{TEST_KEY_1_PUBKEY_HEX}:{}",
438 generate_repo_ref_event().identifier().unwrap()
439 ))));
440 }
441 Ok(())
442 }
443
444 #[tokio::test]
445 #[serial]
446 async fn p_tags_for_maintainers() -> Result<()> {
447 let maintainers = &generate_repo_ref_event()
448 .iter_tags()
449 .find(|t| t.as_vec()[0].eq(&"maintainers"))
450 .unwrap()
451 .as_vec()
452 .clone()[1..];
453 let (_, _, r53, r55, r56) = prep_run_create_pr(true).await?;
454 for relay in [&r53, &r55, &r56] {
455 for m in maintainers {
456 let pr_event: &nostr::Event =
457 relay.events.iter().find(|e| is_cover_letter(e)).unwrap();
458 assert!(
459 pr_event
460 .iter_tags()
461 .any(|t| { t.as_vec()[0].eq("p") && t.as_vec()[1].eq(m) })
462 );
463 }
464 }
465 Ok(())
466 }
467
468 #[tokio::test]
469 #[serial]
470 async fn t_tag_cover_letter() -> Result<()> {
471 let (_, _, r53, r55, r56) = prep_run_create_pr(true).await?;
472 for relay in [&r53, &r55, &r56] {
473 let pr_event: &nostr::Event =
474 relay.events.iter().find(|e| is_cover_letter(e)).unwrap();
475 assert!(
476 pr_event
477 .iter_tags()
478 .any(|t| { t.as_vec()[0].eq("t") && t.as_vec()[1].eq(&"cover-letter") })
479 );
480 }
481 Ok(())
482 }
483
484 #[tokio::test]
485 #[serial]
486 async fn t_tag_root() -> Result<()> {
487 let (_, _, r53, r55, r56) = prep_run_create_pr(true).await?;
488 for relay in [&r53, &r55, &r56] {
489 let pr_event: &nostr::Event =
490 relay.events.iter().find(|e| is_cover_letter(e)).unwrap();
491 assert!(
492 pr_event
493 .iter_tags()
494 .any(|t| { t.as_vec()[0].eq("t") && t.as_vec()[1].eq(&"root") })
495 );
496 }
497 Ok(())
498 }
499
500 #[tokio::test]
501 #[serial]
502 async fn pr_tags_branch_name() -> Result<()> {
503 let (_, _, r53, r55, r56) = prep_run_create_pr(true).await?;
504 for relay in [&r53, &r55, &r56] {
505 let pr_event: &nostr::Event =
506 relay.events.iter().find(|e| is_cover_letter(e)).unwrap();
507
508 // branch-name tag
509 assert_eq!(
510 pr_event
511 .iter_tags()
512 .find(|t| t.as_vec()[0].eq("branch-name"))
513 .unwrap()
514 .as_vec()[1],
515 "feature"
516 );
517 }
518 Ok(())
519 }
520 }
521
522 mod patch_tags {
523 use super::*;
524
525 async fn prep() -> Result<nostr::Event> {
526 let (_, _, r53, _, _) = prep_run_create_pr(true).await?;
527 Ok(r53.events.iter().find(|e| is_patch(e)).unwrap().clone())
528 }
529
530 #[tokio::test]
531 #[serial]
532 async fn commit_and_commit_r() -> Result<()> {
533 static COMMIT_ID: &str = "232efb37ebc67692c9e9ff58b83c0d3d63971a0a";
534 let most_recent_patch = prep().await?;
535 assert!(
536 most_recent_patch
537 .tags
538 .iter()
539 .any(|t| t.as_vec()[0].eq("r") && t.as_vec()[1].eq(COMMIT_ID))
540 );
541 assert!(
542 most_recent_patch
543 .tags
544 .iter()
545 .any(|t| t.as_vec()[0].eq("commit") && t.as_vec()[1].eq(COMMIT_ID))
546 );
547 Ok(())
548 }
549
550 #[tokio::test]
551 #[serial]
552 async fn parent_commit() -> Result<()> {
553 // commit parent 'r' and 'parent-commit' tag
554 static COMMIT_PARENT_ID: &str = "431b84edc0d2fa118d63faa3c2db9c73d630a5ae";
555 let most_recent_patch = prep().await?;
556 assert_eq!(
557 most_recent_patch
558 .tags
559 .iter()
560 .find(|t| t.as_vec()[0].eq("parent-commit"))
561 .unwrap()
562 .as_vec()[1],
563 COMMIT_PARENT_ID,
564 );
565 Ok(())
566 }
567
568 #[tokio::test]
569 #[serial]
570 async fn root_commit_as_r() -> Result<()> {
571 assert!(prep().await?.tags.iter().any(|t| t.as_vec()[0].eq("r")
572 && t.as_vec()[1].eq("9ee507fc4357d7ee16a5d8901bedcd103f23c17d")));
573 Ok(())
574 }
575
576 #[tokio::test]
577 #[serial]
578 async fn p_tags_for_maintainers() -> Result<()> {
579 let maintainers = &generate_repo_ref_event()
580 .iter_tags()
581 .find(|t| t.as_vec()[0].eq(&"maintainers"))
582 .unwrap()
583 .as_vec()
584 .clone()[1..];
585 for m in maintainers {
586 assert!(
587 prep()
588 .await?
589 .iter_tags()
590 .any(|t| { t.as_vec()[0].eq("p") && t.as_vec()[1].eq(m) })
591 );
592 }
593 Ok(())
594 }
595
596 #[tokio::test]
597 #[serial]
598 async fn a_tag_for_repo_event() -> Result<()> {
599 assert!(prep().await?.tags.iter().any(|t| {
600 t.as_vec()[0].eq("a")
601 && t.as_vec()[1].eq(&format!(
602 "{REPOSITORY_KIND}:{TEST_KEY_1_PUBKEY_HEX}:{}",
603 generate_repo_ref_event().identifier().unwrap()
604 ))
605 }));
606 Ok(())
607 }
608
609 #[tokio::test]
610 #[serial]
611 async fn description_with_commit_message() -> Result<()> {
612 assert_eq!(
613 prep()
614 .await?
615 .tags
616 .iter()
617 .find(|t| t.as_vec()[0].eq("description"))
618 .unwrap()
619 .as_vec()[1],
620 "add t3.md"
621 );
622 Ok(())
623 }
624
625 #[tokio::test]
626 #[serial]
627 async fn commit_author() -> Result<()> {
628 assert_eq!(
629 prep()
630 .await?
631 .tags
632 .iter()
633 .find(|t| t.as_vec()[0].eq("author"))
634 .unwrap()
635 .as_vec(),
636 vec!["author", "Joe Bloggs", "joe.bloggs@pm.me", "0", "0"],
637 );
638 Ok(())
639 }
640
641 #[tokio::test]
642 #[serial]
643 async fn commit_committer() -> Result<()> {
644 assert_eq!(
645 prep()
646 .await?
647 .tags
648 .iter()
649 .find(|t| t.as_vec()[0].eq("committer"))
650 .unwrap()
651 .as_vec(),
652 vec!["committer", "Joe Bloggs", "joe.bloggs@pm.me", "0", "0"],
653 );
654 Ok(())
655 }
656
657 #[tokio::test]
658 #[serial]
659 async fn patch_tags_pr_event_as_root() -> Result<()> {
660 let (_, _, r53, r55, r56) = prep_run_create_pr(true).await?;
661 for relay in [&r53, &r55, &r56] {
662 let patch_events: Vec<&nostr::Event> =
663 relay.events.iter().filter(|e| is_patch(e)).collect();
664
665 let most_recent_patch = patch_events[0];
666 let pr_event = relay.events.iter().find(|e| is_cover_letter(e)).unwrap();
667
668 let root_event_tag = most_recent_patch
669 .tags
670 .iter()
671 .find(|t| {
672 t.as_vec()[0].eq("e") && t.as_vec().len().eq(&4) && t.as_vec()[3].eq("root")
673 })
674 .unwrap();
675
676 assert_eq!(root_event_tag.as_vec()[1], pr_event.id.to_string());
677 }
678 Ok(())
679 }
680
681 #[tokio::test]
682 #[serial]
683 async fn second_patch_tags_first_with_reply() -> Result<()> {
684 let (_, _, r53, r55, r56) = prep_run_create_pr(true).await?;
685 for relay in [&r53, &r55, &r56] {
686 let patch_events = relay
687 .events
688 .iter()
689 .filter(|e| is_patch(e))
690 .collect::<Vec<&nostr::Event>>();
691 assert_eq!(
692 patch_events[1]
693 .iter_tags()
694 .find(|t| t.as_vec()[0].eq("e")
695 && t.as_vec().len().eq(&4)
696 && t.as_vec()[3].eq("reply"))
697 .unwrap()
698 .as_vec()[1],
699 patch_events[0].id.to_string(),
700 );
701 }
702 Ok(())
703 }
704
705 #[tokio::test]
706 #[serial]
707 async fn no_t_root_tag() -> Result<()> {
708 assert!(
709 !prep()
710 .await?
711 .tags
712 .iter()
713 .any(|t| t.as_vec()[0].eq("t") && t.as_vec()[1].eq("root"))
714 );
715 Ok(())
716 }
717 }
718 mod cli_ouput {
719 use super::*;
720
721 async fn run_test_async() -> Result<()> {
722 let git_repo = prep_git_repo()?;
723
724 let (mut r51, mut r52, mut r53, mut r55, mut r56) = (
725 Relay::new(
726 8051,
727 None,
728 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
729 relay.respond_events(
730 client_id,
731 &subscription_id,
732 &vec![
733 generate_test_key_1_metadata_event("fred"),
734 generate_test_key_1_relay_list_event(),
735 ],
736 )?;
737 Ok(())
738 }),
739 ),
740 Relay::new(8052, None, None),
741 Relay::new(8053, None, None),
742 Relay::new(
743 8055,
744 None,
745 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
746 relay.respond_events(
747 client_id,
748 &subscription_id,
749 &vec![generate_repo_ref_event()],
750 )?;
751 Ok(())
752 }),
753 ),
754 Relay::new(8056, None, None),
755 );
756
757 // // check relay had the right number of events
758 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
759 let mut p = cli_tester_create_pr(&git_repo, true);
760 expect_msgs_first(&mut p, true)?;
761 relay::expect_send_with_progress(
762 &mut p,
763 vec![
764 (" [my-relay] [repo-relay] ws://localhost:8055", true, ""),
765 (" [my-relay] ws://localhost:8053", true, ""),
766 (" [repo-relay] ws://localhost:8056", true, ""),
767 ],
768 3,
769 )?;
770 p.expect_end_with_whitespace()?;
771 for p in [51, 52, 53, 55, 56] {
772 relay::shutdown_relay(8000 + p)?;
773 }
774 Ok(())
775 });
776
777 // launch relay
778 let _ = join!(
779 r51.listen_until_close(),
780 r52.listen_until_close(),
781 r53.listen_until_close(),
782 r55.listen_until_close(),
783 r56.listen_until_close(),
784 );
785 cli_tester_handle.join().unwrap()?;
786 Ok(())
787 }
788
789 #[tokio::test]
790 #[serial]
791 async fn check_cli_output() -> Result<()> {
792 run_test_async().await?;
793 Ok(())
794 }
795 }
796
797 mod first_event_rejected_by_1_relay {
798 use super::*;
799
800 mod only_first_rejected_event_sent_to_relay {
801 use super::*;
802
803 async fn run_test_async() -> Result<()> {
804 let git_repo = prep_git_repo()?;
805
806 let (mut r51, mut r52, mut r53, mut r55, mut r56) = (
807 Relay::new(
808 8051,
809 None,
810 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
811 relay.respond_events(
812 client_id,
813 &subscription_id,
814 &vec![
815 generate_test_key_1_metadata_event("fred"),
816 generate_test_key_1_relay_list_event(),
817 ],
818 )?;
819 Ok(())
820 }),
821 ),
822 Relay::new(8052, None, None),
823 Relay::new(8053, None, None),
824 Relay::new(
825 8055,
826 None,
827 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
828 relay.respond_events(
829 client_id,
830 &subscription_id,
831 &vec![generate_repo_ref_event()],
832 )?;
833 Ok(())
834 }),
835 ),
836 Relay::new(
837 8056,
838 Some(&|relay, client_id, event| -> Result<()> {
839 relay.respond_ok(client_id, event, Some("Payment Required"))?;
840 Ok(())
841 }),
842 None,
843 ),
844 );
845
846 // // check relay had the right number of events
847 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
848 let mut p = cli_tester_create_pr(&git_repo, true);
849 p.expect_end_eventually()?;
850 for p in [51, 52, 53, 55, 56] {
851 relay::shutdown_relay(8000 + p)?;
852 }
853 Ok(())
854 });
855
856 // launch relay
857 let _ = join!(
858 r51.listen_until_close(),
859 r52.listen_until_close(),
860 r53.listen_until_close(),
861 r55.listen_until_close(),
862 r56.listen_until_close(),
863 );
864 cli_tester_handle.join().unwrap()?;
865
866 assert_eq!(r56.events.len(), 1);
867
868 Ok(())
869 }
870
871 #[tokio::test]
872 #[serial]
873 async fn only_first_rejected_event_sent_to_relay() -> Result<()> {
874 run_test_async().await?;
875 Ok(())
876 }
877 }
878
879 mod cli_show_rejection_with_comment {
880 use super::*;
881
882 async fn run_test_async() -> Result<(Relay<'static>, Relay<'static>, Relay<'static>)> {
883 let git_repo = prep_git_repo()?;
884
885 let (mut r51, mut r52, mut r53, mut r55, mut r56) = (
886 Relay::new(
887 8051,
888 None,
889 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
890 relay.respond_events(
891 client_id,
892 &subscription_id,
893 &vec![
894 generate_test_key_1_metadata_event("fred"),
895 generate_test_key_1_relay_list_event(),
896 ],
897 )?;
898 Ok(())
899 }),
900 ),
901 Relay::new(8052, None, None),
902 Relay::new(8053, None, None),
903 Relay::new(
904 8055,
905 None,
906 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
907 relay.respond_events(
908 client_id,
909 &subscription_id,
910 &vec![generate_repo_ref_event()],
911 )?;
912 Ok(())
913 }),
914 ),
915 Relay::new(
916 8056,
917 Some(&|relay, client_id, event| -> Result<()> {
918 relay.respond_ok(client_id, event, Some("Payment Required"))?;
919 Ok(())
920 }),
921 None,
922 ),
923 );
924
925 // // check relay had the right number of events
926 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
927 let mut p = cli_tester_create_pr(&git_repo, true);
928 expect_msgs_first(&mut p, true)?;
929 // p.expect_end_with("bla")?;
930 relay::expect_send_with_progress(
931 &mut p,
932 vec![
933 (" [my-relay] [repo-relay] ws://localhost:8055", true, ""),
934 (" [my-relay] ws://localhost:8053", true, ""),
935 (
936 " [repo-relay] ws://localhost:8056",
937 false,
938 "error: Payment Required",
939 ),
940 ],
941 3,
942 )?;
943 p.expect_end_with_whitespace()?;
944 for p in [51, 52, 53, 55, 56] {
945 relay::shutdown_relay(8000 + p)?;
946 }
947
948 Ok(())
949 });
950
951 // launch relay
952 let _ = join!(
953 r51.listen_until_close(),
954 r52.listen_until_close(),
955 r53.listen_until_close(),
956 r55.listen_until_close(),
957 r56.listen_until_close(),
958 );
959 cli_tester_handle.join().unwrap()?;
960 Ok((r51, r52, r53))
961 }
962
963 #[tokio::test]
964 #[serial]
965 async fn cli_show_rejection_with_comment() -> Result<()> {
966 run_test_async().await?;
967 Ok(())
968 }
969 }
970 }
971}
972
973mod sends_2_patches_without_cover_letter {
974 use super::*;
975
976 mod cli_ouput {
977 use super::*;
978
979 async fn run_test_async() -> Result<()> {
980 let git_repo = prep_git_repo()?;
981
982 let (mut r51, mut r52, mut r53, mut r55, mut r56) = (
983 Relay::new(
984 8051,
985 None,
986 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
987 relay.respond_events(
988 client_id,
989 &subscription_id,
990 &vec![
991 generate_test_key_1_metadata_event("fred"),
992 generate_test_key_1_relay_list_event(),
993 ],
994 )?;
995 Ok(())
996 }),
997 ),
998 Relay::new(8052, None, None),
999 Relay::new(8053, None, None),
1000 Relay::new(
1001 8055,
1002 None,
1003 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
1004 relay.respond_events(
1005 client_id,
1006 &subscription_id,
1007 &vec![generate_repo_ref_event()],
1008 )?;
1009 Ok(())
1010 }),
1011 ),
1012 Relay::new(8056, None, None),
1013 );
1014
1015 // // check relay had the right number of events
1016 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
1017 let mut p = cli_tester_create_pr(&git_repo, false);
1018
1019 expect_msgs_first(&mut p, false)?;
1020 relay::expect_send_with_progress(
1021 &mut p,
1022 vec![
1023 (" [my-relay] [repo-relay] ws://localhost:8055", true, ""),
1024 (" [my-relay] ws://localhost:8053", true, ""),
1025 (" [repo-relay] ws://localhost:8056", true, ""),
1026 ],
1027 2,
1028 )?;
1029 p.expect_end_with_whitespace()?;
1030 for p in [51, 52, 53, 55, 56] {
1031 relay::shutdown_relay(8000 + p)?;
1032 }
1033 Ok(())
1034 });
1035
1036 // launch relay
1037 let _ = join!(
1038 r51.listen_until_close(),
1039 r52.listen_until_close(),
1040 r53.listen_until_close(),
1041 r55.listen_until_close(),
1042 r56.listen_until_close(),
1043 );
1044 cli_tester_handle.join().unwrap()?;
1045 Ok(())
1046 }
1047
1048 #[tokio::test]
1049 #[serial]
1050 async fn check_cli_output() -> Result<()> {
1051 run_test_async().await?;
1052 Ok(())
1053 }
1054 }
1055
1056 #[tokio::test]
1057 #[serial]
1058 async fn no_cover_letter_event() -> Result<()> {
1059 let (_, _, r53, r55, r56) = prep_run_create_pr(false).await?;
1060 for relay in [&r53, &r55, &r56] {
1061 assert_eq!(
1062 relay.events.iter().filter(|e| is_cover_letter(e)).count(),
1063 0,
1064 );
1065 }
1066 Ok(())
1067 }
1068
1069 #[tokio::test]
1070 #[serial]
1071 async fn two_patch_events() -> Result<()> {
1072 let (_, _, r53, r55, r56) = prep_run_create_pr(false).await?;
1073 for relay in [&r53, &r55, &r56] {
1074 assert_eq!(relay.events.iter().filter(|e| is_patch(e)).count(), 2);
1075 }
1076 Ok(())
1077 }
1078
1079 #[tokio::test]
1080 #[serial]
1081 // TODO check this is the ancestor
1082 async fn first_patch_with_root_t_tag() -> Result<()> {
1083 let (_, _, r53, r55, r56) = prep_run_create_pr(false).await?;
1084 for relay in [&r53, &r55, &r56] {
1085 let patch_events = relay
1086 .events
1087 .iter()
1088 .filter(|e| is_patch(e))
1089 .collect::<Vec<&nostr::Event>>();
1090
1091 // first patch tagged as root
1092 assert!(
1093 patch_events[0]
1094 .iter_tags()
1095 .any(|t| t.as_vec()[0].eq("t") && t.as_vec()[1].eq("root"))
1096 );
1097 // second patch not tagged as root
1098 assert!(
1099 !patch_events[1]
1100 .iter_tags()
1101 .any(|t| t.as_vec()[0].eq("t") && t.as_vec()[1].eq("root"))
1102 );
1103 }
1104 Ok(())
1105 }
1106
1107 #[tokio::test]
1108 #[serial]
1109 async fn second_patch_lists_first_as_root() -> Result<()> {
1110 let (_, _, r53, r55, r56) = prep_run_create_pr(false).await?;
1111 for relay in [&r53, &r55, &r56] {
1112 let patch_events = relay
1113 .events
1114 .iter()
1115 .filter(|e| is_patch(e))
1116 .collect::<Vec<&nostr::Event>>();
1117
1118 assert_eq!(
1119 patch_events[1]
1120 .iter_tags()
1121 .find(|t| t.as_vec()[0].eq("e")
1122 && t.as_vec().len().eq(&4)
1123 && t.as_vec()[3].eq("root"))
1124 .unwrap()
1125 .as_vec()[1],
1126 patch_events[0].id.to_string(),
1127 );
1128 }
1129 Ok(())
1130 }
1131}