test(billing): validate stripe customer id enforcement
This commit is contained in:
@@ -732,3 +732,112 @@ impl Billing {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
#[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