Files
cloudlysis/control/api/tests/control_api_smoke_env_gated.rs
Vlad Durnea 2595e7f1c5
Some checks failed
ci / ui (push) Failing after 28s
ci / rust (push) Failing after 2m40s
images / build-and-push (push) Failing after 19s
feat(billing): implement tenant subscription entitlements system (milestones 0-6)
2026-03-30 18:41:23 +03:00

158 lines
4.9 KiB
Rust

use jsonwebtoken::{EncodingKey, Header, encode};
use reqwest::StatusCode;
use serde::Serialize;
use serde_json::json;
use std::time::Duration;
use uuid::Uuid;
#[derive(Serialize)]
struct TestClaims {
sub: String,
session_id: String,
permissions: Vec<String>,
exp: usize,
}
fn make_token(secret: &[u8], perms: &[&str]) -> String {
let exp = (std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs()
+ 300) as usize;
encode(
&Header::default(),
&TestClaims {
sub: "smoke".to_string(),
session_id: "smoke".to_string(),
permissions: perms.iter().map(|p| (*p).to_string()).collect(),
exp,
},
&EncodingKey::from_secret(secret),
)
.unwrap()
}
#[tokio::test]
async fn control_api_docs_smoke_is_env_gated() {
let enabled = std::env::var("CONTROL_TEST_SMOKE").ok();
if enabled.as_deref() != Some("1") {
eprintln!("skipping: set CONTROL_TEST_SMOKE=1 to enable env smoke tests");
return;
}
let base_url =
std::env::var("CONTROL_TEST_BASE_URL").expect("CONTROL_TEST_BASE_URL is required");
let base_url = base_url.trim_end_matches('/').to_string();
// Either provide a token directly, or provide secret+perms to mint one.
let token = if let Ok(t) = std::env::var("CONTROL_TEST_TOKEN") {
t
} else {
let secret = std::env::var("CONTROL_TEST_JWT_SECRET")
.expect("CONTROL_TEST_TOKEN or CONTROL_TEST_JWT_SECRET is required");
make_token(secret.as_bytes(), &["control:read", "control:write"])
};
let tenant_id = std::env::var("CONTROL_TEST_TENANT_ID")
.ok()
.unwrap_or_else(|| Uuid::new_v4().to_string());
let http = reqwest::Client::builder()
.timeout(Duration::from_secs(15))
.build()
.unwrap();
// Health.
let health = http
.get(format!("{base_url}/health"))
.send()
.await
.expect("health request failed");
assert!(health.status().is_success(), "health not ok");
// Presign upload.
let doc_id = Uuid::new_v4().to_string();
let filename = "smoke.txt";
let presign_up = http
.post(format!(
"{base_url}/admin/v1/tenants/{tenant_id}/docs/presign/upload"
))
.header("authorization", format!("Bearer {token}"))
.header("x-tenant-id", &tenant_id)
.json(&json!({
"doc_type": "deployments",
"doc_id": doc_id,
"filename": filename,
"content_type": "text/plain",
}))
.send()
.await
.expect("presign upload failed");
assert!(
presign_up.status().is_success(),
"presign upload not ok: {}",
presign_up.status()
);
let up_json: serde_json::Value = presign_up.json().await.unwrap();
let put_url = up_json.get("url").and_then(|v| v.as_str()).unwrap();
let key = up_json
.get("key")
.and_then(|v| v.as_str())
.unwrap()
.to_string();
// PUT bytes to S3 directly.
let payload = b"hello-smoke".to_vec();
let put = http
.put(put_url)
.header("content-type", "text/plain")
.body(payload.clone())
.send()
.await
.expect("s3 put failed");
assert!(put.status().is_success(), "s3 put not ok: {}", put.status());
// List should include key.
let list = http
.get(format!(
"{base_url}/admin/v1/tenants/{tenant_id}/docs?prefix=deployments/"
))
.header("authorization", format!("Bearer {token}"))
.header("x-tenant-id", &tenant_id)
.send()
.await
.expect("list failed");
assert!(list.status().is_success(), "list not ok");
let list_json: serde_json::Value = list.json().await.unwrap();
let objects = list_json.get("objects").and_then(|v| v.as_array()).unwrap();
assert!(
objects
.iter()
.any(|o| o.get("key").and_then(|k| k.as_str()) == Some(key.as_str())),
"expected list to include presigned upload key"
);
// Presign download and fetch bytes.
let presign_down = http
.post(format!(
"{base_url}/admin/v1/tenants/{tenant_id}/docs/presign/download"
))
.header("authorization", format!("Bearer {token}"))
.header("x-tenant-id", &tenant_id)
.json(&json!({ "key": key }))
.send()
.await
.expect("presign download failed");
assert!(
presign_down.status().is_success(),
"presign download not ok"
);
let down_json: serde_json::Value = presign_down.json().await.unwrap();
let get_url = down_json.get("url").and_then(|v| v.as_str()).unwrap();
let got = http.get(get_url).send().await.expect("s3 get failed");
assert_eq!(got.status(), StatusCode::OK);
let got_bytes = got.bytes().await.unwrap().to_vec();
assert_eq!(got_bytes, payload);
}