use super::auth::*;
use super::metrics::{render_counter, render_histogram};
use crate::hub::AdminConfig;
use axum::http::HeaderMap;
#[tokio::test]
async fn test_check_admin_auth_wrong_token() {
let admin = AdminConfig {
token: Some("correct-token".to_string()),
insecure_no_auth: false,
outbound_origin_label: None,
};
let mut headers = HeaderMap::new();
headers.insert("authorization", "Bearer wrong-token-here".parse().unwrap());
assert!(!check_admin_auth(&admin, &headers));
}
#[tokio::test]
async fn test_check_admin_auth_correct_token() {
let admin = AdminConfig {
token: Some("correct-token".to_string()),
insecure_no_auth: false,
outbound_origin_label: None,
};
let mut headers = HeaderMap::new();
headers.insert("authorization", "Bearer correct-token".parse().unwrap());
assert!(check_admin_auth(&admin, &headers));
}
#[tokio::test]
async fn test_check_admin_auth_empty_headers_no_token_no_insecure() {
let admin = AdminConfig {
token: None,
insecure_no_auth: false,
outbound_origin_label: None,
};
let headers = HeaderMap::new();
assert!(!check_admin_auth(&admin, &headers));
}
#[tokio::test]
async fn test_check_admin_auth_empty_headers_insecure_mode() {
let admin = AdminConfig {
token: None,
insecure_no_auth: true,
outbound_origin_label: None,
};
let headers = HeaderMap::new();
assert!(check_admin_auth(&admin, &headers));
}
#[test]
fn test_is_valid_vtoken_accepts_well_formed() {
assert!(is_valid_vtoken("vhub_0123456789abcdef0123456789abcdef"));
}
#[test]
fn test_is_valid_vtoken_rejects_ilink_style() {
assert!(!is_valid_vtoken("botid@im.bot:secret"));
assert!(!is_valid_vtoken(""));
}
#[test]
fn test_is_valid_vtoken_rejects_wrong_length_and_case() {
assert!(!is_valid_vtoken("vhub_short"));
assert!(!is_valid_vtoken("vhub_0123456789ABCDEF0123456789ABCDEF")); assert!(!is_valid_vtoken("vhub_0123456789abcdef0123456789abcde")); assert!(!is_valid_vtoken("vhub_0123456789abcdef0123456789abcdef0")); }
#[test]
fn test_is_valid_vtoken_rejects_non_hex_suffix() {
assert!(!is_valid_vtoken("vhub_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"));
}
#[test]
fn test_extract_vtoken_filters_invalid_format() {
let mut headers = HeaderMap::new();
headers.insert(
"authorization",
"Bearer botid@im.bot:secret".parse().unwrap(),
);
assert!(extract_vtoken(&headers).is_none());
}
#[test]
fn render_counter_strips_total_suffix_from_base_name() {
let mut out = String::new();
render_counter(&mut out, "messages_dispatched_total", "help text", 42, 1.0);
assert!(
out.contains("# HELP messages_dispatched help text\n"),
"HELP must use base name without _total: {out}"
);
assert!(
out.contains("# TYPE messages_dispatched counter\n"),
"TYPE must use base name without _total: {out}"
);
assert!(
out.contains("messages_dispatched_total 42\n"),
"value line must keep _total suffix: {out}"
);
assert!(
out.contains("messages_dispatched_created 1\n"),
"_created must use base name: {out}"
);
}
#[test]
fn render_counter_passthrough_when_no_total_suffix() {
let mut out = String::new();
render_counter(&mut out, "my_counter", "desc", 7, 2.0);
assert!(out.contains("# HELP my_counter desc\n"));
assert!(out.contains("my_counter 7\n"));
assert!(out.contains("my_counter_created 2\n"));
}
#[test]
fn render_histogram_produces_cumulative_bucket_counts() {
use crate::hub::LatencyHistogram;
use std::sync::atomic::Ordering;
let h = LatencyHistogram::new();
h.buckets[0].store(3, Ordering::Relaxed);
h.buckets[1].store(2, Ordering::Relaxed);
h.count.store(5, Ordering::Relaxed);
let mut out = String::new();
render_histogram(&mut out, "test_latency", "desc", &h, 0.0);
assert!(
out.contains("test_latency_bucket{le=\"1\"} 3\n"),
"first bucket must equal bucket[0] count: {out}"
);
assert!(
out.contains("test_latency_bucket{le=\"5\"} 5\n"),
"second bucket must be cumulative (3+2=5): {out}"
);
assert!(
out.contains("test_latency_bucket{le=\"+Inf\"} 5\n"),
"+Inf bucket must equal total count: {out}"
);
}
#[test]
fn render_histogram_includes_help_and_type_lines() {
use crate::hub::LatencyHistogram;
let h = LatencyHistogram::new();
let mut out = String::new();
render_histogram(&mut out, "my_latency", "my help", &h, 0.0);
assert!(out.contains("# HELP my_latency my help\n"));
assert!(out.contains("# TYPE my_latency histogram\n"));
}