Skip to main content

max / makenotwork

5.4 KB · 182 lines History Blame Raw
1 //! Content insertion workflow tests: presign, confirm, rename, delete.
2 //!
3 //! These tests use the in-memory storage backend.
4
5 use crate::harness::TestHarness;
6 use serde_json::Value;
7
8 /// Setup: creator user logged in with small_files tier. Returns user_id.
9 async fn setup_creator(h: &mut TestHarness) -> String {
10 let user_id = h.create_creator("insuser").await;
11 h.grant_tier(user_id, "small_files").await;
12 user_id.to_string()
13 }
14
15 #[tokio::test]
16 async fn presign_requires_auth() {
17 let mut h = TestHarness::with_storage().await;
18
19 let resp = h
20 .client
21 .post_json(
22 "/api/users/me/insertions/presign",
23 r#"{"file_name": "test.mp3", "content_type": "audio/mpeg"}"#,
24 )
25 .await;
26 assert!(
27 resp.status.is_client_error() || resp.status.is_redirection(),
28 "Unauthenticated presign should be rejected: {} {}",
29 resp.status, resp.text
30 );
31 }
32
33 #[tokio::test]
34 async fn presign_invalid_content_type_rejected() {
35 let mut h = TestHarness::with_storage().await;
36 let _user_id = setup_creator(&mut h).await;
37
38 let resp = h
39 .client
40 .post_json(
41 "/api/users/me/insertions/presign",
42 r#"{"file_name": "evil.exe", "content_type": "application/octet-stream"}"#,
43 )
44 .await;
45 assert!(
46 resp.status.is_client_error(),
47 "Invalid content type should be rejected: {} {}",
48 resp.status, resp.text
49 );
50 }
51
52 #[tokio::test]
53 async fn presign_valid_audio_succeeds() {
54 let mut h = TestHarness::with_storage().await;
55 let _user_id = setup_creator(&mut h).await;
56
57 let resp = h
58 .client
59 .post_json(
60 "/api/users/me/insertions/presign",
61 r#"{"file_name": "intro.mp3", "content_type": "audio/mpeg"}"#,
62 )
63 .await;
64 assert!(
65 resp.status.is_success(),
66 "Valid presign should succeed: {} {}",
67 resp.status, resp.text
68 );
69 let body: Value = resp.json();
70 assert!(body["upload_url"].is_string(), "Should return upload_url");
71 assert!(body["s3_key"].is_string(), "Should return s3_key");
72 }
73
74 #[tokio::test]
75 async fn confirm_nonexistent_object_rejected() {
76 let mut h = TestHarness::with_storage().await;
77 let _user_id = setup_creator(&mut h).await;
78
79 let resp = h
80 .client
81 .post_json(
82 "/api/users/me/insertions/confirm",
83 r#"{"s3_key": "nonexistent/key.mp3", "title": "Test", "duration_ms": 5000, "file_size": 1024, "mime_type": "audio/mpeg"}"#,
84 )
85 .await;
86 assert!(
87 resp.status.is_client_error() || resp.status.is_server_error(),
88 "Confirming nonexistent object should fail: {} {}",
89 resp.status, resp.text
90 );
91 }
92
93 #[tokio::test]
94 async fn confirm_with_object_succeeds() {
95 let mut h = TestHarness::with_storage().await;
96 let user_id = setup_creator(&mut h).await;
97
98 // Pre-populate storage with a fake object (key must match user_id prefix)
99 let s3_key = format!("{}/insertions/intro.mp3", user_id);
100 h.storage.as_ref().unwrap().put(&s3_key, vec![0u8; 1024]);
101
102 let resp = h
103 .client
104 .post_json(
105 "/api/users/me/insertions/confirm",
106 &format!(
107 r#"{{"s3_key": "{}", "title": "Intro Music", "duration_ms": 5000, "file_size": 1024, "mime_type": "audio/mpeg"}}"#,
108 s3_key
109 ),
110 )
111 .await;
112 assert!(
113 resp.status.is_success(),
114 "Confirm with existing object should succeed: {} {}",
115 resp.status, resp.text
116 );
117 let body: Value = resp.json();
118 assert_eq!(body["title"].as_str().unwrap(), "Intro Music");
119 }
120
121 #[tokio::test]
122 async fn confirm_empty_title_rejected() {
123 let mut h = TestHarness::with_storage().await;
124 let user_id = setup_creator(&mut h).await;
125
126 let s3_key = format!("{}/insertions/empty.mp3", user_id);
127 h.storage.as_ref().unwrap().put(&s3_key, vec![0u8; 1024]);
128
129 let resp = h
130 .client
131 .post_json(
132 "/api/users/me/insertions/confirm",
133 &format!(
134 r#"{{"s3_key": "{}", "title": "", "duration_ms": 5000, "file_size": 1024, "mime_type": "audio/mpeg"}}"#,
135 s3_key
136 ),
137 )
138 .await;
139 assert!(
140 resp.status.is_client_error(),
141 "Empty title should be rejected: {} {}",
142 resp.status, resp.text
143 );
144 }
145
146 #[tokio::test]
147 async fn delete_nonexistent_insertion_returns_404() {
148 let mut h = TestHarness::with_storage().await;
149 let _user_id = setup_creator(&mut h).await;
150
151 let fake_id = uuid::Uuid::new_v4();
152 let resp = h
153 .client
154 .delete(&format!("/api/insertions/{}", fake_id))
155 .await;
156 assert_eq!(
157 resp.status, 404,
158 "Deleting nonexistent insertion should return 404: {} {}",
159 resp.status, resp.text
160 );
161 }
162
163 #[tokio::test]
164 async fn rename_nonexistent_insertion_returns_404() {
165 let mut h = TestHarness::with_storage().await;
166 let _user_id = setup_creator(&mut h).await;
167
168 let fake_id = uuid::Uuid::new_v4();
169 let resp = h
170 .client
171 .put_json(
172 &format!("/api/insertions/{}", fake_id),
173 r#"{"title": "New Name"}"#,
174 )
175 .await;
176 assert_eq!(
177 resp.status, 404,
178 "Renaming nonexistent insertion should return 404: {} {}",
179 resp.status, resp.text
180 );
181 }
182