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 async fn parse<T: serde::de::DeserializeOwned>(resp: reqwest::Response) -> Result<T, Error> {
100 let status = resp.status().as_u16();
101 if !resp.status().is_success() {
102 let body = resp.text().await.unwrap_or_default();
103 return Err(Error::Api { status, body });
104 }
105 Ok(resp.json::<T>().await?)
106 }
107}
108
109pub struct RdsClient<'a> {
112 fc: &'a FakeCloud,
113}
114
115impl RdsClient<'_> {
116 pub async fn get_instances(&self) -> Result<RdsInstancesResponse, Error> {
118 let resp = self
119 .fc
120 .client
121 .get(format!("{}/_fakecloud/rds/instances", self.fc.base_url))
122 .send()
123 .await?;
124 FakeCloud::parse(resp).await
125 }
126}
127
128pub struct ElastiCacheClient<'a> {
131 fc: &'a FakeCloud,
132}
133
134impl ElastiCacheClient<'_> {
135 pub async fn get_clusters(&self) -> Result<ElastiCacheClustersResponse, Error> {
137 let resp = self
138 .fc
139 .client
140 .get(format!(
141 "{}/_fakecloud/elasticache/clusters",
142 self.fc.base_url
143 ))
144 .send()
145 .await?;
146 FakeCloud::parse(resp).await
147 }
148
149 pub async fn get_replication_groups(
151 &self,
152 ) -> Result<ElastiCacheReplicationGroupsResponse, Error> {
153 let resp = self
154 .fc
155 .client
156 .get(format!(
157 "{}/_fakecloud/elasticache/replication-groups",
158 self.fc.base_url
159 ))
160 .send()
161 .await?;
162 FakeCloud::parse(resp).await
163 }
164
165 pub async fn get_serverless_caches(
167 &self,
168 ) -> Result<ElastiCacheServerlessCachesResponse, Error> {
169 let resp = self
170 .fc
171 .client
172 .get(format!(
173 "{}/_fakecloud/elasticache/serverless-caches",
174 self.fc.base_url
175 ))
176 .send()
177 .await?;
178 FakeCloud::parse(resp).await
179 }
180}
181
182pub struct LambdaClient<'a> {
185 fc: &'a FakeCloud,
186}
187
188impl LambdaClient<'_> {
189 pub async fn get_invocations(&self) -> Result<LambdaInvocationsResponse, Error> {
191 let resp = self
192 .fc
193 .client
194 .get(format!(
195 "{}/_fakecloud/lambda/invocations",
196 self.fc.base_url
197 ))
198 .send()
199 .await?;
200 FakeCloud::parse(resp).await
201 }
202
203 pub async fn get_warm_containers(&self) -> Result<WarmContainersResponse, Error> {
205 let resp = self
206 .fc
207 .client
208 .get(format!(
209 "{}/_fakecloud/lambda/warm-containers",
210 self.fc.base_url
211 ))
212 .send()
213 .await?;
214 FakeCloud::parse(resp).await
215 }
216
217 pub async fn evict_container(
219 &self,
220 function_name: &str,
221 ) -> Result<EvictContainerResponse, Error> {
222 let resp = self
223 .fc
224 .client
225 .post(format!(
226 "{}/_fakecloud/lambda/{}/evict-container",
227 self.fc.base_url, function_name
228 ))
229 .send()
230 .await?;
231 FakeCloud::parse(resp).await
232 }
233}
234
235pub struct SesClient<'a> {
238 fc: &'a FakeCloud,
239}
240
241impl SesClient<'_> {
242 pub async fn get_emails(&self) -> Result<SesEmailsResponse, Error> {
244 let resp = self
245 .fc
246 .client
247 .get(format!("{}/_fakecloud/ses/emails", self.fc.base_url))
248 .send()
249 .await?;
250 FakeCloud::parse(resp).await
251 }
252
253 pub async fn simulate_inbound(
255 &self,
256 req: &InboundEmailRequest,
257 ) -> Result<InboundEmailResponse, Error> {
258 let resp = self
259 .fc
260 .client
261 .post(format!("{}/_fakecloud/ses/inbound", self.fc.base_url))
262 .json(req)
263 .send()
264 .await?;
265 FakeCloud::parse(resp).await
266 }
267}
268
269pub struct SnsClient<'a> {
272 fc: &'a FakeCloud,
273}
274
275impl SnsClient<'_> {
276 pub async fn get_messages(&self) -> Result<SnsMessagesResponse, Error> {
278 let resp = self
279 .fc
280 .client
281 .get(format!("{}/_fakecloud/sns/messages", self.fc.base_url))
282 .send()
283 .await?;
284 FakeCloud::parse(resp).await
285 }
286
287 pub async fn get_pending_confirmations(&self) -> Result<PendingConfirmationsResponse, Error> {
289 let resp = self
290 .fc
291 .client
292 .get(format!(
293 "{}/_fakecloud/sns/pending-confirmations",
294 self.fc.base_url
295 ))
296 .send()
297 .await?;
298 FakeCloud::parse(resp).await
299 }
300
301 pub async fn confirm_subscription(
303 &self,
304 req: &ConfirmSubscriptionRequest,
305 ) -> Result<ConfirmSubscriptionResponse, Error> {
306 let resp = self
307 .fc
308 .client
309 .post(format!(
310 "{}/_fakecloud/sns/confirm-subscription",
311 self.fc.base_url
312 ))
313 .json(req)
314 .send()
315 .await?;
316 FakeCloud::parse(resp).await
317 }
318}
319
320pub struct SqsClient<'a> {
323 fc: &'a FakeCloud,
324}
325
326impl SqsClient<'_> {
327 pub async fn get_messages(&self) -> Result<SqsMessagesResponse, Error> {
329 let resp = self
330 .fc
331 .client
332 .get(format!("{}/_fakecloud/sqs/messages", self.fc.base_url))
333 .send()
334 .await?;
335 FakeCloud::parse(resp).await
336 }
337
338 pub async fn tick_expiration(&self) -> Result<ExpirationTickResponse, Error> {
340 let resp = self
341 .fc
342 .client
343 .post(format!(
344 "{}/_fakecloud/sqs/expiration-processor/tick",
345 self.fc.base_url
346 ))
347 .send()
348 .await?;
349 FakeCloud::parse(resp).await
350 }
351
352 pub async fn force_dlq(&self, queue_name: &str) -> Result<ForceDlqResponse, Error> {
354 let resp = self
355 .fc
356 .client
357 .post(format!(
358 "{}/_fakecloud/sqs/{}/force-dlq",
359 self.fc.base_url, queue_name
360 ))
361 .send()
362 .await?;
363 FakeCloud::parse(resp).await
364 }
365}
366
367pub struct EventsClient<'a> {
370 fc: &'a FakeCloud,
371}
372
373impl EventsClient<'_> {
374 pub async fn get_history(&self) -> Result<EventHistoryResponse, Error> {
376 let resp = self
377 .fc
378 .client
379 .get(format!("{}/_fakecloud/events/history", self.fc.base_url))
380 .send()
381 .await?;
382 FakeCloud::parse(resp).await
383 }
384
385 pub async fn fire_rule(&self, req: &FireRuleRequest) -> Result<FireRuleResponse, Error> {
387 let resp = self
388 .fc
389 .client
390 .post(format!("{}/_fakecloud/events/fire-rule", self.fc.base_url))
391 .json(req)
392 .send()
393 .await?;
394 FakeCloud::parse(resp).await
395 }
396}
397
398pub struct S3Client<'a> {
401 fc: &'a FakeCloud,
402}
403
404impl S3Client<'_> {
405 pub async fn get_notifications(&self) -> Result<S3NotificationsResponse, Error> {
407 let resp = self
408 .fc
409 .client
410 .get(format!("{}/_fakecloud/s3/notifications", self.fc.base_url))
411 .send()
412 .await?;
413 FakeCloud::parse(resp).await
414 }
415
416 pub async fn tick_lifecycle(&self) -> Result<LifecycleTickResponse, Error> {
418 let resp = self
419 .fc
420 .client
421 .post(format!(
422 "{}/_fakecloud/s3/lifecycle-processor/tick",
423 self.fc.base_url
424 ))
425 .send()
426 .await?;
427 FakeCloud::parse(resp).await
428 }
429}
430
431pub struct DynamoDbClient<'a> {
434 fc: &'a FakeCloud,
435}
436
437impl DynamoDbClient<'_> {
438 pub async fn tick_ttl(&self) -> Result<TtlTickResponse, Error> {
440 let resp = self
441 .fc
442 .client
443 .post(format!(
444 "{}/_fakecloud/dynamodb/ttl-processor/tick",
445 self.fc.base_url
446 ))
447 .send()
448 .await?;
449 FakeCloud::parse(resp).await
450 }
451}
452
453pub struct SecretsManagerClient<'a> {
456 fc: &'a FakeCloud,
457}
458
459impl SecretsManagerClient<'_> {
460 pub async fn tick_rotation(&self) -> Result<RotationTickResponse, Error> {
462 let resp = self
463 .fc
464 .client
465 .post(format!(
466 "{}/_fakecloud/secretsmanager/rotation-scheduler/tick",
467 self.fc.base_url
468 ))
469 .send()
470 .await?;
471 FakeCloud::parse(resp).await
472 }
473}
474
475pub struct CognitoClient<'a> {
478 fc: &'a FakeCloud,
479}
480
481impl CognitoClient<'_> {
482 pub async fn get_user_codes(
484 &self,
485 pool_id: &str,
486 username: &str,
487 ) -> Result<UserConfirmationCodes, Error> {
488 let resp = self
489 .fc
490 .client
491 .get(format!(
492 "{}/_fakecloud/cognito/confirmation-codes/{}/{}",
493 self.fc.base_url, pool_id, username
494 ))
495 .send()
496 .await?;
497 FakeCloud::parse(resp).await
498 }
499
500 pub async fn get_confirmation_codes(&self) -> Result<ConfirmationCodesResponse, Error> {
502 let resp = self
503 .fc
504 .client
505 .get(format!(
506 "{}/_fakecloud/cognito/confirmation-codes",
507 self.fc.base_url
508 ))
509 .send()
510 .await?;
511 FakeCloud::parse(resp).await
512 }
513
514 pub async fn confirm_user(
516 &self,
517 req: &ConfirmUserRequest,
518 ) -> Result<ConfirmUserResponse, Error> {
519 let resp = self
520 .fc
521 .client
522 .post(format!(
523 "{}/_fakecloud/cognito/confirm-user",
524 self.fc.base_url
525 ))
526 .json(req)
527 .send()
528 .await?;
529 let status = resp.status().as_u16();
531 let body: ConfirmUserResponse = resp.json().await?;
532 if status == 404 {
533 return Err(Error::Api {
534 status,
535 body: body.error.unwrap_or_default(),
536 });
537 }
538 Ok(body)
539 }
540
541 pub async fn get_tokens(&self) -> Result<TokensResponse, Error> {
543 let resp = self
544 .fc
545 .client
546 .get(format!("{}/_fakecloud/cognito/tokens", self.fc.base_url))
547 .send()
548 .await?;
549 FakeCloud::parse(resp).await
550 }
551
552 pub async fn expire_tokens(
554 &self,
555 req: &ExpireTokensRequest,
556 ) -> Result<ExpireTokensResponse, Error> {
557 let resp = self
558 .fc
559 .client
560 .post(format!(
561 "{}/_fakecloud/cognito/expire-tokens",
562 self.fc.base_url
563 ))
564 .json(req)
565 .send()
566 .await?;
567 FakeCloud::parse(resp).await
568 }
569
570 pub async fn get_auth_events(&self) -> Result<AuthEventsResponse, Error> {
572 let resp = self
573 .fc
574 .client
575 .get(format!(
576 "{}/_fakecloud/cognito/auth-events",
577 self.fc.base_url
578 ))
579 .send()
580 .await?;
581 FakeCloud::parse(resp).await
582 }
583}