fake_stripe_client.rs

  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, StripeCheckoutSession, StripeCheckoutSessionMode,
 11    StripeCheckoutSessionPaymentMethodCollection, StripeClient,
 12    StripeCreateCheckoutSessionLineItems, StripeCreateCheckoutSessionParams,
 13    StripeCreateCheckoutSessionSubscriptionData, StripeCreateMeterEventParams, StripeCustomer,
 14    StripeCustomerId, StripeMeter, StripeMeterId, StripePrice, StripePriceId, StripeSubscription,
 15    StripeSubscriptionId, UpdateSubscriptionParams,
 16};
 17
 18#[derive(Debug, Clone)]
 19pub struct StripeCreateMeterEventCall {
 20    pub identifier: Arc<str>,
 21    pub event_name: Arc<str>,
 22    pub value: u64,
 23    pub stripe_customer_id: StripeCustomerId,
 24    pub timestamp: Option<i64>,
 25}
 26
 27#[derive(Debug, Clone)]
 28pub struct StripeCreateCheckoutSessionCall {
 29    pub customer: Option<StripeCustomerId>,
 30    pub client_reference_id: Option<String>,
 31    pub mode: Option<StripeCheckoutSessionMode>,
 32    pub line_items: Option<Vec<StripeCreateCheckoutSessionLineItems>>,
 33    pub payment_method_collection: Option<StripeCheckoutSessionPaymentMethodCollection>,
 34    pub subscription_data: Option<StripeCreateCheckoutSessionSubscriptionData>,
 35    pub success_url: Option<String>,
 36}
 37
 38pub struct FakeStripeClient {
 39    pub customers: Arc<Mutex<HashMap<StripeCustomerId, StripeCustomer>>>,
 40    pub subscriptions: Arc<Mutex<HashMap<StripeSubscriptionId, StripeSubscription>>>,
 41    pub update_subscription_calls:
 42        Arc<Mutex<Vec<(StripeSubscriptionId, UpdateSubscriptionParams)>>>,
 43    pub prices: Arc<Mutex<HashMap<StripePriceId, StripePrice>>>,
 44    pub meters: Arc<Mutex<HashMap<StripeMeterId, StripeMeter>>>,
 45    pub create_meter_event_calls: Arc<Mutex<Vec<StripeCreateMeterEventCall>>>,
 46    pub create_checkout_session_calls: Arc<Mutex<Vec<StripeCreateCheckoutSessionCall>>>,
 47}
 48
 49impl FakeStripeClient {
 50    pub fn new() -> Self {
 51        Self {
 52            customers: Arc::new(Mutex::new(HashMap::default())),
 53            subscriptions: Arc::new(Mutex::new(HashMap::default())),
 54            update_subscription_calls: Arc::new(Mutex::new(Vec::new())),
 55            prices: Arc::new(Mutex::new(HashMap::default())),
 56            meters: Arc::new(Mutex::new(HashMap::default())),
 57            create_meter_event_calls: Arc::new(Mutex::new(Vec::new())),
 58            create_checkout_session_calls: Arc::new(Mutex::new(Vec::new())),
 59        }
 60    }
 61}
 62
 63#[async_trait]
 64impl StripeClient for FakeStripeClient {
 65    async fn list_customers_by_email(&self, email: &str) -> Result<Vec<StripeCustomer>> {
 66        Ok(self
 67            .customers
 68            .lock()
 69            .values()
 70            .filter(|customer| customer.email.as_deref() == Some(email))
 71            .cloned()
 72            .collect())
 73    }
 74
 75    async fn create_customer(&self, params: CreateCustomerParams<'_>) -> Result<StripeCustomer> {
 76        let customer = StripeCustomer {
 77            id: StripeCustomerId(format!("cus_{}", Uuid::new_v4()).into()),
 78            email: params.email.map(|email| email.to_string()),
 79        };
 80
 81        self.customers
 82            .lock()
 83            .insert(customer.id.clone(), customer.clone());
 84
 85        Ok(customer)
 86    }
 87
 88    async fn get_subscription(
 89        &self,
 90        subscription_id: &StripeSubscriptionId,
 91    ) -> Result<StripeSubscription> {
 92        self.subscriptions
 93            .lock()
 94            .get(subscription_id)
 95            .cloned()
 96            .ok_or_else(|| anyhow!("no subscription found for {subscription_id:?}"))
 97    }
 98
 99    async fn update_subscription(
100        &self,
101        subscription_id: &StripeSubscriptionId,
102        params: UpdateSubscriptionParams,
103    ) -> Result<()> {
104        let subscription = self.get_subscription(subscription_id).await?;
105
106        self.update_subscription_calls
107            .lock()
108            .push((subscription.id, params));
109
110        Ok(())
111    }
112
113    async fn list_prices(&self) -> Result<Vec<StripePrice>> {
114        let prices = self.prices.lock().values().cloned().collect();
115
116        Ok(prices)
117    }
118
119    async fn list_meters(&self) -> Result<Vec<StripeMeter>> {
120        let meters = self.meters.lock().values().cloned().collect();
121
122        Ok(meters)
123    }
124
125    async fn create_meter_event(&self, params: StripeCreateMeterEventParams<'_>) -> Result<()> {
126        self.create_meter_event_calls
127            .lock()
128            .push(StripeCreateMeterEventCall {
129                identifier: params.identifier.into(),
130                event_name: params.event_name.into(),
131                value: params.payload.value,
132                stripe_customer_id: params.payload.stripe_customer_id.clone(),
133                timestamp: params.timestamp,
134            });
135
136        Ok(())
137    }
138
139    async fn create_checkout_session(
140        &self,
141        params: StripeCreateCheckoutSessionParams<'_>,
142    ) -> Result<StripeCheckoutSession> {
143        self.create_checkout_session_calls
144            .lock()
145            .push(StripeCreateCheckoutSessionCall {
146                customer: params.customer.cloned(),
147                client_reference_id: params.client_reference_id.map(|id| id.to_string()),
148                mode: params.mode,
149                line_items: params.line_items,
150                payment_method_collection: params.payment_method_collection,
151                subscription_data: params.subscription_data,
152                success_url: params.success_url.map(|url| url.to_string()),
153            });
154
155        Ok(StripeCheckoutSession {
156            url: Some("https://checkout.stripe.com/c/pay/cs_test_1".to_string()),
157        })
158    }
159}