diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2023-11-01 00:00:00 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2023-11-01 00:00:00 +0000 |
| commit | 0753e0bcdd3d606f8f0226a3980bcd817117abaa (patch) | |
| tree | 8eab6115e2840cbf1c16de441e1168e3fdf18eb8 | |
| parent | 1b740dd135aafb52b94b710b3ae24e4aaaa99632 (diff) | |
feat(claim) create basic event
replacable event with root-commit, name, description and relay tags
| -rw-r--r-- | src/main.rs | 7 | ||||
| -rw-r--r-- | src/sub_commands/claim.rs | 114 | ||||
| -rw-r--r-- | src/sub_commands/mod.rs | 1 | ||||
| -rw-r--r-- | src/sub_commands/prs/create.rs | 12 | ||||
| -rw-r--r-- | tests/claim.rs | 331 |
5 files changed, 458 insertions, 7 deletions
diff --git a/src/main.rs b/src/main.rs index 68b0ed6..54ad748 100644 --- a/src/main.rs +++ b/src/main.rs | |||
| @@ -33,7 +33,9 @@ pub struct Cli { | |||
| 33 | enum Commands { | 33 | enum Commands { |
| 34 | /// save encrypted nsec for future use | 34 | /// save encrypted nsec for future use |
| 35 | Login(sub_commands::login::SubCommandArgs), | 35 | Login(sub_commands::login::SubCommandArgs), |
| 36 | /// create and issue Prs | 36 | /// issue repository reference event as a maintainers |
| 37 | Claim(sub_commands::claim::SubCommandArgs), | ||
| 38 | /// create and issue prs | ||
| 37 | Prs(sub_commands::prs::SubCommandArgs), | 39 | Prs(sub_commands::prs::SubCommandArgs), |
| 38 | } | 40 | } |
| 39 | 41 | ||
| @@ -44,6 +46,9 @@ async fn main() -> Result<()> { | |||
| 44 | Commands::Login(args) => { | 46 | Commands::Login(args) => { |
| 45 | futures::executor::block_on(sub_commands::login::launch(&cli, args)) | 47 | futures::executor::block_on(sub_commands::login::launch(&cli, args)) |
| 46 | } | 48 | } |
| 49 | Commands::Claim(args) => { | ||
| 50 | futures::executor::block_on(sub_commands::claim::launch(&cli, args)) | ||
| 51 | } | ||
| 47 | Commands::Prs(args) => futures::executor::block_on(sub_commands::prs::launch(&cli, args)), | 52 | Commands::Prs(args) => futures::executor::block_on(sub_commands::prs::launch(&cli, args)), |
| 48 | } | 53 | } |
| 49 | } | 54 | } |
diff --git a/src/sub_commands/claim.rs b/src/sub_commands/claim.rs new file mode 100644 index 0000000..5eb66bb --- /dev/null +++ b/src/sub_commands/claim.rs | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | use anyhow::{Context, Result}; | ||
| 2 | use nostr::{EventBuilder, Tag}; | ||
| 3 | |||
| 4 | use super::prs::create::send_events; | ||
| 5 | #[cfg(not(test))] | ||
| 6 | use crate::client::Client; | ||
| 7 | #[cfg(test)] | ||
| 8 | use crate::client::MockConnect; | ||
| 9 | use crate::{ | ||
| 10 | cli_interactor::{Interactor, InteractorPrompt, PromptInputParms}, | ||
| 11 | client::Connect, | ||
| 12 | git::{Repo, RepoActions}, | ||
| 13 | login, Cli, | ||
| 14 | }; | ||
| 15 | |||
| 16 | #[derive(Debug, clap::Args)] | ||
| 17 | pub struct SubCommandArgs { | ||
| 18 | #[clap(short, long)] | ||
| 19 | /// name of repository | ||
| 20 | title: Option<String>, | ||
| 21 | #[clap(short, long)] | ||
| 22 | /// optional description | ||
| 23 | description: Option<String>, | ||
| 24 | } | ||
| 25 | |||
| 26 | pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { | ||
| 27 | let git_repo = Repo::discover().context("cannot find a git repository")?; | ||
| 28 | |||
| 29 | let (main_or_master_branch_name, _) = git_repo | ||
| 30 | .get_main_or_master_branch() | ||
| 31 | .context("no main or master branch")?; | ||
| 32 | |||
| 33 | let root_commit = git_repo | ||
| 34 | .get_root_commit(main_or_master_branch_name) | ||
| 35 | .context("failed to get root commit of the repository")?; | ||
| 36 | |||
| 37 | // TODO: check for empty repo | ||
| 38 | // TODO: check for existing maintaiers file | ||
| 39 | // TODO: check for other claims | ||
| 40 | |||
| 41 | let name = match &args.title { | ||
| 42 | Some(t) => t.clone(), | ||
| 43 | None => Interactor::default().input(PromptInputParms::default().with_prompt("name"))?, | ||
| 44 | }; | ||
| 45 | |||
| 46 | let description = match &args.description { | ||
| 47 | Some(t) => t.clone(), | ||
| 48 | None => Interactor::default() | ||
| 49 | .input(PromptInputParms::default().with_prompt("description (Optional)"))?, | ||
| 50 | }; | ||
| 51 | |||
| 52 | #[cfg(not(test))] | ||
| 53 | let mut client = Client::default(); | ||
| 54 | #[cfg(test)] | ||
| 55 | let mut client = <MockConnect as std::default::Default>::default(); | ||
| 56 | |||
| 57 | let (keys, user_ref) = login::launch(&cli_args.nsec, &cli_args.password, Some(&client)).await?; | ||
| 58 | |||
| 59 | client.set_keys(&keys).await; | ||
| 60 | |||
| 61 | // TODO: choice input defaulting to user relay list filtered by non paid relays | ||
| 62 | let repo_relays: Vec<String> = vec![ | ||
| 63 | "ws://localhost:8055".to_string(), | ||
| 64 | "ws://localhost:8056".to_string(), | ||
| 65 | ]; | ||
| 66 | |||
| 67 | println!("publishing repostory reference..."); | ||
| 68 | |||
| 69 | send_events( | ||
| 70 | &client, | ||
| 71 | vec![generate_repo_event( | ||
| 72 | &name, | ||
| 73 | &description, | ||
| 74 | &repo_relays, | ||
| 75 | &root_commit.to_string(), | ||
| 76 | &keys, | ||
| 77 | )?], | ||
| 78 | user_ref.relays.write(), | ||
| 79 | repo_relays, | ||
| 80 | !cli_args.disable_cli_spinners, | ||
| 81 | ) | ||
| 82 | .await?; | ||
| 83 | |||
| 84 | Ok(()) | ||
| 85 | } | ||
| 86 | |||
| 87 | fn generate_repo_event( | ||
| 88 | name: &str, | ||
| 89 | description: &str, | ||
| 90 | relays: &[String], | ||
| 91 | // git_server: String, | ||
| 92 | root_commit: &String, | ||
| 93 | keys: &nostr::Keys, | ||
| 94 | ) -> Result<nostr::Event> { | ||
| 95 | EventBuilder::new( | ||
| 96 | nostr::event::Kind::Custom(30017), | ||
| 97 | "", | ||
| 98 | &[ | ||
| 99 | vec![ | ||
| 100 | Tag::Identifier(root_commit.to_string()), | ||
| 101 | Tag::Reference(format!("r-{root_commit}")), | ||
| 102 | Tag::Name(name.to_owned()), | ||
| 103 | Tag::Description(description.to_owned()), | ||
| 104 | ], | ||
| 105 | relays.iter().map(|r| Tag::Relay(r.into())).collect(), | ||
| 106 | // git_servers | ||
| 107 | // other maintainers | ||
| 108 | // code languages and hashtags | ||
| 109 | ] | ||
| 110 | .concat(), | ||
| 111 | ) | ||
| 112 | .to_event(keys) | ||
| 113 | .context("failed to create pr event") | ||
| 114 | } | ||
diff --git a/src/sub_commands/mod.rs b/src/sub_commands/mod.rs index 3c3da1d..6e99ca5 100644 --- a/src/sub_commands/mod.rs +++ b/src/sub_commands/mod.rs | |||
| @@ -1,2 +1,3 @@ | |||
| 1 | pub mod claim; | ||
| 1 | pub mod login; | 2 | pub mod login; |
| 2 | pub mod prs; | 3 | pub mod prs; |
diff --git a/src/sub_commands/prs/create.rs b/src/sub_commands/prs/create.rs index aad80f4..d82f53e 100644 --- a/src/sub_commands/prs/create.rs +++ b/src/sub_commands/prs/create.rs | |||
| @@ -105,6 +105,11 @@ pub async fn launch( | |||
| 105 | "ws://localhost:8056".to_string(), | 105 | "ws://localhost:8056".to_string(), |
| 106 | ]; | 106 | ]; |
| 107 | 107 | ||
| 108 | println!( | ||
| 109 | "posting 1 pull request with {} commits...", | ||
| 110 | events.len() - 1 | ||
| 111 | ); | ||
| 112 | |||
| 108 | send_events( | 113 | send_events( |
| 109 | &client, | 114 | &client, |
| 110 | events, | 115 | events, |
| @@ -118,7 +123,7 @@ pub async fn launch( | |||
| 118 | Ok(()) | 123 | Ok(()) |
| 119 | } | 124 | } |
| 120 | 125 | ||
| 121 | async fn send_events( | 126 | pub async fn send_events( |
| 122 | #[cfg(test)] client: &crate::client::MockConnect, | 127 | #[cfg(test)] client: &crate::client::MockConnect, |
| 123 | #[cfg(not(test))] client: &Client, | 128 | #[cfg(not(test))] client: &Client, |
| 124 | events: Vec<nostr::Event>, | 129 | events: Vec<nostr::Event>, |
| @@ -128,11 +133,6 @@ async fn send_events( | |||
| 128 | ) -> Result<()> { | 133 | ) -> Result<()> { |
| 129 | let (_, _, _, all) = unique_and_duplicate_all(&my_write_relays, &repo_read_relays); | 134 | let (_, _, _, all) = unique_and_duplicate_all(&my_write_relays, &repo_read_relays); |
| 130 | 135 | ||
| 131 | println!( | ||
| 132 | "posting 1 pull request with {} commits...", | ||
| 133 | events.len() - 1 | ||
| 134 | ); | ||
| 135 | |||
| 136 | let m = MultiProgress::new(); | 136 | let m = MultiProgress::new(); |
| 137 | let pb_style = ProgressStyle::with_template(if animate { | 137 | let pb_style = ProgressStyle::with_template(if animate { |
| 138 | " {spinner} {prefix} {bar} {pos}/{len} {msg}" | 138 | " {spinner} {prefix} {bar} {pos}/{len} {msg}" |
diff --git a/tests/claim.rs b/tests/claim.rs new file mode 100644 index 0000000..ec62c0b --- /dev/null +++ b/tests/claim.rs | |||
| @@ -0,0 +1,331 @@ | |||
| 1 | use anyhow::Result; | ||
| 2 | use serial_test::serial; | ||
| 3 | use test_utils::{git::GitTestRepo, *}; | ||
| 4 | |||
| 5 | #[test] | ||
| 6 | fn when_no_main_or_master_branch_return_error() -> Result<()> { | ||
| 7 | let test_repo = GitTestRepo::new("notmain")?; | ||
| 8 | test_repo.populate()?; | ||
| 9 | let mut p = CliTester::new_from_dir(&test_repo.dir, ["claim"]); | ||
| 10 | p.expect("Error: no main or master branch")?; | ||
| 11 | Ok(()) | ||
| 12 | } | ||
| 13 | |||
| 14 | mod sends_repoistory_to_relays { | ||
| 15 | use futures::join; | ||
| 16 | use test_utils::relay::Relay; | ||
| 17 | |||
| 18 | use super::*; | ||
| 19 | |||
| 20 | static REPOSITORY_KIND: u64 = 30017; | ||
| 21 | |||
| 22 | fn prep_git_repo() -> Result<GitTestRepo> { | ||
| 23 | let test_repo = GitTestRepo::default(); | ||
| 24 | test_repo.populate()?; | ||
| 25 | Ok(test_repo) | ||
| 26 | } | ||
| 27 | |||
| 28 | fn cli_tester_claim(git_repo: &GitTestRepo) -> CliTester { | ||
| 29 | CliTester::new_from_dir( | ||
| 30 | &git_repo.dir, | ||
| 31 | [ | ||
| 32 | "--nsec", | ||
| 33 | TEST_KEY_1_NSEC, | ||
| 34 | "--password", | ||
| 35 | TEST_PASSWORD, | ||
| 36 | "--disable-cli-spinners", | ||
| 37 | "claim", | ||
| 38 | "--title", | ||
| 39 | "example-name", | ||
| 40 | "--description", | ||
| 41 | "example-description", | ||
| 42 | ], | ||
| 43 | ) | ||
| 44 | } | ||
| 45 | |||
| 46 | fn expect_msgs_first(p: &mut CliTester) -> Result<()> { | ||
| 47 | p.expect("searching for your details...\r\n")?; | ||
| 48 | p.expect("\r")?; | ||
| 49 | p.expect("logged in as fred\r\n")?; | ||
| 50 | // // p.expect("searching for existing claims on repository...\r\n")?; | ||
| 51 | p.expect("publishing repostory reference...\r\n")?; | ||
| 52 | Ok(()) | ||
| 53 | } | ||
| 54 | |||
| 55 | async fn prep_run_claim() -> Result<( | ||
| 56 | Relay<'static>, | ||
| 57 | Relay<'static>, | ||
| 58 | Relay<'static>, | ||
| 59 | Relay<'static>, | ||
| 60 | Relay<'static>, | ||
| 61 | )> { | ||
| 62 | let git_repo = prep_git_repo()?; | ||
| 63 | // fallback (51,52) user write (53, 55) repo (55, 56) | ||
| 64 | let (mut r51, mut r52, mut r53, mut r55, mut r56) = ( | ||
| 65 | Relay::new( | ||
| 66 | 8051, | ||
| 67 | None, | ||
| 68 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 69 | relay.respond_events( | ||
| 70 | client_id, | ||
| 71 | &subscription_id, | ||
| 72 | &vec![ | ||
| 73 | generate_test_key_1_metadata_event("fred"), | ||
| 74 | generate_test_key_1_relay_list_event(), | ||
| 75 | ], | ||
| 76 | )?; | ||
| 77 | Ok(()) | ||
| 78 | }), | ||
| 79 | ), | ||
| 80 | Relay::new(8052, None, None), | ||
| 81 | Relay::new(8053, None, None), | ||
| 82 | Relay::new(8055, None, None), | ||
| 83 | Relay::new(8056, None, None), | ||
| 84 | ); | ||
| 85 | |||
| 86 | // // check relay had the right number of events | ||
| 87 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 88 | let mut p = cli_tester_claim(&git_repo); | ||
| 89 | p.expect_end_eventually()?; | ||
| 90 | for p in [51, 52, 53, 55, 56] { | ||
| 91 | relay::shutdown_relay(8000 + p)?; | ||
| 92 | } | ||
| 93 | Ok(()) | ||
| 94 | }); | ||
| 95 | |||
| 96 | // launch relay | ||
| 97 | let _ = join!( | ||
| 98 | r51.listen_until_close(), | ||
| 99 | r52.listen_until_close(), | ||
| 100 | r53.listen_until_close(), | ||
| 101 | r55.listen_until_close(), | ||
| 102 | r56.listen_until_close(), | ||
| 103 | ); | ||
| 104 | cli_tester_handle.join().unwrap()?; | ||
| 105 | Ok((r51, r52, r53, r55, r56)) | ||
| 106 | } | ||
| 107 | |||
| 108 | mod sent_to_correct_relays { | ||
| 109 | use super::*; | ||
| 110 | |||
| 111 | #[test] | ||
| 112 | #[serial] | ||
| 113 | fn only_1_repository_kind_event_sent_to_user_relays() -> Result<()> { | ||
| 114 | let (_, _, r53, r55, _) = futures::executor::block_on(prep_run_claim())?; | ||
| 115 | for relay in [&r53, &r55] { | ||
| 116 | assert_eq!( | ||
| 117 | relay | ||
| 118 | .events | ||
| 119 | .iter() | ||
| 120 | .filter(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) | ||
| 121 | .count(), | ||
| 122 | 1, | ||
| 123 | ); | ||
| 124 | } | ||
| 125 | Ok(()) | ||
| 126 | } | ||
| 127 | |||
| 128 | #[test] | ||
| 129 | #[serial] | ||
| 130 | fn only_1_repository_kind_event_sent_to_repo_relays() -> Result<()> { | ||
| 131 | let (_, _, _, r55, r56) = futures::executor::block_on(prep_run_claim())?; | ||
| 132 | for relay in [&r55, &r56] { | ||
| 133 | assert_eq!( | ||
| 134 | relay | ||
| 135 | .events | ||
| 136 | .iter() | ||
| 137 | .filter(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) | ||
| 138 | .count(), | ||
| 139 | 1, | ||
| 140 | ); | ||
| 141 | } | ||
| 142 | Ok(()) | ||
| 143 | } | ||
| 144 | |||
| 145 | #[test] | ||
| 146 | #[serial] | ||
| 147 | fn event_not_sent_to_fallback_relay() -> Result<()> { | ||
| 148 | let (r51, r52, _, _, _) = futures::executor::block_on(prep_run_claim())?; | ||
| 149 | for relay in [&r51, &r52] { | ||
| 150 | assert_eq!( | ||
| 151 | relay | ||
| 152 | .events | ||
| 153 | .iter() | ||
| 154 | .filter(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) | ||
| 155 | .count(), | ||
| 156 | 0, | ||
| 157 | ); | ||
| 158 | } | ||
| 159 | Ok(()) | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | mod tags { | ||
| 164 | use super::*; | ||
| 165 | |||
| 166 | #[test] | ||
| 167 | #[serial] | ||
| 168 | fn d_replaceable_event_identifier() -> Result<()> { | ||
| 169 | let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?; | ||
| 170 | for relay in [&r53, &r55, &r56] { | ||
| 171 | let event: &nostr::Event = relay | ||
| 172 | .events | ||
| 173 | .iter() | ||
| 174 | .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) | ||
| 175 | .unwrap(); | ||
| 176 | |||
| 177 | assert!(event.tags.iter().any(|t| t.as_vec()[0].eq("d") | ||
| 178 | && t.as_vec()[1].eq("9ee507fc4357d7ee16a5d8901bedcd103f23c17d"))); | ||
| 179 | } | ||
| 180 | Ok(()) | ||
| 181 | } | ||
| 182 | |||
| 183 | #[test] | ||
| 184 | #[serial] | ||
| 185 | fn root_commit() -> Result<()> { | ||
| 186 | let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?; | ||
| 187 | for relay in [&r53, &r55, &r56] { | ||
| 188 | let event: &nostr::Event = relay | ||
| 189 | .events | ||
| 190 | .iter() | ||
| 191 | .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) | ||
| 192 | .unwrap(); | ||
| 193 | |||
| 194 | // root commit 'r' tag with 'r-' prefix | ||
| 195 | assert!(event.tags.iter().any(|t| t.as_vec()[0].eq("r") | ||
| 196 | && t.as_vec()[1].eq("r-9ee507fc4357d7ee16a5d8901bedcd103f23c17d"))); | ||
| 197 | } | ||
| 198 | Ok(()) | ||
| 199 | } | ||
| 200 | |||
| 201 | #[test] | ||
| 202 | #[serial] | ||
| 203 | fn name() -> Result<()> { | ||
| 204 | let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?; | ||
| 205 | for relay in [&r53, &r55, &r56] { | ||
| 206 | let event: &nostr::Event = relay | ||
| 207 | .events | ||
| 208 | .iter() | ||
| 209 | .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) | ||
| 210 | .unwrap(); | ||
| 211 | |||
| 212 | assert!( | ||
| 213 | event | ||
| 214 | .tags | ||
| 215 | .iter() | ||
| 216 | .any(|t| t.as_vec()[0].eq("name") && t.as_vec()[1].eq("example-name")) | ||
| 217 | ); | ||
| 218 | } | ||
| 219 | Ok(()) | ||
| 220 | } | ||
| 221 | |||
| 222 | #[test] | ||
| 223 | #[serial] | ||
| 224 | fn description() -> Result<()> { | ||
| 225 | let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?; | ||
| 226 | for relay in [&r53, &r55, &r56] { | ||
| 227 | let event: &nostr::Event = relay | ||
| 228 | .events | ||
| 229 | .iter() | ||
| 230 | .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) | ||
| 231 | .unwrap(); | ||
| 232 | |||
| 233 | assert!( | ||
| 234 | event.tags.iter().any(|t| t.as_vec()[0].eq("description") | ||
| 235 | && t.as_vec()[1].eq("example-description")) | ||
| 236 | ); | ||
| 237 | } | ||
| 238 | Ok(()) | ||
| 239 | } | ||
| 240 | |||
| 241 | #[test] | ||
| 242 | #[serial] | ||
| 243 | fn relays() -> Result<()> { | ||
| 244 | let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?; | ||
| 245 | for relay in [&r53, &r55, &r56] { | ||
| 246 | let event: &nostr::Event = relay | ||
| 247 | .events | ||
| 248 | .iter() | ||
| 249 | .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) | ||
| 250 | .unwrap(); | ||
| 251 | |||
| 252 | let relay_tags = event | ||
| 253 | .tags | ||
| 254 | .iter() | ||
| 255 | .filter(|t| t.as_vec()[0].eq("relay")) | ||
| 256 | .collect::<Vec<&nostr::Tag>>(); | ||
| 257 | assert_eq!(relay_tags[0].as_vec()[1], "ws://localhost:8055"); | ||
| 258 | assert_eq!(relay_tags[1].as_vec()[1], "ws://localhost:8056"); | ||
| 259 | } | ||
| 260 | Ok(()) | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | mod cli_ouput { | ||
| 265 | use super::*; | ||
| 266 | |||
| 267 | async fn run_test_async() -> Result<()> { | ||
| 268 | let git_repo = prep_git_repo()?; | ||
| 269 | |||
| 270 | let (mut r51, mut r52, mut r53, mut r55, mut r56) = ( | ||
| 271 | Relay::new( | ||
| 272 | 8051, | ||
| 273 | None, | ||
| 274 | Some(&|relay, client_id, subscription_id, _| -> Result<()> { | ||
| 275 | relay.respond_events( | ||
| 276 | client_id, | ||
| 277 | &subscription_id, | ||
| 278 | &vec![ | ||
| 279 | generate_test_key_1_metadata_event("fred"), | ||
| 280 | generate_test_key_1_relay_list_event(), | ||
| 281 | ], | ||
| 282 | )?; | ||
| 283 | Ok(()) | ||
| 284 | }), | ||
| 285 | ), | ||
| 286 | Relay::new(8052, None, None), | ||
| 287 | Relay::new(8053, None, None), | ||
| 288 | Relay::new(8055, None, None), | ||
| 289 | Relay::new(8056, None, None), | ||
| 290 | ); | ||
| 291 | |||
| 292 | // // check relay had the right number of events | ||
| 293 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 294 | let mut p = cli_tester_claim(&git_repo); | ||
| 295 | expect_msgs_first(&mut p)?; | ||
| 296 | relay::expect_send_with_progress( | ||
| 297 | &mut p, | ||
| 298 | vec![ | ||
| 299 | (" [my-relay] [repo-relay] ws://localhost:8055", true, ""), | ||
| 300 | (" [my-relay] ws://localhost:8053", true, ""), | ||
| 301 | (" [repo-relay] ws://localhost:8056", true, ""), | ||
| 302 | ], | ||
| 303 | 1, | ||
| 304 | )?; | ||
| 305 | p.expect_end_with_whitespace()?; | ||
| 306 | for p in [51, 52, 53, 55, 56] { | ||
| 307 | relay::shutdown_relay(8000 + p)?; | ||
| 308 | } | ||
| 309 | Ok(()) | ||
| 310 | }); | ||
| 311 | |||
| 312 | // launch relay | ||
| 313 | let _ = join!( | ||
| 314 | r51.listen_until_close(), | ||
| 315 | r52.listen_until_close(), | ||
| 316 | r53.listen_until_close(), | ||
| 317 | r55.listen_until_close(), | ||
| 318 | r56.listen_until_close(), | ||
| 319 | ); | ||
| 320 | cli_tester_handle.join().unwrap()?; | ||
| 321 | Ok(()) | ||
| 322 | } | ||
| 323 | |||
| 324 | #[test] | ||
| 325 | #[serial] | ||
| 326 | fn check_cli_output() -> Result<()> { | ||
| 327 | futures::executor::block_on(run_test_async())?; | ||
| 328 | Ok(()) | ||
| 329 | } | ||
| 330 | } | ||
| 331 | } | ||