158 lines
4.9 KiB
Rust
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);
|
|
}
|