upleb.uk

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

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