this repo has no description
1mod common;
2mod helpers;
3use chrono::Utc;
4use common::*;
5use helpers::*;
6use reqwest::StatusCode;
7use serde_json::{Value, json};
8
9#[tokio::test]
10async fn test_like_lifecycle() {
11 let client = client();
12 let (alice_did, alice_jwt) = setup_new_user("alice-like").await;
13 let (bob_did, bob_jwt) = setup_new_user("bob-like").await;
14 let (post_uri, post_cid) =
15 create_post(&client, &alice_did, &alice_jwt, "Like this post!").await;
16 let (like_uri, _) = create_like(&client, &bob_did, &bob_jwt, &post_uri, &post_cid).await;
17 let like_rkey = like_uri.split('/').next_back().unwrap();
18 let get_like_res = client
19 .get(format!(
20 "{}/xrpc/com.atproto.repo.getRecord",
21 base_url().await
22 ))
23 .query(&[
24 ("repo", bob_did.as_str()),
25 ("collection", "app.bsky.feed.like"),
26 ("rkey", like_rkey),
27 ])
28 .send()
29 .await
30 .expect("Failed to get like");
31 assert_eq!(get_like_res.status(), StatusCode::OK);
32 let like_body: Value = get_like_res.json().await.unwrap();
33 assert_eq!(like_body["value"]["subject"]["uri"], post_uri);
34 let delete_payload = json!({
35 "repo": bob_did,
36 "collection": "app.bsky.feed.like",
37 "rkey": like_rkey
38 });
39 let delete_res = client
40 .post(format!(
41 "{}/xrpc/com.atproto.repo.deleteRecord",
42 base_url().await
43 ))
44 .bearer_auth(&bob_jwt)
45 .json(&delete_payload)
46 .send()
47 .await
48 .expect("Failed to delete like");
49 assert_eq!(delete_res.status(), StatusCode::OK, "Failed to delete like");
50 let get_deleted_res = client
51 .get(format!(
52 "{}/xrpc/com.atproto.repo.getRecord",
53 base_url().await
54 ))
55 .query(&[
56 ("repo", bob_did.as_str()),
57 ("collection", "app.bsky.feed.like"),
58 ("rkey", like_rkey),
59 ])
60 .send()
61 .await
62 .expect("Failed to check deleted like");
63 assert_eq!(
64 get_deleted_res.status(),
65 StatusCode::NOT_FOUND,
66 "Like should be deleted"
67 );
68}
69
70#[tokio::test]
71async fn test_repost_lifecycle() {
72 let client = client();
73 let (alice_did, alice_jwt) = setup_new_user("alice-repost").await;
74 let (bob_did, bob_jwt) = setup_new_user("bob-repost").await;
75 let (post_uri, post_cid) = create_post(&client, &alice_did, &alice_jwt, "Repost this!").await;
76 let (repost_uri, _) = create_repost(&client, &bob_did, &bob_jwt, &post_uri, &post_cid).await;
77 let repost_rkey = repost_uri.split('/').next_back().unwrap();
78 let get_repost_res = client
79 .get(format!(
80 "{}/xrpc/com.atproto.repo.getRecord",
81 base_url().await
82 ))
83 .query(&[
84 ("repo", bob_did.as_str()),
85 ("collection", "app.bsky.feed.repost"),
86 ("rkey", repost_rkey),
87 ])
88 .send()
89 .await
90 .expect("Failed to get repost");
91 assert_eq!(get_repost_res.status(), StatusCode::OK);
92 let repost_body: Value = get_repost_res.json().await.unwrap();
93 assert_eq!(repost_body["value"]["subject"]["uri"], post_uri);
94 let delete_payload = json!({
95 "repo": bob_did,
96 "collection": "app.bsky.feed.repost",
97 "rkey": repost_rkey
98 });
99 let delete_res = client
100 .post(format!(
101 "{}/xrpc/com.atproto.repo.deleteRecord",
102 base_url().await
103 ))
104 .bearer_auth(&bob_jwt)
105 .json(&delete_payload)
106 .send()
107 .await
108 .expect("Failed to delete repost");
109 assert_eq!(
110 delete_res.status(),
111 StatusCode::OK,
112 "Failed to delete repost"
113 );
114}
115
116#[tokio::test]
117async fn test_unfollow_lifecycle() {
118 let client = client();
119 let (alice_did, _alice_jwt) = setup_new_user("alice-unfollow").await;
120 let (bob_did, bob_jwt) = setup_new_user("bob-unfollow").await;
121 let (follow_uri, _) = create_follow(&client, &bob_did, &bob_jwt, &alice_did).await;
122 let follow_rkey = follow_uri.split('/').next_back().unwrap();
123 let get_follow_res = client
124 .get(format!(
125 "{}/xrpc/com.atproto.repo.getRecord",
126 base_url().await
127 ))
128 .query(&[
129 ("repo", bob_did.as_str()),
130 ("collection", "app.bsky.graph.follow"),
131 ("rkey", follow_rkey),
132 ])
133 .send()
134 .await
135 .expect("Failed to get follow");
136 assert_eq!(get_follow_res.status(), StatusCode::OK);
137 let unfollow_payload = json!({
138 "repo": bob_did,
139 "collection": "app.bsky.graph.follow",
140 "rkey": follow_rkey
141 });
142 let unfollow_res = client
143 .post(format!(
144 "{}/xrpc/com.atproto.repo.deleteRecord",
145 base_url().await
146 ))
147 .bearer_auth(&bob_jwt)
148 .json(&unfollow_payload)
149 .send()
150 .await
151 .expect("Failed to unfollow");
152 assert_eq!(unfollow_res.status(), StatusCode::OK, "Failed to unfollow");
153 let get_deleted_res = client
154 .get(format!(
155 "{}/xrpc/com.atproto.repo.getRecord",
156 base_url().await
157 ))
158 .query(&[
159 ("repo", bob_did.as_str()),
160 ("collection", "app.bsky.graph.follow"),
161 ("rkey", follow_rkey),
162 ])
163 .send()
164 .await
165 .expect("Failed to check deleted follow");
166 assert_eq!(
167 get_deleted_res.status(),
168 StatusCode::NOT_FOUND,
169 "Follow should be deleted"
170 );
171}
172
173#[tokio::test]
174async fn test_account_to_post_full_lifecycle() {
175 let client = client();
176 let ts = Utc::now().timestamp_millis();
177 let handle = format!("fullcycle-{}.test", ts);
178 let email = format!("fullcycle-{}@test.com", ts);
179 let password = "Fullcycle123!";
180 let create_account_res = client
181 .post(format!(
182 "{}/xrpc/com.atproto.server.createAccount",
183 base_url().await
184 ))
185 .json(&json!({
186 "handle": handle,
187 "email": email,
188 "password": password
189 }))
190 .send()
191 .await
192 .expect("Failed to create account");
193 assert_eq!(create_account_res.status(), StatusCode::OK);
194 let account_body: Value = create_account_res.json().await.unwrap();
195 let did = account_body["did"].as_str().unwrap().to_string();
196 let handle = account_body["handle"].as_str().unwrap().to_string();
197 let access_jwt = verify_new_account(&client, &did).await;
198 let get_session_res = client
199 .get(format!(
200 "{}/xrpc/com.atproto.server.getSession",
201 base_url().await
202 ))
203 .bearer_auth(&access_jwt)
204 .send()
205 .await
206 .expect("Failed to get session");
207 assert_eq!(get_session_res.status(), StatusCode::OK);
208 let session_body: Value = get_session_res.json().await.unwrap();
209 assert_eq!(session_body["did"], did);
210 let normalized_handle = session_body["handle"].as_str().unwrap().to_string();
211 assert!(
212 normalized_handle.starts_with(&handle),
213 "Session handle should start with the requested handle"
214 );
215 let profile_res = client
216 .post(format!(
217 "{}/xrpc/com.atproto.repo.putRecord",
218 base_url().await
219 ))
220 .bearer_auth(&access_jwt)
221 .json(&json!({
222 "repo": did,
223 "collection": "app.bsky.actor.profile",
224 "rkey": "self",
225 "record": {
226 "$type": "app.bsky.actor.profile",
227 "displayName": "Full Cycle User"
228 }
229 }))
230 .send()
231 .await
232 .expect("Failed to create profile");
233 assert_eq!(profile_res.status(), StatusCode::OK);
234 let (post_uri, post_cid) = create_post(&client, &did, &access_jwt, "My first post!").await;
235 let get_post_res = client
236 .get(format!(
237 "{}/xrpc/com.atproto.repo.getRecord",
238 base_url().await
239 ))
240 .query(&[
241 ("repo", did.as_str()),
242 ("collection", "app.bsky.feed.post"),
243 ("rkey", post_uri.split('/').next_back().unwrap()),
244 ])
245 .send()
246 .await
247 .expect("Failed to get post");
248 assert_eq!(get_post_res.status(), StatusCode::OK);
249 create_like(&client, &did, &access_jwt, &post_uri, &post_cid).await;
250 let describe_res = client
251 .get(format!(
252 "{}/xrpc/com.atproto.repo.describeRepo",
253 base_url().await
254 ))
255 .query(&[("repo", did.as_str())])
256 .send()
257 .await
258 .expect("Failed to describe repo");
259 assert_eq!(describe_res.status(), StatusCode::OK);
260 let describe_body: Value = describe_res.json().await.unwrap();
261 assert_eq!(describe_body["did"], did);
262 let describe_handle = describe_body["handle"].as_str().unwrap();
263 assert!(
264 normalized_handle.starts_with(describe_handle) || describe_handle.starts_with(&handle),
265 "describeRepo handle should be related to the requested handle"
266 );
267}