this repo has no description
1mod common;
2use common::*;
3use chrono::Utc;
4use reqwest::StatusCode;
5use serde_json::{Value, json};
6#[tokio::test]
7async fn test_apply_writes_create() {
8 let client = client();
9 let (token, did) = create_account_and_login(&client).await;
10 let now = Utc::now().to_rfc3339();
11 let payload = json!({
12 "repo": did,
13 "writes": [
14 {
15 "$type": "com.atproto.repo.applyWrites#create",
16 "collection": "app.bsky.feed.post",
17 "value": {
18 "$type": "app.bsky.feed.post",
19 "text": "Batch created post 1",
20 "createdAt": now
21 }
22 },
23 {
24 "$type": "com.atproto.repo.applyWrites#create",
25 "collection": "app.bsky.feed.post",
26 "value": {
27 "$type": "app.bsky.feed.post",
28 "text": "Batch created post 2",
29 "createdAt": now
30 }
31 }
32 ]
33 });
34 let res = client
35 .post(format!(
36 "{}/xrpc/com.atproto.repo.applyWrites",
37 base_url().await
38 ))
39 .bearer_auth(&token)
40 .json(&payload)
41 .send()
42 .await
43 .expect("Failed to send request");
44 assert_eq!(res.status(), StatusCode::OK);
45 let body: Value = res.json().await.expect("Response was not valid JSON");
46 assert!(body["commit"]["cid"].is_string());
47 assert!(body["results"].is_array());
48 let results = body["results"].as_array().unwrap();
49 assert_eq!(results.len(), 2);
50 assert!(results[0]["uri"].is_string());
51 assert!(results[0]["cid"].is_string());
52}
53#[tokio::test]
54async fn test_apply_writes_update() {
55 let client = client();
56 let (token, did) = create_account_and_login(&client).await;
57 let now = Utc::now().to_rfc3339();
58 let rkey = format!("batch_update_{}", Utc::now().timestamp_millis());
59 let create_payload = json!({
60 "repo": did,
61 "collection": "app.bsky.feed.post",
62 "rkey": rkey,
63 "record": {
64 "$type": "app.bsky.feed.post",
65 "text": "Original post",
66 "createdAt": now
67 }
68 });
69 let res = client
70 .post(format!(
71 "{}/xrpc/com.atproto.repo.putRecord",
72 base_url().await
73 ))
74 .bearer_auth(&token)
75 .json(&create_payload)
76 .send()
77 .await
78 .expect("Failed to create");
79 assert_eq!(res.status(), StatusCode::OK);
80 let update_payload = json!({
81 "repo": did,
82 "writes": [
83 {
84 "$type": "com.atproto.repo.applyWrites#update",
85 "collection": "app.bsky.feed.post",
86 "rkey": rkey,
87 "value": {
88 "$type": "app.bsky.feed.post",
89 "text": "Updated post via applyWrites",
90 "createdAt": now
91 }
92 }
93 ]
94 });
95 let res = client
96 .post(format!(
97 "{}/xrpc/com.atproto.repo.applyWrites",
98 base_url().await
99 ))
100 .bearer_auth(&token)
101 .json(&update_payload)
102 .send()
103 .await
104 .expect("Failed to send request");
105 assert_eq!(res.status(), StatusCode::OK);
106 let body: Value = res.json().await.expect("Response was not valid JSON");
107 let results = body["results"].as_array().unwrap();
108 assert_eq!(results.len(), 1);
109 assert!(results[0]["uri"].is_string());
110}
111#[tokio::test]
112async fn test_apply_writes_delete() {
113 let client = client();
114 let (token, did) = create_account_and_login(&client).await;
115 let now = Utc::now().to_rfc3339();
116 let rkey = format!("batch_delete_{}", Utc::now().timestamp_millis());
117 let create_payload = json!({
118 "repo": did,
119 "collection": "app.bsky.feed.post",
120 "rkey": rkey,
121 "record": {
122 "$type": "app.bsky.feed.post",
123 "text": "Post to delete",
124 "createdAt": now
125 }
126 });
127 let res = client
128 .post(format!(
129 "{}/xrpc/com.atproto.repo.putRecord",
130 base_url().await
131 ))
132 .bearer_auth(&token)
133 .json(&create_payload)
134 .send()
135 .await
136 .expect("Failed to create");
137 assert_eq!(res.status(), StatusCode::OK);
138 let delete_payload = json!({
139 "repo": did,
140 "writes": [
141 {
142 "$type": "com.atproto.repo.applyWrites#delete",
143 "collection": "app.bsky.feed.post",
144 "rkey": rkey
145 }
146 ]
147 });
148 let res = client
149 .post(format!(
150 "{}/xrpc/com.atproto.repo.applyWrites",
151 base_url().await
152 ))
153 .bearer_auth(&token)
154 .json(&delete_payload)
155 .send()
156 .await
157 .expect("Failed to send request");
158 assert_eq!(res.status(), StatusCode::OK);
159 let get_res = client
160 .get(format!(
161 "{}/xrpc/com.atproto.repo.getRecord",
162 base_url().await
163 ))
164 .query(&[
165 ("repo", did.as_str()),
166 ("collection", "app.bsky.feed.post"),
167 ("rkey", rkey.as_str()),
168 ])
169 .send()
170 .await
171 .expect("Failed to verify");
172 assert_eq!(get_res.status(), StatusCode::NOT_FOUND);
173}
174#[tokio::test]
175async fn test_apply_writes_mixed_operations() {
176 let client = client();
177 let (token, did) = create_account_and_login(&client).await;
178 let now = Utc::now().to_rfc3339();
179 let rkey_to_delete = format!("mixed_del_{}", Utc::now().timestamp_millis());
180 let rkey_to_update = format!("mixed_upd_{}", Utc::now().timestamp_millis());
181 let setup_payload = json!({
182 "repo": did,
183 "writes": [
184 {
185 "$type": "com.atproto.repo.applyWrites#create",
186 "collection": "app.bsky.feed.post",
187 "rkey": rkey_to_delete,
188 "value": {
189 "$type": "app.bsky.feed.post",
190 "text": "To be deleted",
191 "createdAt": now
192 }
193 },
194 {
195 "$type": "com.atproto.repo.applyWrites#create",
196 "collection": "app.bsky.feed.post",
197 "rkey": rkey_to_update,
198 "value": {
199 "$type": "app.bsky.feed.post",
200 "text": "To be updated",
201 "createdAt": now
202 }
203 }
204 ]
205 });
206 let res = client
207 .post(format!(
208 "{}/xrpc/com.atproto.repo.applyWrites",
209 base_url().await
210 ))
211 .bearer_auth(&token)
212 .json(&setup_payload)
213 .send()
214 .await
215 .expect("Failed to setup");
216 assert_eq!(res.status(), StatusCode::OK);
217 let mixed_payload = json!({
218 "repo": did,
219 "writes": [
220 {
221 "$type": "com.atproto.repo.applyWrites#create",
222 "collection": "app.bsky.feed.post",
223 "value": {
224 "$type": "app.bsky.feed.post",
225 "text": "New post",
226 "createdAt": now
227 }
228 },
229 {
230 "$type": "com.atproto.repo.applyWrites#update",
231 "collection": "app.bsky.feed.post",
232 "rkey": rkey_to_update,
233 "value": {
234 "$type": "app.bsky.feed.post",
235 "text": "Updated text",
236 "createdAt": now
237 }
238 },
239 {
240 "$type": "com.atproto.repo.applyWrites#delete",
241 "collection": "app.bsky.feed.post",
242 "rkey": rkey_to_delete
243 }
244 ]
245 });
246 let res = client
247 .post(format!(
248 "{}/xrpc/com.atproto.repo.applyWrites",
249 base_url().await
250 ))
251 .bearer_auth(&token)
252 .json(&mixed_payload)
253 .send()
254 .await
255 .expect("Failed to send request");
256 assert_eq!(res.status(), StatusCode::OK);
257 let body: Value = res.json().await.expect("Response was not valid JSON");
258 let results = body["results"].as_array().unwrap();
259 assert_eq!(results.len(), 3);
260}
261#[tokio::test]
262async fn test_apply_writes_no_auth() {
263 let client = client();
264 let payload = json!({
265 "repo": "did:plc:test",
266 "writes": [
267 {
268 "$type": "com.atproto.repo.applyWrites#create",
269 "collection": "app.bsky.feed.post",
270 "value": {
271 "$type": "app.bsky.feed.post",
272 "text": "Test",
273 "createdAt": "2025-01-01T00:00:00Z"
274 }
275 }
276 ]
277 });
278 let res = client
279 .post(format!(
280 "{}/xrpc/com.atproto.repo.applyWrites",
281 base_url().await
282 ))
283 .json(&payload)
284 .send()
285 .await
286 .expect("Failed to send request");
287 assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
288}
289#[tokio::test]
290async fn test_apply_writes_empty_writes() {
291 let client = client();
292 let (token, did) = create_account_and_login(&client).await;
293 let payload = json!({
294 "repo": did,
295 "writes": []
296 });
297 let res = client
298 .post(format!(
299 "{}/xrpc/com.atproto.repo.applyWrites",
300 base_url().await
301 ))
302 .bearer_auth(&token)
303 .json(&payload)
304 .send()
305 .await
306 .expect("Failed to send request");
307 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
308}