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 pub fn rds(&self) -> RdsClient<'_> {
90 RdsClient { fc: self }
91 }
92
93 pub fn elasticache(&self) -> ElastiCacheClient<'_> {
94 ElastiCacheClient { fc: self }
95 }
96
97 pub fn apigatewayv2(&self) -> ApiGatewayV2Client<'_> {
98 ApiGatewayV2Client { fc: self }
99 }
100
101 pub fn stepfunctions(&self) -> StepFunctionsClient<'_> {
102 StepFunctionsClient { fc: self }
103 }
104
105 async fn parse<T: serde::de::DeserializeOwned>(resp: reqwest::Response) -> Result<T, Error> {
108 let status = resp.status().as_u16();
109 if !resp.status().is_success() {
110 let body = resp.text().await.unwrap_or_default();
111 return Err(Error::Api { status, body });
112 }
113 Ok(resp.json::<T>().await?)
114 }
115}
116
117pub struct RdsClient<'a> {
120 fc: &'a FakeCloud,
121}
122
123impl RdsClient<'_> {
124 pub async fn get_instances(&self) -> Result<RdsInstancesResponse, Error> {
126 let resp = self
127 .fc
128 .client
129 .get(format!("{}/_fakecloud/rds/instances", self.fc.base_url))
130 .send()
131 .await?;
132 FakeCloud::parse(resp).await
133 }
134}
135
136pub struct ElastiCacheClient<'a> {
139 fc: &'a FakeCloud,
140}
141
142impl ElastiCacheClient<'_> {
143 pub async fn get_clusters(&self) -> Result<ElastiCacheClustersResponse, Error> {
145 let resp = self
146 .fc
147 .client
148 .get(format!(
149 "{}/_fakecloud/elasticache/clusters",
150 self.fc.base_url
151 ))
152 .send()
153 .await?;
154 FakeCloud::parse(resp).await
155 }
156
157 pub async fn get_replication_groups(
159 &self,
160 ) -> Result<ElastiCacheReplicationGroupsResponse, Error> {
161 let resp = self
162 .fc
163 .client
164 .get(format!(
165 "{}/_fakecloud/elasticache/replication-groups",
166 self.fc.base_url
167 ))
168 .send()
169 .await?;
170 FakeCloud::parse(resp).await
171 }
172
173 pub async fn get_serverless_caches(
175 &self,
176 ) -> Result<ElastiCacheServerlessCachesResponse, Error> {
177 let resp = self
178 .fc
179 .client
180 .get(format!(
181 "{}/_fakecloud/elasticache/serverless-caches",
182 self.fc.base_url
183 ))
184 .send()
185 .await?;
186 FakeCloud::parse(resp).await
187 }
188}
189
190pub struct LambdaClient<'a> {
193 fc: &'a FakeCloud,
194}
195
196impl LambdaClient<'_> {
197 pub async fn get_invocations(&self) -> Result<LambdaInvocationsResponse, Error> {
199 let resp = self
200 .fc
201 .client
202 .get(format!(
203 "{}/_fakecloud/lambda/invocations",
204 self.fc.base_url
205 ))
206 .send()
207 .await?;
208 FakeCloud::parse(resp).await
209 }
210
211 pub async fn get_warm_containers(&self) -> Result<WarmContainersResponse, Error> {
213 let resp = self
214 .fc
215 .client
216 .get(format!(
217 "{}/_fakecloud/lambda/warm-containers",
218 self.fc.base_url
219 ))
220 .send()
221 .await?;
222 FakeCloud::parse(resp).await
223 }
224
225 pub async fn evict_container(
227 &self,
228 function_name: &str,
229 ) -> Result<EvictContainerResponse, Error> {
230 let resp = self
231 .fc
232 .client
233 .post(format!(
234 "{}/_fakecloud/lambda/{}/evict-container",
235 self.fc.base_url, function_name
236 ))
237 .send()
238 .await?;
239 FakeCloud::parse(resp).await
240 }
241}
242
243pub struct SesClient<'a> {
246 fc: &'a FakeCloud,
247}
248
249impl SesClient<'_> {
250 pub async fn get_emails(&self) -> Result<SesEmailsResponse, Error> {
252 let resp = self
253 .fc
254 .client
255 .get(format!("{}/_fakecloud/ses/emails", self.fc.base_url))
256 .send()
257 .await?;
258 FakeCloud::parse(resp).await
259 }
260
261 pub async fn simulate_inbound(
263 &self,
264 req: &InboundEmailRequest,
265 ) -> Result<InboundEmailResponse, Error> {
266 let resp = self
267 .fc
268 .client
269 .post(format!("{}/_fakecloud/ses/inbound", self.fc.base_url))
270 .json(req)
271 .send()
272 .await?;
273 FakeCloud::parse(resp).await
274 }
275}
276
277pub struct SnsClient<'a> {
280 fc: &'a FakeCloud,
281}
282
283impl SnsClient<'_> {
284 pub async fn get_messages(&self) -> Result<SnsMessagesResponse, Error> {
286 let resp = self
287 .fc
288 .client
289 .get(format!("{}/_fakecloud/sns/messages", self.fc.base_url))
290 .send()
291 .await?;
292 FakeCloud::parse(resp).await
293 }
294
295 pub async fn get_pending_confirmations(&self) -> Result<PendingConfirmationsResponse, Error> {
297 let resp = self
298 .fc
299 .client
300 .get(format!(
301 "{}/_fakecloud/sns/pending-confirmations",
302 self.fc.base_url
303 ))
304 .send()
305 .await?;
306 FakeCloud::parse(resp).await
307 }
308
309 pub async fn confirm_subscription(
311 &self,
312 req: &ConfirmSubscriptionRequest,
313 ) -> Result<ConfirmSubscriptionResponse, Error> {
314 let resp = self
315 .fc
316 .client
317 .post(format!(
318 "{}/_fakecloud/sns/confirm-subscription",
319 self.fc.base_url
320 ))
321 .json(req)
322 .send()
323 .await?;
324 FakeCloud::parse(resp).await
325 }
326}
327
328pub struct SqsClient<'a> {
331 fc: &'a FakeCloud,
332}
333
334impl SqsClient<'_> {
335 pub async fn get_messages(&self) -> Result<SqsMessagesResponse, Error> {
337 let resp = self
338 .fc
339 .client
340 .get(format!("{}/_fakecloud/sqs/messages", self.fc.base_url))
341 .send()
342 .await?;
343 FakeCloud::parse(resp).await
344 }
345
346 pub async fn tick_expiration(&self) -> Result<ExpirationTickResponse, Error> {
348 let resp = self
349 .fc
350 .client
351 .post(format!(
352 "{}/_fakecloud/sqs/expiration-processor/tick",
353 self.fc.base_url
354 ))
355 .send()
356 .await?;
357 FakeCloud::parse(resp).await
358 }
359
360 pub async fn force_dlq(&self, queue_name: &str) -> Result<ForceDlqResponse, Error> {
362 let resp = self
363 .fc
364 .client
365 .post(format!(
366 "{}/_fakecloud/sqs/{}/force-dlq",
367 self.fc.base_url, queue_name
368 ))
369 .send()
370 .await?;
371 FakeCloud::parse(resp).await
372 }
373}
374
375pub struct EventsClient<'a> {
378 fc: &'a FakeCloud,
379}
380
381impl EventsClient<'_> {
382 pub async fn get_history(&self) -> Result<EventHistoryResponse, Error> {
384 let resp = self
385 .fc
386 .client
387 .get(format!("{}/_fakecloud/events/history", self.fc.base_url))
388 .send()
389 .await?;
390 FakeCloud::parse(resp).await
391 }
392
393 pub async fn fire_rule(&self, req: &FireRuleRequest) -> Result<FireRuleResponse, Error> {
395 let resp = self
396 .fc
397 .client
398 .post(format!("{}/_fakecloud/events/fire-rule", self.fc.base_url))
399 .json(req)
400 .send()
401 .await?;
402 FakeCloud::parse(resp).await
403 }
404}
405
406pub struct S3Client<'a> {
409 fc: &'a FakeCloud,
410}
411
412impl S3Client<'_> {
413 pub async fn get_notifications(&self) -> Result<S3NotificationsResponse, Error> {
415 let resp = self
416 .fc
417 .client
418 .get(format!("{}/_fakecloud/s3/notifications", self.fc.base_url))
419 .send()
420 .await?;
421 FakeCloud::parse(resp).await
422 }
423
424 pub async fn tick_lifecycle(&self) -> Result<LifecycleTickResponse, Error> {
426 let resp = self
427 .fc
428 .client
429 .post(format!(
430 "{}/_fakecloud/s3/lifecycle-processor/tick",
431 self.fc.base_url
432 ))
433 .send()
434 .await?;
435 FakeCloud::parse(resp).await
436 }
437}
438
439pub struct DynamoDbClient<'a> {
442 fc: &'a FakeCloud,
443}
444
445impl DynamoDbClient<'_> {
446 pub async fn tick_ttl(&self) -> Result<TtlTickResponse, Error> {
448 let resp = self
449 .fc
450 .client
451 .post(format!(
452 "{}/_fakecloud/dynamodb/ttl-processor/tick",
453 self.fc.base_url
454 ))
455 .send()
456 .await?;
457 FakeCloud::parse(resp).await
458 }
459}
460
461pub struct SecretsManagerClient<'a> {
464 fc: &'a FakeCloud,
465}
466
467impl SecretsManagerClient<'_> {
468 pub async fn tick_rotation(&self) -> Result<RotationTickResponse, Error> {
470 let resp = self
471 .fc
472 .client
473 .post(format!(
474 "{}/_fakecloud/secretsmanager/rotation-scheduler/tick",
475 self.fc.base_url
476 ))
477 .send()
478 .await?;
479 FakeCloud::parse(resp).await
480 }
481}
482
483pub struct CognitoClient<'a> {
486 fc: &'a FakeCloud,
487}
488
489impl CognitoClient<'_> {
490 pub async fn get_user_codes(
492 &self,
493 pool_id: &str,
494 username: &str,
495 ) -> Result<UserConfirmationCodes, Error> {
496 let resp = self
497 .fc
498 .client
499 .get(format!(
500 "{}/_fakecloud/cognito/confirmation-codes/{}/{}",
501 self.fc.base_url, pool_id, username
502 ))
503 .send()
504 .await?;
505 FakeCloud::parse(resp).await
506 }
507
508 pub async fn get_confirmation_codes(&self) -> Result<ConfirmationCodesResponse, Error> {
510 let resp = self
511 .fc
512 .client
513 .get(format!(
514 "{}/_fakecloud/cognito/confirmation-codes",
515 self.fc.base_url
516 ))
517 .send()
518 .await?;
519 FakeCloud::parse(resp).await
520 }
521
522 pub async fn confirm_user(
524 &self,
525 req: &ConfirmUserRequest,
526 ) -> Result<ConfirmUserResponse, Error> {
527 let resp = self
528 .fc
529 .client
530 .post(format!(
531 "{}/_fakecloud/cognito/confirm-user",
532 self.fc.base_url
533 ))
534 .json(req)
535 .send()
536 .await?;
537 let status = resp.status().as_u16();
538 let body: ConfirmUserResponse = resp.json().await?;
539 if status >= 400 {
540 return Err(Error::Api {
541 status,
542 body: body.error.unwrap_or_default(),
543 });
544 }
545 Ok(body)
546 }
547
548 pub async fn get_tokens(&self) -> Result<TokensResponse, Error> {
550 let resp = self
551 .fc
552 .client
553 .get(format!("{}/_fakecloud/cognito/tokens", self.fc.base_url))
554 .send()
555 .await?;
556 FakeCloud::parse(resp).await
557 }
558
559 pub async fn expire_tokens(
561 &self,
562 req: &ExpireTokensRequest,
563 ) -> Result<ExpireTokensResponse, Error> {
564 let resp = self
565 .fc
566 .client
567 .post(format!(
568 "{}/_fakecloud/cognito/expire-tokens",
569 self.fc.base_url
570 ))
571 .json(req)
572 .send()
573 .await?;
574 FakeCloud::parse(resp).await
575 }
576
577 pub async fn get_auth_events(&self) -> Result<AuthEventsResponse, Error> {
579 let resp = self
580 .fc
581 .client
582 .get(format!(
583 "{}/_fakecloud/cognito/auth-events",
584 self.fc.base_url
585 ))
586 .send()
587 .await?;
588 FakeCloud::parse(resp).await
589 }
590}
591
592pub struct ApiGatewayV2Client<'a> {
595 fc: &'a FakeCloud,
596}
597
598impl ApiGatewayV2Client<'_> {
599 pub async fn get_requests(&self) -> Result<ApiGatewayV2RequestsResponse, Error> {
601 let resp = self
602 .fc
603 .client
604 .get(format!(
605 "{}/_fakecloud/apigatewayv2/requests",
606 self.fc.base_url
607 ))
608 .send()
609 .await?;
610 FakeCloud::parse(resp).await
611 }
612}
613
614pub struct StepFunctionsClient<'a> {
617 fc: &'a FakeCloud,
618}
619
620impl StepFunctionsClient<'_> {
621 pub async fn get_executions(&self) -> Result<StepFunctionsExecutionsResponse, Error> {
623 let resp = self
624 .fc
625 .client
626 .get(format!(
627 "{}/_fakecloud/stepfunctions/executions",
628 self.fc.base_url
629 ))
630 .send()
631 .await?;
632 FakeCloud::parse(resp).await
633 }
634}