This repository has no description
1#![allow(dead_code)]
2
3use knot_cob::{ChangePayload, CobError, CobHome, CobId, CobStore};
4use knot_cobs::{Grant, Members, MembersChange, MembersCob, Registration, RegistryChange, Rename};
5use knot_git::{Layout, RefUpdate, Repo};
6use knot_runtime::{K256Signer, SeededEntropy, Signer};
7use knot_types::{
8 AccountDid, ActorId, Oid, OwnerDid, RefName, RepoDid, RepoName, RepoRkey, TypeName, UnixSeconds,
9};
10use tempfile::TempDir;
11
12pub fn fixture() -> (TempDir, Repo) {
13 let dir = tempfile::tempdir().unwrap();
14 let repo = Layout::new(dir.path())
15 .create(&RepoDid::new("did:plc:squid").unwrap())
16 .unwrap();
17 (dir, repo)
18}
19
20pub fn signer(seed: u64) -> K256Signer {
21 K256Signer::generate(&SeededEntropy::new(seed))
22}
23
24pub fn home() -> CobHome {
25 CobHome::from(&RepoDid::new("did:plc:squid").unwrap())
26}
27
28pub fn account(suffix: &str) -> AccountDid {
29 AccountDid::new(format!("did:plc:{suffix}")).unwrap()
30}
31
32pub fn grant(subject: &str, added_by: &str, at: i64) -> Grant {
33 Grant {
34 subject: account(subject),
35 added_by: account(added_by),
36 created_at: UnixSeconds::new(at),
37 }
38}
39
40pub fn at(seconds: i64) -> UnixSeconds {
41 UnixSeconds::new(seconds)
42}
43
44pub fn owner_of(seed: u64) -> ActorId {
45 ActorId::from_secp256k1(signer(seed).public_key().as_bytes())
46}
47
48pub fn rkey(value: &str) -> RepoRkey {
49 RepoRkey::new(value).unwrap()
50}
51
52pub fn did<T: std::str::FromStr>(suffix: &str) -> T
53where
54 T::Err: std::fmt::Debug,
55{
56 format!("did:plc:{suffix}").parse().unwrap()
57}
58
59pub fn registration(owner: &str, key: &str, repo_id: &str, ts: i64) -> Registration {
60 Registration {
61 owner: OwnerDid::new(format!("did:plc:{owner}")).unwrap(),
62 rkey: rkey(key),
63 name: RepoName::new(key).unwrap(),
64 repo: RepoDid::new(format!("did:plc:{repo_id}")).unwrap(),
65 created_at: at(ts),
66 }
67}
68
69pub fn rename(owner_id: &str, key: &str, repo_id: &str) -> Rename {
70 Rename {
71 owner: did::<OwnerDid>(owner_id),
72 rkey: rkey(key),
73 name: RepoName::new(key).unwrap(),
74 repo: did::<RepoDid>(repo_id),
75 }
76}
77
78pub fn reopen(repo: Repo) -> Repo {
79 let path = repo.path().to_path_buf();
80 drop(repo);
81 Repo::open(path).unwrap()
82}
83
84pub fn members_store(
85 seed: u64,
86 steps: &[(MembersChange, i64)],
87) -> (TempDir, Repo, K256Signer, CobId) {
88 let (dir, repo) = fixture();
89 let key = signer(seed);
90 let store = CobStore::new(&repo);
91 let (first, first_at) = &steps[0];
92 let created = store.create(&home(), first, &key, at(*first_at)).unwrap();
93 steps[1..].iter().for_each(|(change, ts)| {
94 store
95 .update(&home(), created.object, change, &key, at(*ts))
96 .unwrap();
97 });
98 (dir, repo, key, created.object)
99}
100
101pub fn build_members(seed: u64, steps: &[(MembersChange, i64)]) -> Members {
102 let (_dir, repo, _key, object) = members_store(seed, steps);
103 CobStore::new(&repo)
104 .get::<MembersCob>(object)
105 .unwrap()
106 .into_state()
107}
108
109pub fn write_cob_commit(
110 repo: &Repo,
111 type_name: &TypeName,
112 payload: &[u8],
113 parents: &[Oid],
114 author: &ActorId,
115 timestamp: i64,
116) -> Oid {
117 let git = repo.git();
118 let payload_oid = git.write_blob(payload).unwrap().detach();
119 let tree = gix::objs::Tree {
120 entries: vec![gix::objs::tree::Entry {
121 mode: gix::objs::tree::EntryKind::Blob.into(),
122 filename: "payload".into(),
123 oid: payload_oid,
124 }],
125 };
126 let revision = git.write_object(tree).unwrap().detach();
127 let identity = gix::actor::Signature {
128 name: "knot".into(),
129 email: "noreply@knot".into(),
130 time: gix::date::Time::new(timestamp, 0),
131 };
132 let commit = gix::objs::Commit {
133 tree: revision,
134 parents: parents.iter().map(|oid| oid.object_id()).collect(),
135 author: identity.clone(),
136 committer: identity,
137 encoding: None,
138 message: Vec::new().into(),
139 extra_headers: vec![
140 ("cob-type".into(), type_name.as_str().into()),
141 ("cob-author".into(), author.as_str().into()),
142 ("cob-sig".into(), "00".into()),
143 ],
144 };
145 Oid::from(git.write_object(commit).unwrap().detach())
146}
147
148pub fn cob_ref(type_name: &TypeName, object: CobId) -> RefName {
149 RefName::new(format!(
150 "refs/cobs/{}/{}",
151 type_name.as_str(),
152 object.oid().to_hex()
153 ))
154 .unwrap()
155}
156
157pub fn forked_members_object(
158 seed: u64,
159 root: (MembersChange, i64),
160 left: (MembersChange, i64),
161 right: (MembersChange, i64),
162 merge: (MembersChange, i64),
163) -> (TempDir, Repo, CobId) {
164 let (dir, repo) = fixture();
165 let nsid = MembersChange::type_name();
166 let author = ActorId::from_secp256k1(signer(seed).public_key().as_bytes());
167 let enc = |c: &MembersChange| c.encode().unwrap();
168
169 let root_oid = write_cob_commit(&repo, &nsid, &enc(&root.0), &[], &author, root.1);
170 let object = CobId::new(root_oid);
171 let left_oid = write_cob_commit(&repo, &nsid, &enc(&left.0), &[root_oid], &author, left.1);
172 let right_oid = write_cob_commit(&repo, &nsid, &enc(&right.0), &[root_oid], &author, right.1);
173 let merge_oid = write_cob_commit(
174 &repo,
175 &nsid,
176 &enc(&merge.0),
177 &[left_oid, right_oid],
178 &author,
179 merge.1,
180 );
181 repo.update_ref(&RefUpdate::Create {
182 name: cob_ref(&nsid, object),
183 new: merge_oid,
184 })
185 .unwrap();
186 (dir, repo, object)
187}
188
189pub fn forked_members(
190 seed: u64,
191 root: (MembersChange, i64),
192 left: (MembersChange, i64),
193 right: (MembersChange, i64),
194 merge: (MembersChange, i64),
195) -> Result<Members, CobError> {
196 let (_dir, repo, object) = forked_members_object(seed, root, left, right, merge);
197 CobStore::new(&repo)
198 .get::<MembersCob>(object)
199 .map(|object| object.into_state())
200}
201
202pub fn registry_with(repo: &Repo, key: &K256Signer, name: &str, repo_id: &str) -> CobId {
203 let store = CobStore::new(repo);
204 store
205 .create(
206 &home(),
207 &RegistryChange::Register(registration("nel", name, repo_id, 1)),
208 key,
209 at(1),
210 )
211 .unwrap()
212 .object
213}