1use std::sync::Arc;
2
3use anyhow::{Result, anyhow};
4use async_trait::async_trait;
5use collections::HashMap;
6use parking_lot::Mutex;
7use uuid::Uuid;
8
9use crate::stripe_client::{
10 CreateCustomerParams, StripeClient, StripeCustomer, StripeCustomerId, StripeMeter,
11 StripeMeterId, StripePrice, StripePriceId, StripeSubscription, StripeSubscriptionId,
12 UpdateSubscriptionParams,
13};
14
15pub struct FakeStripeClient {
16 pub customers: Arc<Mutex<HashMap<StripeCustomerId, StripeCustomer>>>,
17 pub subscriptions: Arc<Mutex<HashMap<StripeSubscriptionId, StripeSubscription>>>,
18 pub update_subscription_calls:
19 Arc<Mutex<Vec<(StripeSubscriptionId, UpdateSubscriptionParams)>>>,
20 pub prices: Arc<Mutex<HashMap<StripePriceId, StripePrice>>>,
21 pub meters: Arc<Mutex<HashMap<StripeMeterId, StripeMeter>>>,
22}
23
24impl FakeStripeClient {
25 pub fn new() -> Self {
26 Self {
27 customers: Arc::new(Mutex::new(HashMap::default())),
28 subscriptions: Arc::new(Mutex::new(HashMap::default())),
29 update_subscription_calls: Arc::new(Mutex::new(Vec::new())),
30 prices: Arc::new(Mutex::new(HashMap::default())),
31 meters: Arc::new(Mutex::new(HashMap::default())),
32 }
33 }
34}
35
36#[async_trait]
37impl StripeClient for FakeStripeClient {
38 async fn list_customers_by_email(&self, email: &str) -> Result<Vec<StripeCustomer>> {
39 Ok(self
40 .customers
41 .lock()
42 .values()
43 .filter(|customer| customer.email.as_deref() == Some(email))
44 .cloned()
45 .collect())
46 }
47
48 async fn create_customer(&self, params: CreateCustomerParams<'_>) -> Result<StripeCustomer> {
49 let customer = StripeCustomer {
50 id: StripeCustomerId(format!("cus_{}", Uuid::new_v4()).into()),
51 email: params.email.map(|email| email.to_string()),
52 };
53
54 self.customers
55 .lock()
56 .insert(customer.id.clone(), customer.clone());
57
58 Ok(customer)
59 }
60
61 async fn get_subscription(
62 &self,
63 subscription_id: &StripeSubscriptionId,
64 ) -> Result<StripeSubscription> {
65 self.subscriptions
66 .lock()
67 .get(subscription_id)
68 .cloned()
69 .ok_or_else(|| anyhow!("no subscription found for {subscription_id:?}"))
70 }
71
72 async fn update_subscription(
73 &self,
74 subscription_id: &StripeSubscriptionId,
75 params: UpdateSubscriptionParams,
76 ) -> Result<()> {
77 let subscription = self.get_subscription(subscription_id).await?;
78
79 self.update_subscription_calls
80 .lock()
81 .push((subscription.id, params));
82
83 Ok(())
84 }
85
86 async fn list_prices(&self) -> Result<Vec<StripePrice>> {
87 let prices = self.prices.lock().values().cloned().collect();
88
89 Ok(prices)
90 }
91
92 async fn list_meters(&self) -> Result<Vec<StripeMeter>> {
93 let meters = self.meters.lock().values().cloned().collect();
94
95 Ok(meters)
96 }
97}