1use crate::error::Error;
2use crate::types::*;
3
4pub struct FakeCloud {
6 base_url: String,
7 client: reqwest::Client,
8}
9
10impl FakeCloud {
11 pub fn new(base_url: &str) -> Self {
13 Self {
14 base_url: base_url.trim_end_matches('/').to_string(),
15 client: reqwest::Client::new(),
16 }
17 }
18
19 pub async fn health(&self) -> Result<HealthResponse, Error> {
23 let resp = self
24 .client
25 .get(format!("{}/_fakecloud/health", self.base_url))
26 .send()
27 .await?;
28 Self::parse(resp).await
29 }
30
31 pub async fn reset(&self) -> Result<ResetResponse, Error> {
33 let resp = self
34 .client
35 .post(format!("{}/_reset", self.base_url))
36 .send()
37 .await?;
38 Self::parse(resp).await
39 }
40
41 pub async fn reset_service(&self, service: &str) -> Result<ResetServiceResponse, Error> {
43 let resp = self
44 .client
45 .post(format!("{}/_fakecloud/reset/{}", self.base_url, service))
46 .send()
47 .await?;
48 Self::parse(resp).await
49 }
50
51 pub fn lambda(&self) -> LambdaClient<'_> {
54 LambdaClient { fc: self }
55 }
56
57 pub fn ses(&self) -> SesClient<'_> {
58 SesClient { fc: self }
59 }
60
61 pub fn sns(&self) -> SnsClient<'_> {
62 SnsClient { fc: self }
63 }
64
65 pub fn sqs(&self) -> SqsClient<'_> {
66 SqsClient { fc: self }
67 }
68
69 pub fn events(&self) -> EventsClient<'_> {
70 EventsClient { fc: self }
71 }
72
73 pub fn s3(&self) -> S3Client<'_> {
74 S3Client { fc: self }
75 }
76
77 pub fn dynamodb(&self) -> DynamoDbClient<'_> {
78 DynamoDbClient { fc: self }
79 }
80
81 pub fn secretsmanager(&self) -> SecretsManagerClient<'_> {
82 SecretsManagerClient { fc: self }
83 }
84
85 pub fn cognito(&self) -> CognitoClient<'_> {
86 CognitoClient { fc: self }
87 }
88
89 async fn parse<T: serde::de::DeserializeOwned>(resp: reqwest::Response) -> Result<T, Error> {
92 let status = resp.status().as_u16();
93 if !resp.status().is_success() {
94 let body = resp.text().await.unwrap_or_default();
95 return Err(Error::Api { status, body });
96 }
97 Ok(resp.json::<T>().await?)
98 }
99}
100
101pub struct LambdaClient<'a> {
104 fc: &'a FakeCloud,
105}
106
107impl LambdaClient<'_> {
108 pub async fn get_invocations(&self) -> Result<LambdaInvocationsResponse, Error> {
110 let resp = self
111 .fc
112 .client
113 .get(format!(
114 "{}/_fakecloud/lambda/invocations",
115 self.fc.base_url
116 ))
117 .send()
118 .await?;
119 FakeCloud::parse(resp).await
120 }
121
122 pub async fn get_warm_containers(&self) -> Result<WarmContainersResponse, Error> {
124 let resp = self
125 .fc
126 .client
127 .get(format!(
128 "{}/_fakecloud/lambda/warm-containers",
129 self.fc.base_url
130 ))
131 .send()
132 .await?;
133 FakeCloud::parse(resp).await
134 }
135
136 pub async fn evict_container(
138 &self,
139 function_name: &str,
140 ) -> Result<EvictContainerResponse, Error> {
141 let resp = self
142 .fc
143 .client
144 .post(format!(
145 "{}/_fakecloud/lambda/{}/evict-container",
146 self.fc.base_url, function_name
147 ))
148 .send()
149 .await?;
150 FakeCloud::parse(resp).await
151 }
152}
153
154pub struct SesClient<'a> {
157 fc: &'a FakeCloud,
158}
159
160impl SesClient<'_> {
161 pub async fn get_emails(&self) -> Result<SesEmailsResponse, Error> {
163 let resp = self
164 .fc
165 .client
166 .get(format!("{}/_fakecloud/ses/emails", self.fc.base_url))
167 .send()
168 .await?;
169 FakeCloud::parse(resp).await
170 }
171
172 pub async fn simulate_inbound(
174 &self,
175 req: &InboundEmailRequest,
176 ) -> Result<InboundEmailResponse, Error> {
177 let resp = self
178 .fc
179 .client
180 .post(format!("{}/_fakecloud/ses/inbound", self.fc.base_url))
181 .json(req)
182 .send()
183 .await?;
184 FakeCloud::parse(resp).await
185 }
186}
187
188pub struct SnsClient<'a> {
191 fc: &'a FakeCloud,
192}
193
194impl SnsClient<'_> {
195 pub async fn get_messages(&self) -> Result<SnsMessagesResponse, Error> {
197 let resp = self
198 .fc
199 .client
200 .get(format!("{}/_fakecloud/sns/messages", self.fc.base_url))
201 .send()
202 .await?;
203 FakeCloud::parse(resp).await
204 }
205
206 pub async fn get_pending_confirmations(&self) -> Result<PendingConfirmationsResponse, Error> {
208 let resp = self
209 .fc
210 .client
211 .get(format!(
212 "{}/_fakecloud/sns/pending-confirmations",
213 self.fc.base_url
214 ))
215 .send()
216 .await?;
217 FakeCloud::parse(resp).await
218 }
219
220 pub async fn confirm_subscription(
222 &self,
223 req: &ConfirmSubscriptionRequest,
224 ) -> Result<ConfirmSubscriptionResponse, Error> {
225 let resp = self
226 .fc
227 .client
228 .post(format!(
229 "{}/_fakecloud/sns/confirm-subscription",
230 self.fc.base_url
231 ))
232 .json(req)
233 .send()
234 .await?;
235 FakeCloud::parse(resp).await
236 }
237}
238
239pub struct SqsClient<'a> {
242 fc: &'a FakeCloud,
243}
244
245impl SqsClient<'_> {
246 pub async fn get_messages(&self) -> Result<SqsMessagesResponse, Error> {
248 let resp = self
249 .fc
250 .client
251 .get(format!("{}/_fakecloud/sqs/messages", self.fc.base_url))
252 .send()
253 .await?;
254 FakeCloud::parse(resp).await
255 }
256
257 pub async fn tick_expiration(&self) -> Result<ExpirationTickResponse, Error> {
259 let resp = self
260 .fc
261 .client
262 .post(format!(
263 "{}/_fakecloud/sqs/expiration-processor/tick",
264 self.fc.base_url
265 ))
266 .send()
267 .await?;
268 FakeCloud::parse(resp).await
269 }
270
271 pub async fn force_dlq(&self, queue_name: &str) -> Result<ForceDlqResponse, Error> {
273 let resp = self
274 .fc
275 .client
276 .post(format!(
277 "{}/_fakecloud/sqs/{}/force-dlq",
278 self.fc.base_url, queue_name
279 ))
280 .send()
281 .await?;
282 FakeCloud::parse(resp).await
283 }
284}
285
286pub struct EventsClient<'a> {
289 fc: &'a FakeCloud,
290}
291
292impl EventsClient<'_> {
293 pub async fn get_history(&self) -> Result<EventHistoryResponse, Error> {
295 let resp = self
296 .fc
297 .client
298 .get(format!("{}/_fakecloud/events/history", self.fc.base_url))
299 .send()
300 .await?;
301 FakeCloud::parse(resp).await
302 }
303
304 pub async fn fire_rule(&self, req: &FireRuleRequest) -> Result<FireRuleResponse, Error> {
306 let resp = self
307 .fc
308 .client
309 .post(format!("{}/_fakecloud/events/fire-rule", self.fc.base_url))
310 .json(req)
311 .send()
312 .await?;
313 FakeCloud::parse(resp).await
314 }
315}
316
317pub struct S3Client<'a> {
320 fc: &'a FakeCloud,
321}
322
323impl S3Client<'_> {
324 pub async fn get_notifications(&self) -> Result<S3NotificationsResponse, Error> {
326 let resp = self
327 .fc
328 .client
329 .get(format!("{}/_fakecloud/s3/notifications", self.fc.base_url))
330 .send()
331 .await?;
332 FakeCloud::parse(resp).await
333 }
334
335 pub async fn tick_lifecycle(&self) -> Result<LifecycleTickResponse, Error> {
337 let resp = self
338 .fc
339 .client
340 .post(format!(
341 "{}/_fakecloud/s3/lifecycle-processor/tick",
342 self.fc.base_url
343 ))
344 .send()
345 .await?;
346 FakeCloud::parse(resp).await
347 }
348}
349
350pub struct DynamoDbClient<'a> {
353 fc: &'a FakeCloud,
354}
355
356impl DynamoDbClient<'_> {
357 pub async fn tick_ttl(&self) -> Result<TtlTickResponse, Error> {
359 let resp = self
360 .fc
361 .client
362 .post(format!(
363 "{}/_fakecloud/dynamodb/ttl-processor/tick",
364 self.fc.base_url
365 ))
366 .send()
367 .await?;
368 FakeCloud::parse(resp).await
369 }
370}
371
372pub struct SecretsManagerClient<'a> {
375 fc: &'a FakeCloud,
376}
377
378impl SecretsManagerClient<'_> {
379 pub async fn tick_rotation(&self) -> Result<RotationTickResponse, Error> {
381 let resp = self
382 .fc
383 .client
384 .post(format!(
385 "{}/_fakecloud/secretsmanager/rotation-scheduler/tick",
386 self.fc.base_url
387 ))
388 .send()
389 .await?;
390 FakeCloud::parse(resp).await
391 }
392}
393
394pub struct CognitoClient<'a> {
397 fc: &'a FakeCloud,
398}
399
400impl CognitoClient<'_> {
401 pub async fn get_user_codes(
403 &self,
404 pool_id: &str,
405 username: &str,
406 ) -> Result<UserConfirmationCodes, Error> {
407 let resp = self
408 .fc
409 .client
410 .get(format!(
411 "{}/_fakecloud/cognito/confirmation-codes/{}/{}",
412 self.fc.base_url, pool_id, username
413 ))
414 .send()
415 .await?;
416 FakeCloud::parse(resp).await
417 }
418
419 pub async fn get_confirmation_codes(&self) -> Result<ConfirmationCodesResponse, Error> {
421 let resp = self
422 .fc
423 .client
424 .get(format!(
425 "{}/_fakecloud/cognito/confirmation-codes",
426 self.fc.base_url
427 ))
428 .send()
429 .await?;
430 FakeCloud::parse(resp).await
431 }
432
433 pub async fn confirm_user(
435 &self,
436 req: &ConfirmUserRequest,
437 ) -> Result<ConfirmUserResponse, Error> {
438 let resp = self
439 .fc
440 .client
441 .post(format!(
442 "{}/_fakecloud/cognito/confirm-user",
443 self.fc.base_url
444 ))
445 .json(req)
446 .send()
447 .await?;
448 let status = resp.status().as_u16();
450 let body: ConfirmUserResponse = resp.json().await?;
451 if status == 404 {
452 return Err(Error::Api {
453 status,
454 body: body.error.unwrap_or_default(),
455 });
456 }
457 Ok(body)
458 }
459
460 pub async fn get_tokens(&self) -> Result<TokensResponse, Error> {
462 let resp = self
463 .fc
464 .client
465 .get(format!("{}/_fakecloud/cognito/tokens", self.fc.base_url))
466 .send()
467 .await?;
468 FakeCloud::parse(resp).await
469 }
470
471 pub async fn expire_tokens(
473 &self,
474 req: &ExpireTokensRequest,
475 ) -> Result<ExpireTokensResponse, Error> {
476 let resp = self
477 .fc
478 .client
479 .post(format!(
480 "{}/_fakecloud/cognito/expire-tokens",
481 self.fc.base_url
482 ))
483 .json(req)
484 .send()
485 .await?;
486 FakeCloud::parse(resp).await
487 }
488
489 pub async fn get_auth_events(&self) -> Result<AuthEventsResponse, Error> {
491 let resp = self
492 .fc
493 .client
494 .get(format!(
495 "{}/_fakecloud/cognito/auth-events",
496 self.fc.base_url
497 ))
498 .send()
499 .await?;
500 FakeCloud::parse(resp).await
501 }
502}