use super::*;
use theway_mcp::HttpMcpAuth;
use theway_transport::auth::{AuthStore, ProviderCredential};
fn streamable_http_server(endpoint: &str) -> ServerConfig {
let mut server = http_server(endpoint);
server.name = "streamable-http-server".into();
server
}
#[tokio::test]
async fn connect_streamable_http_success_applies_all_options() {
let mut server = streamable_http_server("http://127.0.0.1:9/mcp");
server.request_timeout_ms = Some(1_234);
server.sse_idle_timeout_ms = Some(5_678);
server.body_cap_bytes = Some(999);
server.reconnect = Some(ReconnectConfig {
initial_ms: Some(100),
max_ms: Some(2_000),
max_attempts: Some(3),
});
let (_work, _base, paths) = test_paths();
let client = connect_streamable_http(&server, &paths.base.join("auth.json"))
.await
.expect("connect_streamable_http should assemble a client without network I/O");
client.close().await;
}
#[tokio::test]
async fn connect_streamable_http_success_applies_reconnect_defaults() {
let mut server = streamable_http_server("http://127.0.0.1:9/mcp");
server.reconnect = Some(ReconnectConfig {
initial_ms: None,
max_ms: None,
max_attempts: Some(2),
});
let (_work, _base, paths) = test_paths();
let client = connect_streamable_http(&server, &paths.base.join("auth.json"))
.await
.expect("connect_streamable_http should assemble a client without network I/O");
client.close().await;
}
#[tokio::test]
async fn connect_one_streamable_http_missing_endpoint_returns_err() {
let mut server = streamable_http_server("");
server.endpoint = None;
let (_work, _base, paths) = test_paths();
let err = match connect_one(&server, &paths.work_dir, &paths.base.join("auth.json")).await {
Ok(_) => panic!("streamable_http without endpoint should fail"),
Err(err) => err,
};
assert!(err.to_string().contains("missing endpoint"), "{err}");
}
#[test]
fn resolve_http_auth_none_returns_none() {
let (_work, _base, paths) = test_paths();
let auth = resolve_http_auth(None, &paths.base.join("auth.json")).unwrap();
assert!(matches!(auth, HttpMcpAuth::None));
}
#[test]
fn resolve_http_auth_loads_bearer_from_auth_store() {
let (_work, base, _paths) = test_paths();
let auth_path = base.path().join("auth.json");
let mut store = AuthStore::default();
store.set(
"mcp-example:default",
ProviderCredential::ApiKey {
value: "secret-token".into(),
},
);
store.save_to(&auth_path).unwrap();
let auth = resolve_http_auth(
Some(&HttpAuthConfig {
kind: "bearer".into(),
token_keychain_ref: Some("mcp-example:default".into()),
}),
&auth_path,
)
.unwrap();
match auth {
HttpMcpAuth::Bearer { token } => assert_eq!(token, "secret-token"),
other => panic!("expected bearer auth, got {other:?}"),
}
}
#[test]
fn resolve_http_auth_reports_store_load_failure_with_recovery_hint() {
let (_work, base, _paths) = test_paths();
let auth_path = base.path().join("auth.json");
std::fs::write(&auth_path, "{ not valid json").unwrap();
let err = resolve_http_auth(
Some(&HttpAuthConfig {
kind: "bearer".into(),
token_keychain_ref: Some("mcp-example:default".into()),
}),
&auth_path,
)
.unwrap_err()
.to_string();
assert!(
err.contains("failed to load local credential store"),
"{err}"
);
assert!(err.contains("run /login <configured-token-ref>"), "{err}");
}