upleb.uk

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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock20
-rw-r--r--Cargo.toml1
-rw-r--r--src/git.rs33
-rw-r--r--src/repo_ref.rs184
-rw-r--r--src/sub_commands/claim.rs52
-rw-r--r--src/sub_commands/prs/create.rs2
-rw-r--r--src/sub_commands/prs/list.rs1
-rw-r--r--src/sub_commands/pull.rs1
-rw-r--r--src/sub_commands/push.rs1
-rw-r--r--test_utils/src/git.rs5
-rw-r--r--tests/claim.rs785
11 files changed, 829 insertions, 256 deletions
diff --git a/Cargo.lock b/Cargo.lock
index e5191e5..7b373f0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1601,6 +1601,7 @@ dependencies = [
1601 "scrypt", 1601 "scrypt",
1602 "serde", 1602 "serde",
1603 "serde_json", 1603 "serde_json",
1604 "serde_yaml",
1604 "serial_test", 1605 "serial_test",
1605 "test_utils", 1606 "test_utils",
1606 "tokio", 1607 "tokio",
@@ -2555,6 +2556,19 @@ dependencies = [
2555] 2556]
2556 2557
2557[[package]] 2558[[package]]
2559name = "serde_yaml"
2560version = "0.9.27"
2561source = "registry+https://github.com/rust-lang/crates.io-index"
2562checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c"
2563dependencies = [
2564 "indexmap 2.1.0",
2565 "itoa",
2566 "ryu",
2567 "serde",
2568 "unsafe-libyaml",
2569]
2570
2571[[package]]
2558name = "serial_test" 2572name = "serial_test"
2559version = "2.0.0" 2573version = "2.0.0"
2560source = "registry+https://github.com/rust-lang/crates.io-index" 2574source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3028,6 +3042,12 @@ dependencies = [
3028] 3042]
3029 3043
3030[[package]] 3044[[package]]
3045name = "unsafe-libyaml"
3046version = "0.2.9"
3047source = "registry+https://github.com/rust-lang/crates.io-index"
3048checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
3049
3050[[package]]
3031name = "untrusted" 3051name = "untrusted"
3032version = "0.9.0" 3052version = "0.9.0"
3033source = "registry+https://github.com/rust-lang/crates.io-index" 3053source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index f578333..78360a1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,6 +29,7 @@ passwords = "3.1.13"
29scrypt = "0.11.0" 29scrypt = "0.11.0"
30serde = { version = "1.0.181", features = ["derive"] } 30serde = { version = "1.0.181", features = ["derive"] }
31serde_json = "1.0.105" 31serde_json = "1.0.105"
32serde_yaml = "0.9.27"
32tokio = "1.33.0" 33tokio = "1.33.0"
33zeroize = "1.6.0" 34zeroize = "1.6.0"
34 35
diff --git a/src/git.rs b/src/git.rs
index e2d8196..29670eb 100644
--- a/src/git.rs
+++ b/src/git.rs
@@ -1,6 +1,6 @@
1use std::env::current_dir;
2#[cfg(test)] 1#[cfg(test)]
3use std::path::PathBuf; 2use std::path::PathBuf;
3use std::{env::current_dir, path::Path};
4 4
5use anyhow::{bail, Context, Result}; 5use anyhow::{bail, Context, Result};
6use git2::{Oid, Revwalk}; 6use git2::{Oid, Revwalk};
@@ -30,6 +30,8 @@ impl Repo {
30// pub type Sha1 = [u8; 20]; 30// pub type Sha1 = [u8; 20];
31 31
32pub trait RepoActions { 32pub trait RepoActions {
33 fn get_path(&self) -> Result<&Path>;
34 fn get_origin_url(&self) -> Result<String>;
33 fn get_local_branch_names(&self) -> Result<Vec<String>>; 35 fn get_local_branch_names(&self) -> Result<Vec<String>>;
34 fn get_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)>; 36 fn get_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)>;
35 fn get_checked_out_branch_name(&self) -> Result<String>; 37 fn get_checked_out_branch_name(&self) -> Result<String>;
@@ -61,6 +63,23 @@ pub trait RepoActions {
61} 63}
62 64
63impl RepoActions for Repo { 65impl RepoActions for Repo {
66 fn get_path(&self) -> Result<&Path> {
67 self.git_repo
68 .path()
69 .parent()
70 .context("cannot find repositiory path as .git has no parent")
71 }
72
73 fn get_origin_url(&self) -> Result<String> {
74 Ok(self
75 .git_repo
76 .find_remote("origin")
77 .context("cannot find origin")?
78 .url()
79 .context("cannot find origin url")?
80 .to_string())
81 }
82
64 fn get_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)> { 83 fn get_main_or_master_branch(&self) -> Result<(&str, Sha1Hash)> {
65 let main_branch_name = { 84 let main_branch_name = {
66 let local_branches = self 85 let local_branches = self
@@ -860,6 +879,18 @@ mod tests {
860 } 879 }
861 } 880 }
862 881
882 mod get_origin_url {
883 use super::*;
884
885 #[test]
886 fn returns_origin_url() -> Result<()> {
887 let test_repo = GitTestRepo::default();
888 test_repo.add_remote("origin", "https://localhost:1000")?;
889 let git_repo = Repo::from_path(&test_repo.dir)?;
890 assert_eq!(git_repo.get_origin_url()?, "https://localhost:1000");
891 Ok(())
892 }
893 }
863 mod get_checked_out_branch_name { 894 mod get_checked_out_branch_name {
864 use super::*; 895 use super::*;
865 896
diff --git a/src/repo_ref.rs b/src/repo_ref.rs
index a92b5b3..a5b35c9 100644
--- a/src/repo_ref.rs
+++ b/src/repo_ref.rs
@@ -1,20 +1,26 @@
1use std::{fs::File, io::BufReader, str::FromStr};
2
1use anyhow::{bail, Context, Result}; 3use anyhow::{bail, Context, Result};
2use nostr::Tag; 4use nostr::{secp256k1::XOnlyPublicKey, FromBech32, Tag, ToBech32};
5use serde::{Deserialize, Serialize};
3 6
4#[cfg(not(test))] 7#[cfg(not(test))]
5use crate::client::Client; 8use crate::client::Client;
6use crate::client::Connect;
7#[cfg(test)] 9#[cfg(test)]
8use crate::client::MockConnect; 10use crate::client::MockConnect;
11use crate::{
12 client::Connect,
13 git::{Repo, RepoActions},
14};
9 15
10#[derive(Default)] 16#[derive(Default)]
11pub struct RepoRef { 17pub struct RepoRef {
12 pub name: String, 18 pub name: String,
13 pub description: String, 19 pub description: String,
14 pub root_commit: String, 20 pub root_commit: String,
21 pub git_server: String,
15 pub relays: Vec<String>, 22 pub relays: Vec<String>,
16 // git_server: String, 23 pub maintainers: Vec<XOnlyPublicKey>,
17 // other maintainers
18 // code languages and hashtags 24 // code languages and hashtags
19} 25}
20 26
@@ -35,6 +41,10 @@ impl TryFrom<nostr::Event> for RepoRef {
35 r.description = t.as_vec()[1].clone(); 41 r.description = t.as_vec()[1].clone();
36 } 42 }
37 43
44 if let Some(t) = event.tags.iter().find(|t| t.as_vec()[0].eq("git-server")) {
45 r.git_server = t.as_vec()[1].clone();
46 }
47
38 if let Some(t) = event.tags.iter().find(|t| t.as_vec()[0].eq("d")) { 48 if let Some(t) = event.tags.iter().find(|t| t.as_vec()[0].eq("d")) {
39 r.root_commit = t.as_vec()[1].clone(); 49 r.root_commit = t.as_vec()[1].clone();
40 } 50 }
@@ -46,6 +56,15 @@ impl TryFrom<nostr::Event> for RepoRef {
46 .map(|t| t.as_vec()[1].clone()) 56 .map(|t| t.as_vec()[1].clone())
47 .collect(); 57 .collect();
48 58
59 for tag in event.tags.iter().filter(|t| t.as_vec()[0].eq("p")) {
60 let pk = tag.as_vec()[1].clone();
61 r.maintainers.push(
62 nostr_sdk::prelude::XOnlyPublicKey::from_str(&pk)
63 .context(format!("cannot convert {pk} into a valid nostr public key"))
64 .context("invalid repository event")?,
65 );
66 }
67
49 Ok(r) 68 Ok(r)
50 } 69 }
51} 70}
@@ -62,10 +81,17 @@ impl RepoRef {
62 Tag::Reference(format!("r-{}", self.root_commit)), 81 Tag::Reference(format!("r-{}", self.root_commit)),
63 Tag::Name(self.name.clone()), 82 Tag::Name(self.name.clone()),
64 Tag::Description(self.description.clone()), 83 Tag::Description(self.description.clone()),
84 Tag::Generic(
85 nostr::TagKind::Custom("git-server".to_string()),
86 vec![self.git_server.clone()],
87 ),
88 Tag::Reference(self.git_server.clone()),
65 ], 89 ],
66 self.relays.iter().map(|r| Tag::Relay(r.into())).collect(), 90 self.relays.iter().map(|r| Tag::Relay(r.into())).collect(),
67 // git_servers 91 self.maintainers
68 // other maintainers 92 .iter()
93 .map(|pk| Tag::PubKey(*pk, None))
94 .collect(),
69 // code languages and hashtags 95 // code languages and hashtags
70 ] 96 ]
71 .concat(), 97 .concat(),
@@ -76,24 +102,30 @@ impl RepoRef {
76} 102}
77 103
78pub async fn fetch( 104pub async fn fetch(
105 git_repo: &Repo,
79 root_commit: String, 106 root_commit: String,
80 #[cfg(test)] client: &MockConnect, 107 #[cfg(test)] client: &MockConnect,
81 #[cfg(not(test))] client: &Client, 108 #[cfg(not(test))] client: &Client,
82 // TODO: more rubust way of finding repo events 109 // TODO: more rubust way of finding repo events
83 relays: Vec<String>, 110 fallback_relays: Vec<String>,
84) -> Result<RepoRef> { 111) -> Result<RepoRef> {
85 // TODO: fetch relay information from file 112 let repo_config = get_repo_config_from_yaml(git_repo);
86 113
87 let events: Vec<nostr::Event> = client 114 // TODO: check events only from maintainers. get relay list of maintainters.
88 .get_events( 115 // check those relays.
89 relays, 116
90 vec![ 117 let mut repo_event_filter = nostr::Filter::default()
91 nostr::Filter::default() 118 .kind(nostr::Kind::Custom(REPO_REF_KIND))
92 .kind(nostr::Kind::Custom(REPO_REF_KIND)) 119 .identifier(root_commit);
93 .identifier(root_commit), 120
94 ], 121 let mut relays = fallback_relays;
95 ) 122 if let Ok(repo_config) = repo_config {
96 .await?; 123 repo_event_filter =
124 repo_event_filter.pubkeys(extract_pks(repo_config.maintainers.clone())?);
125 relays = repo_config.relays.clone();
126 }
127
128 let events: Vec<nostr::Event> = client.get_events(relays, vec![repo_event_filter]).await?;
97 129
98 RepoRef::try_from( 130 RepoRef::try_from(
99 events 131 events
@@ -105,6 +137,68 @@ pub async fn fetch(
105 ) 137 )
106} 138}
107 139
140#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq, Eq)]
141pub struct RepoConfigYaml {
142 pub maintainers: Vec<String>,
143 pub relays: Vec<String>,
144}
145
146pub fn get_repo_config_from_yaml(git_repo: &Repo) -> Result<RepoConfigYaml> {
147 let path = git_repo.get_path()?.join("maintainers.yaml");
148 let file = File::open(path)
149 .context("should open maintainers.yaml if it exists")
150 .context("maintainers.yaml doesnt exist")?;
151 let reader = BufReader::new(file);
152 let repo_config_yaml: RepoConfigYaml = serde_yaml::from_reader(reader)
153 .context("should read maintainers.yaml with serde_yaml")
154 .context("maintainers.yaml incorrectly formatted")?;
155 Ok(repo_config_yaml)
156}
157
158pub fn extract_pks(pk_strings: Vec<String>) -> Result<Vec<XOnlyPublicKey>> {
159 let mut pks: Vec<XOnlyPublicKey> = vec![];
160 for s in pk_strings {
161 pks.push(
162 nostr_sdk::prelude::XOnlyPublicKey::from_bech32(s.clone())
163 .context(format!("cannot convert {s} into a valid nostr public key"))?,
164 );
165 }
166 Ok(pks)
167}
168
169pub fn save_repo_config_to_yaml(
170 git_repo: &Repo,
171 maintainers: Vec<XOnlyPublicKey>,
172 relays: Vec<String>,
173) -> Result<()> {
174 let path = git_repo.get_path()?.join("maintainers.yaml");
175 let file = if path.exists() {
176 std::fs::OpenOptions::new()
177 .create(true)
178 .write(true)
179 .truncate(true)
180 .open(path)
181 .context("cannot open maintainers.yaml file with write and truncate options")?
182 } else {
183 std::fs::File::create(path).context("cannot create maintainers.yaml file")?
184 };
185 let mut maintainers_npubs = vec![];
186 for m in maintainers {
187 maintainers_npubs.push(
188 m.to_bech32()
189 .context("cannot convert public key into npub")?,
190 );
191 }
192 serde_yaml::to_writer(
193 file,
194 &RepoConfigYaml {
195 maintainers: maintainers_npubs,
196 relays,
197 },
198 )
199 .context("cannot write maintainers to maintainers.yaml file serde_yaml")
200}
201
108#[cfg(test)] 202#[cfg(test)]
109mod tests { 203mod tests {
110 use test_utils::*; 204 use test_utils::*;
@@ -116,7 +210,9 @@ mod tests {
116 name: "test name".to_string(), 210 name: "test name".to_string(),
117 description: "test description".to_string(), 211 description: "test description".to_string(),
118 root_commit: "23471389461".to_string(), 212 root_commit: "23471389461".to_string(),
213 git_server: "https://localhost:1000".to_string(),
119 relays: vec!["ws://relay1.io".to_string(), "ws://relay2.io".to_string()], 214 relays: vec!["ws://relay1.io".to_string(), "ws://relay2.io".to_string()],
215 maintainers: vec![TEST_KEY_1_KEYS.public_key(), TEST_KEY_2_KEYS.public_key()],
120 } 216 }
121 .to_event(&TEST_KEY_1_KEYS) 217 .to_event(&TEST_KEY_1_KEYS)
122 .unwrap() 218 .unwrap()
@@ -146,12 +242,28 @@ mod tests {
146 } 242 }
147 243
148 #[test] 244 #[test]
245 fn git_server() {
246 assert_eq!(
247 RepoRef::try_from(create()).unwrap().git_server,
248 "https://localhost:1000",
249 )
250 }
251
252 #[test]
149 fn relays() { 253 fn relays() {
150 assert_eq!( 254 assert_eq!(
151 RepoRef::try_from(create()).unwrap().relays, 255 RepoRef::try_from(create()).unwrap().relays,
152 vec!["ws://relay1.io".to_string(), "ws://relay2.io".to_string()], 256 vec!["ws://relay1.io".to_string(), "ws://relay2.io".to_string()],
153 ) 257 )
154 } 258 }
259
260 #[test]
261 fn maintainers() {
262 assert_eq!(
263 RepoRef::try_from(create()).unwrap().maintainers,
264 vec![TEST_KEY_1_KEYS.public_key(), TEST_KEY_2_KEYS.public_key()],
265 )
266 }
155 } 267 }
156 268
157 mod to_event { 269 mod to_event {
@@ -186,6 +298,21 @@ mod tests {
186 } 298 }
187 299
188 #[test] 300 #[test]
301 fn git_server() {
302 assert!(create().tags.iter().any(|t| t.as_vec()[0].eq("git-server")
303 && t.as_vec()[1].eq("https://localhost:1000")))
304 }
305
306 #[test]
307 fn git_server_as_reference() {
308 assert!(
309 create().tags.iter().any(
310 |t| t.as_vec()[0].eq("r") && t.as_vec()[1].eq("https://localhost:1000")
311 )
312 )
313 }
314
315 #[test]
189 fn root_commit_as_reference() { 316 fn root_commit_as_reference() {
190 assert!( 317 assert!(
191 create() 318 create()
@@ -209,8 +336,27 @@ mod tests {
209 } 336 }
210 337
211 #[test] 338 #[test]
339 fn maintainers() {
340 let event = create();
341 let p_tags = event
342 .tags
343 .iter()
344 .filter(|t| t.as_vec()[0].eq("p"))
345 .collect::<Vec<&nostr::Tag>>();
346 assert_eq!(p_tags[0].as_vec().len(), 2);
347 assert_eq!(
348 p_tags[0].as_vec()[1],
349 TEST_KEY_1_KEYS.public_key().to_string()
350 );
351 assert_eq!(
352 p_tags[1].as_vec()[1],
353 TEST_KEY_2_KEYS.public_key().to_string()
354 );
355 }
356
357 #[test]
212 fn no_other_tags() { 358 fn no_other_tags() {
213 assert_eq!(create().tags.len(), 6) 359 assert_eq!(create().tags.len(), 10)
214 } 360 }
215 } 361 }
216 } 362 }
diff --git a/src/sub_commands/claim.rs b/src/sub_commands/claim.rs
index c0d26dd..2573267 100644
--- a/src/sub_commands/claim.rs
+++ b/src/sub_commands/claim.rs
@@ -10,7 +10,7 @@ use crate::{
10 client::Connect, 10 client::Connect,
11 git::{Repo, RepoActions}, 11 git::{Repo, RepoActions},
12 login, 12 login,
13 repo_ref::RepoRef, 13 repo_ref::{extract_pks, get_repo_config_from_yaml, save_repo_config_to_yaml, RepoRef},
14 Cli, 14 Cli,
15}; 15};
16 16
@@ -22,6 +22,9 @@ pub struct SubCommandArgs {
22 #[clap(short, long)] 22 #[clap(short, long)]
23 /// optional description 23 /// optional description
24 description: Option<String>, 24 description: Option<String>,
25 #[clap(short, long, value_parser, num_args = 1..)]
26 /// relays contributors push patches and comments to
27 relays: Vec<String>,
25} 28}
26 29
27pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { 30pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
@@ -37,6 +40,8 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
37 40
38 // TODO: check for empty repo 41 // TODO: check for empty repo
39 // TODO: check for existing maintaiers file 42 // TODO: check for existing maintaiers file
43
44 let repo_config_result = get_repo_config_from_yaml(&git_repo);
40 // TODO: check for other claims 45 // TODO: check for other claims
41 46
42 let name = match &args.title { 47 let name = match &args.title {
@@ -50,6 +55,8 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
50 .input(PromptInputParms::default().with_prompt("description (Optional)"))?, 55 .input(PromptInputParms::default().with_prompt("description (Optional)"))?,
51 }; 56 };
52 57
58 let git_server = git_repo.get_origin_url()?;
59
53 #[cfg(not(test))] 60 #[cfg(not(test))]
54 let mut client = Client::default(); 61 let mut client = Client::default();
55 #[cfg(test)] 62 #[cfg(test)]
@@ -59,11 +66,41 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
59 66
60 client.set_keys(&keys).await; 67 client.set_keys(&keys).await;
61 68
62 // TODO: choice input defaulting to user relay list filtered by non paid relays 69 let mut maintainers = vec![keys.public_key()];
63 let repo_relays: Vec<String> = vec![ 70
64 "ws://localhost:8055".to_string(), 71 let repo_relays: Vec<String> = if !args.relays.is_empty() {
65 "ws://localhost:8056".to_string(), 72 args.relays.clone()
66 ]; 73 } else if let Ok(config) = &repo_config_result {
74 config.relays.clone()
75 } else {
76 // TODO: choice input defaulting to user relay list filtered by non paid relays
77 // TODO: allow manual input for more relays
78 // TODO: reccommend some free relays
79 user_ref.relays.write()
80 };
81
82 if let Ok(config) = &repo_config_result {
83 maintainers = extract_pks(config.maintainers.clone())?;
84 }
85
86 // if yaml file doesnt exist or needs updating
87 if match &repo_config_result {
88 Ok(config) => {
89 !(extract_pks(config.maintainers.clone())?.eq(&maintainers)
90 && config.relays.eq(&repo_relays))
91 }
92 Err(_) => true,
93 } {
94 save_repo_config_to_yaml(&git_repo, maintainers.clone(), repo_relays.clone())?;
95 println!(
96 "maintainers.yaml {}. commit and push.",
97 if repo_config_result.is_err() {
98 "created"
99 } else {
100 "updated"
101 }
102 );
103 }
67 104
68 println!("publishing repostory reference..."); 105 println!("publishing repostory reference...");
69 106
@@ -71,10 +108,13 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
71 name, 108 name,
72 description, 109 description,
73 root_commit: root_commit.to_string(), 110 root_commit: root_commit.to_string(),
111 git_server,
74 relays: repo_relays.clone(), 112 relays: repo_relays.clone(),
113 maintainers,
75 } 114 }
76 .to_event(&keys)?; 115 .to_event(&keys)?;
77 116
117 // TODO: send repo event to blaster
78 send_events( 118 send_events(
79 &client, 119 &client,
80 vec![repo_event], 120 vec![repo_event],
diff --git a/src/sub_commands/prs/create.rs b/src/sub_commands/prs/create.rs
index 5c4e578..5e41a56 100644
--- a/src/sub_commands/prs/create.rs
+++ b/src/sub_commands/prs/create.rs
@@ -100,12 +100,12 @@ pub async fn launch(
100 generate_pr_and_patch_events(&title, &description, &to_branch, &git_repo, &ahead, &keys)?; 100 generate_pr_and_patch_events(&title, &description, &to_branch, &git_repo, &ahead, &keys)?;
101 101
102 let repo_ref = repo_ref::fetch( 102 let repo_ref = repo_ref::fetch(
103 &git_repo,
103 git_repo 104 git_repo
104 .get_root_commit(&to_branch) 105 .get_root_commit(&to_branch)
105 .context("failed to get root commit of the repository")? 106 .context("failed to get root commit of the repository")?
106 .to_string(), 107 .to_string(),
107 &client, 108 &client,
108 // TODO: get relay list from local yaml file
109 user_ref.relays.write(), 109 user_ref.relays.write(),
110 ) 110 )
111 .await?; 111 .await?;
diff --git a/src/sub_commands/prs/list.rs b/src/sub_commands/prs/list.rs
index 13f29fd..a6aa8b7 100644
--- a/src/sub_commands/prs/list.rs
+++ b/src/sub_commands/prs/list.rs
@@ -45,6 +45,7 @@ pub async fn launch(
45 let client = <MockConnect as std::default::Default>::default(); 45 let client = <MockConnect as std::default::Default>::default();
46 46
47 let repo_ref = repo_ref::fetch( 47 let repo_ref = repo_ref::fetch(
48 &git_repo,
48 root_commit.to_string(), 49 root_commit.to_string(),
49 &client, 50 &client,
50 client.get_more_fallback_relays().clone(), 51 client.get_more_fallback_relays().clone(),
diff --git a/src/sub_commands/pull.rs b/src/sub_commands/pull.rs
index a6513e8..a656e09 100644
--- a/src/sub_commands/pull.rs
+++ b/src/sub_commands/pull.rs
@@ -38,6 +38,7 @@ pub async fn launch() -> Result<()> {
38 let client = <MockConnect as std::default::Default>::default(); 38 let client = <MockConnect as std::default::Default>::default();
39 39
40 let repo_ref = repo_ref::fetch( 40 let repo_ref = repo_ref::fetch(
41 &git_repo,
41 root_commit.to_string(), 42 root_commit.to_string(),
42 &client, 43 &client,
43 client.get_more_fallback_relays().clone(), 44 client.get_more_fallback_relays().clone(),
diff --git a/src/sub_commands/push.rs b/src/sub_commands/push.rs
index 968aa0a..7c64bb2 100644
--- a/src/sub_commands/push.rs
+++ b/src/sub_commands/push.rs
@@ -41,6 +41,7 @@ pub async fn launch(cli_args: &Cli) -> Result<()> {
41 let mut client = <MockConnect as std::default::Default>::default(); 41 let mut client = <MockConnect as std::default::Default>::default();
42 42
43 let repo_ref = repo_ref::fetch( 43 let repo_ref = repo_ref::fetch(
44 &git_repo,
44 root_commit.to_string(), 45 root_commit.to_string(),
45 &client, 46 &client,
46 client.get_more_fallback_relays().clone(), 47 client.get_more_fallback_relays().clone(),
diff --git a/test_utils/src/git.rs b/test_utils/src/git.rs
index af87a3a..7f0b4c7 100644
--- a/test_utils/src/git.rs
+++ b/test_utils/src/git.rs
@@ -146,6 +146,11 @@ impl GitTestRepo {
146 .context(format!("cannot find branch {branch_name}"))?; 146 .context(format!("cannot find branch {branch_name}"))?;
147 Ok(branch.into_reference().peel_to_commit()?.id()) 147 Ok(branch.into_reference().peel_to_commit()?.id())
148 } 148 }
149
150 pub fn add_remote(&self, name: &str, url: &str) -> Result<()> {
151 self.git_repo.remote(name, url)?;
152 Ok(())
153 }
149} 154}
150 155
151impl Drop for GitTestRepo { 156impl Drop for GitTestRepo {
diff --git a/tests/claim.rs b/tests/claim.rs
index 61be68b..cd845f7 100644
--- a/tests/claim.rs
+++ b/tests/claim.rs
@@ -11,260 +11,509 @@ fn when_no_main_or_master_branch_return_error() -> Result<()> {
11 Ok(()) 11 Ok(())
12} 12}
13 13
14mod sends_repoistory_to_relays { 14fn expect_msgs_first(p: &mut CliTester) -> Result<()> {
15 use futures::join; 15 p.expect("searching for your details...\r\n")?;
16 use test_utils::relay::Relay; 16 p.expect("\r")?;
17 p.expect("logged in as fred\r\n")?;
18 // // p.expect("searching for existing claims on repository...\r\n")?;
19 p.expect("maintainers.yaml created. commit and push.\r\n")?;
20 p.expect("publishing repostory reference...\r\n")?;
21 Ok(())
22}
17 23
24mod when_repo_not_previously_claimed {
18 use super::*; 25 use super::*;
19 26
20 fn prep_git_repo() -> Result<GitTestRepo> { 27 mod when_repo_relays_specified_as_arguments {
21 let test_repo = GitTestRepo::default(); 28 use futures::join;
22 test_repo.populate()?; 29 use test_utils::relay::Relay;
23 Ok(test_repo)
24 }
25 30
26 fn cli_tester_claim(git_repo: &GitTestRepo) -> CliTester { 31 use super::*;
27 CliTester::new_from_dir(
28 &git_repo.dir,
29 [
30 "--nsec",
31 TEST_KEY_1_NSEC,
32 "--password",
33 TEST_PASSWORD,
34 "--disable-cli-spinners",
35 "claim",
36 "--title",
37 "example-name",
38 "--description",
39 "example-description",
40 ],
41 )
42 }
43 32
44 fn expect_msgs_first(p: &mut CliTester) -> Result<()> { 33 fn prep_git_repo() -> Result<GitTestRepo> {
45 p.expect("searching for your details...\r\n")?; 34 let test_repo = GitTestRepo::default();
46 p.expect("\r")?; 35 test_repo.populate()?;
47 p.expect("logged in as fred\r\n")?; 36 test_repo.add_remote("origin", "https://localhost:1000")?;
48 // // p.expect("searching for existing claims on repository...\r\n")?; 37 Ok(test_repo)
49 p.expect("publishing repostory reference...\r\n")?; 38 }
50 Ok(())
51 }
52 39
53 async fn prep_run_claim() -> Result<( 40 fn cli_tester_claim(git_repo: &GitTestRepo) -> CliTester {
54 Relay<'static>, 41 CliTester::new_from_dir(
55 Relay<'static>, 42 &git_repo.dir,
56 Relay<'static>, 43 [
57 Relay<'static>, 44 "--nsec",
58 Relay<'static>, 45 TEST_KEY_1_NSEC,
59 )> { 46 "--password",
60 let git_repo = prep_git_repo()?; 47 TEST_PASSWORD,
61 // fallback (51,52) user write (53, 55) repo (55, 56) 48 "--disable-cli-spinners",
62 let (mut r51, mut r52, mut r53, mut r55, mut r56) = ( 49 "claim",
63 Relay::new( 50 "--title",
64 8051, 51 "example-name",
65 None, 52 "--description",
66 Some(&|relay, client_id, subscription_id, _| -> Result<()> { 53 "example-description",
67 relay.respond_events( 54 "--relays",
68 client_id, 55 "ws://localhost:8055",
69 &subscription_id, 56 "ws://localhost:8056",
70 &vec![ 57 ],
71 generate_test_key_1_metadata_event("fred"), 58 )
72 generate_test_key_1_relay_list_event(), 59 }
73 ], 60
74 )?; 61 async fn prep_run_claim() -> Result<(
62 Relay<'static>,
63 Relay<'static>,
64 Relay<'static>,
65 Relay<'static>,
66 Relay<'static>,
67 )> {
68 let git_repo = prep_git_repo()?;
69 // fallback (51,52) user write (53, 55) repo (55, 56)
70 let (mut r51, mut r52, mut r53, mut r55, mut r56) = (
71 Relay::new(
72 8051,
73 None,
74 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
75 relay.respond_events(
76 client_id,
77 &subscription_id,
78 &vec![
79 generate_test_key_1_metadata_event("fred"),
80 generate_test_key_1_relay_list_event(),
81 ],
82 )?;
83 Ok(())
84 }),
85 ),
86 Relay::new(8052, None, None),
87 Relay::new(8053, None, None),
88 Relay::new(8055, None, None),
89 Relay::new(8056, None, None),
90 );
91
92 // // check relay had the right number of events
93 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
94 let mut p = cli_tester_claim(&git_repo);
95 p.expect_end_eventually()?;
96 for p in [51, 52, 53, 55, 56] {
97 relay::shutdown_relay(8000 + p)?;
98 }
99 Ok(())
100 });
101
102 // launch relay
103 let _ = join!(
104 r51.listen_until_close(),
105 r52.listen_until_close(),
106 r53.listen_until_close(),
107 r55.listen_until_close(),
108 r56.listen_until_close(),
109 );
110 cli_tester_handle.join().unwrap()?;
111 Ok((r51, r52, r53, r55, r56))
112 }
113
114 mod sent_to_correct_relays {
115 use super::*;
116
117 #[test]
118 #[serial]
119 fn only_1_repository_kind_event_sent_to_user_relays() -> Result<()> {
120 let (_, _, r53, r55, _) = futures::executor::block_on(prep_run_claim())?;
121 for relay in [&r53, &r55] {
122 assert_eq!(
123 relay
124 .events
125 .iter()
126 .filter(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
127 .count(),
128 1,
129 );
130 }
131 Ok(())
132 }
133
134 #[test]
135 #[serial]
136 fn only_1_repository_kind_event_sent_to_specified_repo_relays() -> Result<()> {
137 let (_, _, _, r55, r56) = futures::executor::block_on(prep_run_claim())?;
138 for relay in [&r55, &r56] {
139 assert_eq!(
140 relay
141 .events
142 .iter()
143 .filter(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
144 .count(),
145 1,
146 );
147 }
148 Ok(())
149 }
150
151 #[test]
152 #[serial]
153 fn event_not_sent_to_fallback_relay() -> Result<()> {
154 let (r51, r52, _, _, _) = futures::executor::block_on(prep_run_claim())?;
155 for relay in [&r51, &r52] {
156 assert_eq!(
157 relay
158 .events
159 .iter()
160 .filter(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
161 .count(),
162 0,
163 );
164 }
165 Ok(())
166 }
167 }
168
169 mod yaml_file {
170 use std::{fs, io::Read};
171
172 use super::*;
173
174 async fn async_run_test() -> Result<()> {
175 let git_repo = prep_git_repo()?;
176 // fallback (51,52) user write (53, 55) repo (55, 56)
177 let (mut r51, mut r52, mut r53, mut r55, mut r56) = (
178 Relay::new(
179 8051,
180 None,
181 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
182 relay.respond_events(
183 client_id,
184 &subscription_id,
185 &vec![
186 generate_test_key_1_metadata_event("fred"),
187 generate_test_key_1_relay_list_event(),
188 ],
189 )?;
190 Ok(())
191 }),
192 ),
193 Relay::new(8052, None, None),
194 Relay::new(8053, None, None),
195 Relay::new(8055, None, None),
196 Relay::new(8056, None, None),
197 );
198
199 // // check relay had the right number of events
200 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
201 let mut p = cli_tester_claim(&git_repo);
202 p.expect_end_eventually()?;
203
204 let yaml_path = git_repo.dir.join("maintainers.yaml");
205
206 assert!(yaml_path.exists());
207
208 let mut file = fs::File::open(yaml_path).expect("no such file");
209 let mut file_contents = "".to_string();
210 let _ = file.read_to_string(&mut file_contents);
211 assert_eq!(
212 file_contents,
213 format!(
214 "\
215 maintainers:\n\
216 - {TEST_KEY_1_NPUB}\n\
217 relays:\n\
218 - ws://localhost:8055\n\
219 - ws://localhost:8056\n\
220 "
221 ),
222 );
223 for p in [51, 52, 53, 55, 56] {
224 relay::shutdown_relay(8000 + p)?;
225 }
75 Ok(()) 226 Ok(())
76 }), 227 });
77 ), 228
78 Relay::new(8052, None, None), 229 // launch relay
79 Relay::new(8053, None, None), 230 let _ = join!(
80 Relay::new(8055, None, None), 231 r51.listen_until_close(),
81 Relay::new(8056, None, None), 232 r52.listen_until_close(),
82 ); 233 r53.listen_until_close(),
83 234 r55.listen_until_close(),
84 // // check relay had the right number of events 235 r56.listen_until_close(),
85 let cli_tester_handle = std::thread::spawn(move || -> Result<()> { 236 );
86 let mut p = cli_tester_claim(&git_repo); 237 cli_tester_handle.join().unwrap()?;
87 p.expect_end_eventually()?; 238 Ok(())
88 for p in [51, 52, 53, 55, 56] {
89 relay::shutdown_relay(8000 + p)?;
90 } 239 }
91 Ok(())
92 });
93
94 // launch relay
95 let _ = join!(
96 r51.listen_until_close(),
97 r52.listen_until_close(),
98 r53.listen_until_close(),
99 r55.listen_until_close(),
100 r56.listen_until_close(),
101 );
102 cli_tester_handle.join().unwrap()?;
103 Ok((r51, r52, r53, r55, r56))
104 }
105 240
106 mod sent_to_correct_relays { 241 #[test]
107 use super::*; 242 #[serial]
243 fn contains_maintainers_and_relays() -> Result<()> {
244 futures::executor::block_on(async_run_test())?;
245 Ok(())
246 }
247 }
248
249 mod tags {
250 use super::*;
108 251
109 #[test] 252 #[test]
110 #[serial] 253 #[serial]
111 fn only_1_repository_kind_event_sent_to_user_relays() -> Result<()> { 254 fn root_commit_as_d_replaceable_event_identifier() -> Result<()> {
112 let (_, _, r53, r55, _) = futures::executor::block_on(prep_run_claim())?; 255 let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?;
113 for relay in [&r53, &r55] { 256 for relay in [&r53, &r55, &r56] {
114 assert_eq!( 257 let event: &nostr::Event = relay
115 relay
116 .events 258 .events
117 .iter() 259 .iter()
118 .filter(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) 260 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
119 .count(), 261 .unwrap();
120 1, 262
121 ); 263 assert!(event.tags.iter().any(|t| t.as_vec()[0].eq("d")
264 && t.as_vec()[1].eq("9ee507fc4357d7ee16a5d8901bedcd103f23c17d")));
265 }
266 Ok(())
122 } 267 }
123 Ok(())
124 }
125 268
126 #[test] 269 #[test]
127 #[serial] 270 #[serial]
128 fn only_1_repository_kind_event_sent_to_repo_relays() -> Result<()> { 271 fn root_commit_as_reference() -> Result<()> {
129 let (_, _, _, r55, r56) = futures::executor::block_on(prep_run_claim())?; 272 let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?;
130 for relay in [&r55, &r56] { 273 for relay in [&r53, &r55, &r56] {
131 assert_eq!( 274 let event: &nostr::Event = relay
132 relay
133 .events 275 .events
134 .iter() 276 .iter()
135 .filter(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) 277 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
136 .count(), 278 .unwrap();
137 1, 279
138 ); 280 // root commit 'r' tag with 'r-' prefix
281 assert!(event.tags.iter().any(|t| t.as_vec()[0].eq("r")
282 && t.as_vec()[1].eq("r-9ee507fc4357d7ee16a5d8901bedcd103f23c17d")));
283 }
284 Ok(())
139 } 285 }
140 Ok(())
141 }
142 286
143 #[test] 287 #[test]
144 #[serial] 288 #[serial]
145 fn event_not_sent_to_fallback_relay() -> Result<()> { 289 fn name() -> Result<()> {
146 let (r51, r52, _, _, _) = futures::executor::block_on(prep_run_claim())?; 290 let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?;
147 for relay in [&r51, &r52] { 291 for relay in [&r53, &r55, &r56] {
148 assert_eq!( 292 let event: &nostr::Event = relay
149 relay
150 .events 293 .events
151 .iter() 294 .iter()
152 .filter(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) 295 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
153 .count(), 296 .unwrap();
154 0, 297
155 ); 298 assert!(
299 event
300 .tags
301 .iter()
302 .any(|t| t.as_vec()[0].eq("name") && t.as_vec()[1].eq("example-name"))
303 );
304 }
305 Ok(())
156 } 306 }
157 Ok(())
158 }
159 }
160 307
161 mod tags { 308 #[test]
162 use super::*; 309 #[serial]
310 fn description() -> Result<()> {
311 let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?;
312 for relay in [&r53, &r55, &r56] {
313 let event: &nostr::Event = relay
314 .events
315 .iter()
316 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
317 .unwrap();
163 318
164 #[test] 319 assert!(event.tags.iter().any(|t| t.as_vec()[0].eq("description")
165 #[serial] 320 && t.as_vec()[1].eq("example-description")));
166 fn root_commit_as_d_replaceable_event_identifier() -> Result<()> { 321 }
167 let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?; 322 Ok(())
168 for relay in [&r53, &r55, &r56] {
169 let event: &nostr::Event = relay
170 .events
171 .iter()
172 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
173 .unwrap();
174
175 assert!(event.tags.iter().any(|t| t.as_vec()[0].eq("d")
176 && t.as_vec()[1].eq("9ee507fc4357d7ee16a5d8901bedcd103f23c17d")));
177 } 323 }
178 Ok(())
179 }
180 324
181 #[test] 325 #[test]
182 #[serial] 326 #[serial]
183 fn root_commit_as_reference() -> Result<()> { 327 fn git_server() -> Result<()> {
184 let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?; 328 let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?;
185 for relay in [&r53, &r55, &r56] { 329 for relay in [&r53, &r55, &r56] {
186 let event: &nostr::Event = relay 330 let event: &nostr::Event = relay
187 .events 331 .events
188 .iter() 332 .iter()
189 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) 333 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
190 .unwrap(); 334 .unwrap();
191 335
192 // root commit 'r' tag with 'r-' prefix 336 assert!(event.tags.iter().any(|t| t.as_vec()[0].eq("git-server")
193 assert!(event.tags.iter().any(|t| t.as_vec()[0].eq("r") 337 && t.as_vec()[1].eq("https://localhost:1000")));
194 && t.as_vec()[1].eq("r-9ee507fc4357d7ee16a5d8901bedcd103f23c17d"))); 338 }
339 Ok(())
340 }
341
342 #[test]
343 #[serial]
344 fn git_server_as_reference() -> Result<()> {
345 let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?;
346 for relay in [&r53, &r55, &r56] {
347 let event: &nostr::Event = relay
348 .events
349 .iter()
350 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
351 .unwrap();
352
353 assert!(event.tags.iter().any(
354 |t| t.as_vec()[0].eq("r") && t.as_vec()[1].eq("https://localhost:1000")
355 ));
356 }
357 Ok(())
195 } 358 }
196 Ok(())
197 }
198 359
199 #[test] 360 #[test]
200 #[serial] 361 #[serial]
201 fn name() -> Result<()> { 362 fn relays() -> Result<()> {
202 let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?; 363 let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?;
203 for relay in [&r53, &r55, &r56] { 364 for relay in [&r53, &r55, &r56] {
204 let event: &nostr::Event = relay 365 let event: &nostr::Event = relay
205 .events 366 .events
206 .iter() 367 .iter()
207 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) 368 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
208 .unwrap(); 369 .unwrap();
209 370
210 assert!( 371 let relay_tags = event
211 event
212 .tags 372 .tags
213 .iter() 373 .iter()
214 .any(|t| t.as_vec()[0].eq("name") && t.as_vec()[1].eq("example-name")) 374 .filter(|t| t.as_vec()[0].eq("relay"))
215 ); 375 .collect::<Vec<&nostr::Tag>>();
376 assert_eq!(relay_tags[0].as_vec()[1], "ws://localhost:8055");
377 assert_eq!(relay_tags[1].as_vec()[1], "ws://localhost:8056");
378 }
379 Ok(())
380 }
381
382 #[test]
383 #[serial]
384 fn current_user_tagged_indicating_maintainer() -> Result<()> {
385 let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?;
386 for relay in [&r53, &r55, &r56] {
387 let event: &nostr::Event = relay
388 .events
389 .iter()
390 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
391 .unwrap();
392
393 let relay_tags = event
394 .tags
395 .iter()
396 .filter(|t| t.as_vec()[0].eq("p"))
397 .collect::<Vec<&nostr::Tag>>();
398 assert_eq!(relay_tags.len(), 1);
399 assert_eq!(
400 relay_tags[0].as_vec()[1],
401 TEST_KEY_1_KEYS.public_key().to_string()
402 );
403 }
404 Ok(())
216 } 405 }
217 Ok(())
218 } 406 }
219 407
220 #[test] 408 mod cli_ouput {
221 #[serial] 409 use super::*;
222 fn description() -> Result<()> { 410
223 let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?; 411 async fn run_test_async() -> Result<()> {
224 for relay in [&r53, &r55, &r56] { 412 let git_repo = prep_git_repo()?;
225 let event: &nostr::Event = relay 413
226 .events 414 let (mut r51, mut r52, mut r53, mut r55, mut r56) = (
227 .iter() 415 Relay::new(
228 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND)) 416 8051,
229 .unwrap(); 417 None,
230 418 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
231 assert!( 419 relay.respond_events(
232 event.tags.iter().any(|t| t.as_vec()[0].eq("description") 420 client_id,
233 && t.as_vec()[1].eq("example-description")) 421 &subscription_id,
422 &vec![
423 generate_test_key_1_metadata_event("fred"),
424 generate_test_key_1_relay_list_event(),
425 ],
426 )?;
427 Ok(())
428 }),
429 ),
430 Relay::new(8052, None, None),
431 Relay::new(8053, None, None),
432 Relay::new(8055, None, None),
433 Relay::new(8056, None, None),
234 ); 434 );
435
436 // // check relay had the right number of events
437 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
438 let mut p = cli_tester_claim(&git_repo);
439 expect_msgs_first(&mut p)?;
440 relay::expect_send_with_progress(
441 &mut p,
442 vec![
443 (" [my-relay] [repo-relay] ws://localhost:8055", true, ""),
444 (" [my-relay] ws://localhost:8053", true, ""),
445 (" [repo-relay] ws://localhost:8056", true, ""),
446 ],
447 1,
448 )?;
449 p.expect_end_with_whitespace()?;
450 for p in [51, 52, 53, 55, 56] {
451 relay::shutdown_relay(8000 + p)?;
452 }
453 Ok(())
454 });
455
456 // launch relay
457 let _ = join!(
458 r51.listen_until_close(),
459 r52.listen_until_close(),
460 r53.listen_until_close(),
461 r55.listen_until_close(),
462 r56.listen_until_close(),
463 );
464 cli_tester_handle.join().unwrap()?;
465 Ok(())
235 } 466 }
236 Ok(())
237 }
238 467
239 #[test] 468 #[test]
240 #[serial] 469 #[serial]
241 fn relays() -> Result<()> { 470 fn check_cli_output() -> Result<()> {
242 let (_, _, r53, r55, r56) = futures::executor::block_on(prep_run_claim())?; 471 futures::executor::block_on(run_test_async())?;
243 for relay in [&r53, &r55, &r56] { 472 Ok(())
244 let event: &nostr::Event = relay
245 .events
246 .iter()
247 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
248 .unwrap();
249
250 let relay_tags = event
251 .tags
252 .iter()
253 .filter(|t| t.as_vec()[0].eq("relay"))
254 .collect::<Vec<&nostr::Tag>>();
255 assert_eq!(relay_tags[0].as_vec()[1], "ws://localhost:8055");
256 assert_eq!(relay_tags[1].as_vec()[1], "ws://localhost:8056");
257 } 473 }
258 Ok(())
259 } 474 }
260 } 475 }
261 476
262 mod cli_ouput { 477 mod when_repo_relays_not_specified {
478 use futures::join;
479 use test_utils::relay::Relay;
480
263 use super::*; 481 use super::*;
264 482
265 async fn run_test_async() -> Result<()> { 483 fn prep_git_repo() -> Result<GitTestRepo> {
266 let git_repo = prep_git_repo()?; 484 let test_repo = GitTestRepo::default();
485 test_repo.populate()?;
486 test_repo.add_remote("origin", "https://localhost:1000")?;
487 Ok(test_repo)
488 }
489
490 fn cli_tester_claim(git_repo: &GitTestRepo) -> CliTester {
491 CliTester::new_from_dir(
492 &git_repo.dir,
493 [
494 "--nsec",
495 TEST_KEY_1_NSEC,
496 "--password",
497 TEST_PASSWORD,
498 "--disable-cli-spinners",
499 "claim",
500 "--title",
501 "example-name",
502 "--description",
503 "example-description",
504 ],
505 )
506 }
267 507
508 async fn prep_run_claim() -> Result<(
509 Relay<'static>,
510 Relay<'static>,
511 Relay<'static>,
512 Relay<'static>,
513 Relay<'static>,
514 )> {
515 let git_repo = prep_git_repo()?;
516 // fallback (51,52) user write (53, 55) repo (55, 56)
268 let (mut r51, mut r52, mut r53, mut r55, mut r56) = ( 517 let (mut r51, mut r52, mut r53, mut r55, mut r56) = (
269 Relay::new( 518 Relay::new(
270 8051, 519 8051,
@@ -290,17 +539,7 @@ mod sends_repoistory_to_relays {
290 // // check relay had the right number of events 539 // // check relay had the right number of events
291 let cli_tester_handle = std::thread::spawn(move || -> Result<()> { 540 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
292 let mut p = cli_tester_claim(&git_repo); 541 let mut p = cli_tester_claim(&git_repo);
293 expect_msgs_first(&mut p)?; 542 p.expect_end_eventually()?;
294 relay::expect_send_with_progress(
295 &mut p,
296 vec![
297 (" [my-relay] [repo-relay] ws://localhost:8055", true, ""),
298 (" [my-relay] ws://localhost:8053", true, ""),
299 (" [repo-relay] ws://localhost:8056", true, ""),
300 ],
301 1,
302 )?;
303 p.expect_end_with_whitespace()?;
304 for p in [51, 52, 53, 55, 56] { 543 for p in [51, 52, 53, 55, 56] {
305 relay::shutdown_relay(8000 + p)?; 544 relay::shutdown_relay(8000 + p)?;
306 } 545 }
@@ -316,14 +555,102 @@ mod sends_repoistory_to_relays {
316 r56.listen_until_close(), 555 r56.listen_until_close(),
317 ); 556 );
318 cli_tester_handle.join().unwrap()?; 557 cli_tester_handle.join().unwrap()?;
319 Ok(()) 558 Ok((r51, r52, r53, r55, r56))
559 }
560
561 mod tags {
562 use super::*;
563
564 #[test]
565 #[serial]
566 fn relays_match_user_write_relays() -> Result<()> {
567 let (_, _, r53, r55, _) = futures::executor::block_on(prep_run_claim())?;
568 for relay in [&r53, &r55] {
569 let event: &nostr::Event = relay
570 .events
571 .iter()
572 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
573 .unwrap();
574
575 let relay_tags = event
576 .tags
577 .iter()
578 .filter(|t| t.as_vec()[0].eq("relay"))
579 .collect::<Vec<&nostr::Tag>>();
580 assert_eq!(relay_tags[0].as_vec()[1], "ws://localhost:8053");
581 assert_eq!(relay_tags[1].as_vec()[1], "ws://localhost:8055");
582 }
583 Ok(())
584 }
320 } 585 }
321 586
322 #[test] 587 mod cli_ouput {
323 #[serial] 588 use super::*;
324 fn check_cli_output() -> Result<()> { 589
325 futures::executor::block_on(run_test_async())?; 590 async fn run_test_async() -> Result<()> {
326 Ok(()) 591 let git_repo = prep_git_repo()?;
592
593 let (mut r51, mut r52, mut r53, mut r55, mut r56) = (
594 Relay::new(
595 8051,
596 None,
597 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
598 relay.respond_events(
599 client_id,
600 &subscription_id,
601 &vec![
602 generate_test_key_1_metadata_event("fred"),
603 generate_test_key_1_relay_list_event(),
604 ],
605 )?;
606 Ok(())
607 }),
608 ),
609 Relay::new(8052, None, None),
610 Relay::new(8053, None, None),
611 Relay::new(8055, None, None),
612 Relay::new(8056, None, None),
613 );
614
615 // // check relay had the right number of events
616 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
617 let mut p = cli_tester_claim(&git_repo);
618 expect_msgs_first(&mut p)?;
619 relay::expect_send_with_progress(
620 &mut p,
621 vec![
622 (" [my-relay] [repo-relay] ws://localhost:8053", true, ""),
623 (" [my-relay] [repo-relay] ws://localhost:8055", true, ""),
624 ],
625 1,
626 )?;
627 p.expect_end_with_whitespace()?;
628 for p in [51, 52, 53, 55, 56] {
629 relay::shutdown_relay(8000 + p)?;
630 }
631 Ok(())
632 });
633
634 // launch relay
635 let _ = join!(
636 r51.listen_until_close(),
637 r52.listen_until_close(),
638 r53.listen_until_close(),
639 r55.listen_until_close(),
640 r56.listen_until_close(),
641 );
642 cli_tester_handle.join().unwrap()?;
643 Ok(())
644 }
645
646 #[test]
647 #[serial]
648 fn check_cli_output() -> Result<()> {
649 futures::executor::block_on(run_test_async())?;
650 Ok(())
651 }
327 } 652 }
328 } 653 }
329} 654}
655
656// TODO: when_updating_existing_repoistory