1use std::sync::Arc;
2
3use pretty_assertions::assert_eq;
4
5use crate::stripe_billing::StripeBilling;
6use crate::stripe_client::{
7 FakeStripeClient, StripeMeter, StripeMeterId, StripePrice, StripePriceId, StripePriceRecurring,
8};
9
10fn make_stripe_billing() -> (StripeBilling, Arc<FakeStripeClient>) {
11 let stripe_client = Arc::new(FakeStripeClient::new());
12 let stripe_billing = StripeBilling::test(stripe_client.clone());
13
14 (stripe_billing, stripe_client)
15}
16
17#[gpui::test]
18async fn test_initialize() {
19 let (stripe_billing, stripe_client) = make_stripe_billing();
20
21 // Add test meters
22 let meter1 = StripeMeter {
23 id: StripeMeterId("meter_1".into()),
24 event_name: "event_1".to_string(),
25 };
26 let meter2 = StripeMeter {
27 id: StripeMeterId("meter_2".into()),
28 event_name: "event_2".to_string(),
29 };
30 stripe_client
31 .meters
32 .lock()
33 .insert(meter1.id.clone(), meter1);
34 stripe_client
35 .meters
36 .lock()
37 .insert(meter2.id.clone(), meter2);
38
39 // Add test prices
40 let price1 = StripePrice {
41 id: StripePriceId("price_1".into()),
42 unit_amount: Some(1_000),
43 lookup_key: Some("zed-pro".to_string()),
44 recurring: None,
45 };
46 let price2 = StripePrice {
47 id: StripePriceId("price_2".into()),
48 unit_amount: Some(0),
49 lookup_key: Some("zed-free".to_string()),
50 recurring: None,
51 };
52 let price3 = StripePrice {
53 id: StripePriceId("price_3".into()),
54 unit_amount: Some(500),
55 lookup_key: None,
56 recurring: Some(StripePriceRecurring {
57 meter: Some("meter_1".to_string()),
58 }),
59 };
60 stripe_client
61 .prices
62 .lock()
63 .insert(price1.id.clone(), price1);
64 stripe_client
65 .prices
66 .lock()
67 .insert(price2.id.clone(), price2);
68 stripe_client
69 .prices
70 .lock()
71 .insert(price3.id.clone(), price3);
72
73 // Initialize the billing system
74 stripe_billing.initialize().await.unwrap();
75
76 // Verify that prices can be found by lookup key
77 let zed_pro_price_id = stripe_billing.zed_pro_price_id().await.unwrap();
78 assert_eq!(zed_pro_price_id.to_string(), "price_1");
79
80 let zed_free_price_id = stripe_billing.zed_free_price_id().await.unwrap();
81 assert_eq!(zed_free_price_id.to_string(), "price_2");
82
83 // Verify that a price can be found by lookup key
84 let zed_pro_price = stripe_billing
85 .find_price_by_lookup_key("zed-pro")
86 .await
87 .unwrap();
88 assert_eq!(zed_pro_price.id.to_string(), "price_1");
89 assert_eq!(zed_pro_price.unit_amount, Some(1_000));
90
91 // Verify that finding a non-existent lookup key returns an error
92 let result = stripe_billing
93 .find_price_by_lookup_key("non-existent")
94 .await;
95 assert!(result.is_err());
96}
97
98#[gpui::test]
99async fn test_find_or_create_customer_by_email() {
100 let (stripe_billing, stripe_client) = make_stripe_billing();
101
102 // Create a customer with an email that doesn't yet correspond to a customer.
103 {
104 let email = "user@example.com";
105
106 let customer_id = stripe_billing
107 .find_or_create_customer_by_email(Some(email))
108 .await
109 .unwrap();
110
111 let customer = stripe_client
112 .customers
113 .lock()
114 .get(&customer_id)
115 .unwrap()
116 .clone();
117 assert_eq!(customer.email.as_deref(), Some(email));
118 }
119
120 // Create a customer with an email that corresponds to an existing customer.
121 {
122 let email = "user2@example.com";
123
124 let existing_customer_id = stripe_billing
125 .find_or_create_customer_by_email(Some(email))
126 .await
127 .unwrap();
128
129 let customer_id = stripe_billing
130 .find_or_create_customer_by_email(Some(email))
131 .await
132 .unwrap();
133 assert_eq!(customer_id, existing_customer_id);
134
135 let customer = stripe_client
136 .customers
137 .lock()
138 .get(&customer_id)
139 .unwrap()
140 .clone();
141 assert_eq!(customer.email.as_deref(), Some(email));
142 }
143}