forked from coracle/caravel
test(billing): validate stripe customer id enforcement
This commit is contained in:
@@ -732,3 +732,112 @@ impl Billing {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use crate::models::Activity;
|
||||||
|
|
||||||
|
async fn test_pool() -> SqlitePool {
|
||||||
|
let connect_options = SqliteConnectOptions::from_str("sqlite::memory:")
|
||||||
|
.expect("valid sqlite memory url")
|
||||||
|
.create_if_missing(true);
|
||||||
|
|
||||||
|
let pool = SqlitePoolOptions::new()
|
||||||
|
.max_connections(1)
|
||||||
|
.connect_with(connect_options)
|
||||||
|
.await
|
||||||
|
.expect("connect sqlite memory db");
|
||||||
|
|
||||||
|
sqlx::migrate!("./migrations")
|
||||||
|
.run(&pool)
|
||||||
|
.await
|
||||||
|
.expect("run migrations");
|
||||||
|
|
||||||
|
pool
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_billing(pool: SqlitePool, stripe_secret_key: &str) -> Billing {
|
||||||
|
Billing {
|
||||||
|
nwc_url: String::new(),
|
||||||
|
stripe_secret_key: stripe_secret_key.to_string(),
|
||||||
|
stripe_webhook_secret: String::new(),
|
||||||
|
http: reqwest::Client::new(),
|
||||||
|
query: Query::new(pool.clone()),
|
||||||
|
command: Command::new(pool),
|
||||||
|
robot: Robot::test_stub(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn stripe_create_customer_requires_secret_key() {
|
||||||
|
let pool = test_pool().await;
|
||||||
|
let billing = test_billing(pool, "");
|
||||||
|
|
||||||
|
let err = billing
|
||||||
|
.stripe_create_customer("tenant_pubkey")
|
||||||
|
.await
|
||||||
|
.expect_err("missing key should fail before HTTP call");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
err.to_string().contains("missing STRIPE_SECRET_KEY"),
|
||||||
|
"unexpected error: {err}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn sync_relay_subscription_fails_for_empty_tenant_customer_id() {
|
||||||
|
let pool = test_pool().await;
|
||||||
|
|
||||||
|
sqlx::query(
|
||||||
|
"INSERT INTO tenant (pubkey, nwc_url, created_at, stripe_customer_id)
|
||||||
|
VALUES (?, ?, ?, ?)",
|
||||||
|
)
|
||||||
|
.bind("tenant_pubkey")
|
||||||
|
.bind("")
|
||||||
|
.bind(0_i64)
|
||||||
|
.bind("")
|
||||||
|
.execute(&pool)
|
||||||
|
.await
|
||||||
|
.expect("insert tenant");
|
||||||
|
|
||||||
|
sqlx::query(
|
||||||
|
"INSERT INTO relay (id, tenant, schema, subdomain, plan, status)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?)",
|
||||||
|
)
|
||||||
|
.bind("relay_1")
|
||||||
|
.bind("tenant_pubkey")
|
||||||
|
.bind("relay_1")
|
||||||
|
.bind("relay-1")
|
||||||
|
.bind("basic")
|
||||||
|
.bind("active")
|
||||||
|
.execute(&pool)
|
||||||
|
.await
|
||||||
|
.expect("insert relay");
|
||||||
|
|
||||||
|
let billing = test_billing(pool, "sk_test_dummy");
|
||||||
|
let activity = Activity {
|
||||||
|
id: "activity_1".to_string(),
|
||||||
|
tenant: "tenant_pubkey".to_string(),
|
||||||
|
created_at: 0,
|
||||||
|
activity_type: "create_relay".to_string(),
|
||||||
|
resource_type: "relay".to_string(),
|
||||||
|
resource_id: "relay_1".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let err = billing
|
||||||
|
.sync_relay_subscription(&activity)
|
||||||
|
.await
|
||||||
|
.expect_err("empty tenant customer id should fail clearly");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
err.to_string()
|
||||||
|
.contains("tenant tenant_pubkey has no stripe_customer_id"),
|
||||||
|
"unexpected error: {err}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -324,3 +324,56 @@ impl Command {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use sqlx::SqlitePool;
|
||||||
|
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
async fn test_pool() -> SqlitePool {
|
||||||
|
let connect_options = SqliteConnectOptions::from_str("sqlite::memory:")
|
||||||
|
.expect("valid sqlite memory url")
|
||||||
|
.create_if_missing(true);
|
||||||
|
|
||||||
|
let pool = SqlitePoolOptions::new()
|
||||||
|
.max_connections(1)
|
||||||
|
.connect_with(connect_options)
|
||||||
|
.await
|
||||||
|
.expect("connect sqlite memory db");
|
||||||
|
|
||||||
|
sqlx::migrate!("./migrations")
|
||||||
|
.run(&pool)
|
||||||
|
.await
|
||||||
|
.expect("run migrations");
|
||||||
|
|
||||||
|
pool
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn create_tenant_rejects_empty_stripe_customer_id() {
|
||||||
|
let pool = test_pool().await;
|
||||||
|
let command = Command::new(pool);
|
||||||
|
|
||||||
|
let tenant = Tenant {
|
||||||
|
pubkey: "tenant_pubkey".to_string(),
|
||||||
|
nwc_url: String::new(),
|
||||||
|
nwc_error: None,
|
||||||
|
created_at: 0,
|
||||||
|
stripe_customer_id: " ".to_string(),
|
||||||
|
stripe_subscription_id: None,
|
||||||
|
past_due_at: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let err = command
|
||||||
|
.create_tenant(&tenant)
|
||||||
|
.await
|
||||||
|
.expect_err("empty customer id must be rejected");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
err.to_string().contains("stripe_customer_id is required"),
|
||||||
|
"unexpected error: {err}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -254,3 +254,23 @@ async fn set_cached(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl Robot {
|
||||||
|
pub fn test_stub() -> Self {
|
||||||
|
let keys = Keys::generate();
|
||||||
|
let client = Client::new(keys);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
secret: String::new(),
|
||||||
|
name: String::new(),
|
||||||
|
description: String::new(),
|
||||||
|
picture: String::new(),
|
||||||
|
outbox_client: client.clone(),
|
||||||
|
indexer_client: client.clone(),
|
||||||
|
messaging_client: client,
|
||||||
|
outbox_cache: std::sync::Arc::new(Mutex::new(HashMap::new())),
|
||||||
|
dm_cache: std::sync::Arc::new(Mutex::new(HashMap::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user