mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-07 03:00:29 +00:00
test(unwrap): clean server integration helpers
This commit is contained in:
parent
0b91c71514
commit
2ec1fb2987
10 changed files with 71 additions and 46 deletions
|
|
@ -32,7 +32,7 @@ async fn configure_token_install(app: &axum::Router, token: &str) {
|
|||
.body(Body::from(
|
||||
r#"{"providers":[{"provider":"anthropic","api_key":"anthropic-test-key"}]}"#,
|
||||
))
|
||||
.unwrap(),
|
||||
.expect("LLM install request should build"),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
@ -49,7 +49,7 @@ async fn configure_token_install(app: &axum::Router, token: &str) {
|
|||
.body(Body::from(
|
||||
r#"{"canonical_url":"https://fabro.example.com"}"#,
|
||||
))
|
||||
.unwrap(),
|
||||
.expect("server install request should build"),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
@ -66,7 +66,7 @@ async fn configure_token_install(app: &axum::Router, token: &str) {
|
|||
.body(Body::from(
|
||||
r#"{"token":"ghp_test_token","username":"brynary"}"#,
|
||||
))
|
||||
.unwrap(),
|
||||
.expect("GitHub token install request should build"),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
|
|||
|
|
@ -435,7 +435,7 @@ fn request_with_connect_info(path: &str, ip: IpAddr) -> Request<Body> {
|
|||
.method("GET")
|
||||
.uri(path)
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
.expect("routing test request should build");
|
||||
let mut request = request;
|
||||
request
|
||||
.extensions_mut()
|
||||
|
|
|
|||
|
|
@ -56,11 +56,16 @@ async fn create_run(app: &axum::Router, manifest: serde_json::Value) -> String {
|
|||
.method("POST")
|
||||
.uri(api("/runs"))
|
||||
.header("content-type", "application/json")
|
||||
.body(Body::from(serde_json::to_vec(&manifest).unwrap()))
|
||||
.unwrap();
|
||||
.body(Body::from(
|
||||
serde_json::to_vec(&manifest).expect("manifest fixture should serialize"),
|
||||
))
|
||||
.expect("create-run request should build");
|
||||
let response = app.clone().oneshot(request).await.unwrap();
|
||||
let body = body_json(response.into_body()).await;
|
||||
body["id"].as_str().unwrap().to_string()
|
||||
body["id"]
|
||||
.as_str()
|
||||
.expect("create-run response should include an id")
|
||||
.to_string()
|
||||
}
|
||||
|
||||
async fn start_run(app: &axum::Router, run_id: &str) {
|
||||
|
|
@ -68,7 +73,7 @@ async fn start_run(app: &axum::Router, run_id: &str) {
|
|||
.method("POST")
|
||||
.uri(api(&format!("/runs/{run_id}/start")))
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
.expect("start-run request should build");
|
||||
let response = app.clone().oneshot(request).await.unwrap();
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
}
|
||||
|
|
@ -79,7 +84,7 @@ async fn wait_for_question(app: &axum::Router, run_id: &str) -> serde_json::Valu
|
|||
.method("GET")
|
||||
.uri(api(&format!("/runs/{run_id}/questions")))
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
.expect("questions request should build");
|
||||
let response = app.clone().oneshot(request).await.unwrap();
|
||||
let body = body_json(response.into_body()).await;
|
||||
if let Some(question) = body["data"].as_array().and_then(|items| items.first()) {
|
||||
|
|
@ -95,7 +100,7 @@ async fn load_questions(app: &axum::Router, run_id: &str) -> serde_json::Value {
|
|||
.method("GET")
|
||||
.uri(api(&format!("/runs/{run_id}/questions")))
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
.expect("questions request should build");
|
||||
let response = app.clone().oneshot(request).await.unwrap();
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
body_json(response.into_body()).await
|
||||
|
|
|
|||
|
|
@ -27,8 +27,12 @@ const TEST_DEV_TOKEN: &str =
|
|||
"fabro_dev_abababababababababababababababababababababababababababababababab";
|
||||
|
||||
async fn start_tcp_server(auth_mode: AuthMode, ip_allowlist: Arc<IpAllowlistConfig>) -> SocketAddr {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
||||
let addr = listener.local_addr().unwrap();
|
||||
let listener = TcpListener::bind("127.0.0.1:0")
|
||||
.await
|
||||
.expect("test TCP listener should bind");
|
||||
let addr = listener
|
||||
.local_addr()
|
||||
.expect("test TCP listener should have a local address");
|
||||
|
||||
let state = create_app_state();
|
||||
let router =
|
||||
|
|
@ -51,24 +55,24 @@ fn build_unix_client(path: &Path) -> fabro_http::HttpClient {
|
|||
.unix_socket(path)
|
||||
.no_proxy()
|
||||
.build()
|
||||
.unwrap()
|
||||
.expect("Unix test client should build")
|
||||
}
|
||||
|
||||
fn write_test_config(tempdir: &TempDir, settings: &str) -> PathBuf {
|
||||
let config_path = tempdir.path().join("settings.toml");
|
||||
std::fs::write(&config_path, settings).unwrap();
|
||||
std::fs::write(&config_path, settings).expect("test settings should write");
|
||||
std::fs::write(
|
||||
ServerState::new(tempdir.path()).env_path(),
|
||||
format!("FABRO_DEV_TOKEN={TEST_DEV_TOKEN}\n"),
|
||||
)
|
||||
.unwrap();
|
||||
.expect("test env file should write");
|
||||
config_path
|
||||
}
|
||||
|
||||
async fn spawn_served_listener(
|
||||
settings: impl AsRef<str>,
|
||||
) -> (JoinHandle<anyhow::Result<()>>, Bind, TempDir) {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let tempdir = tempfile::tempdir().expect("temporary server directory should create");
|
||||
let config_path = write_test_config(&tempdir, settings.as_ref());
|
||||
let styles: &'static Styles = Box::leak(Box::new(Styles::new(false)));
|
||||
let (tx, rx) = tokio::sync::oneshot::channel();
|
||||
|
|
|
|||
|
|
@ -78,8 +78,10 @@ pub(crate) fn api(path: &str) -> String {
|
|||
}
|
||||
|
||||
pub(crate) async fn body_json(body: Body) -> serde_json::Value {
|
||||
let bytes = to_bytes(body, usize::MAX).await.unwrap();
|
||||
serde_json::from_slice(&bytes).unwrap()
|
||||
let bytes = to_bytes(body, usize::MAX)
|
||||
.await
|
||||
.expect("response body should fit in memory");
|
||||
serde_json::from_slice(&bytes).expect("response body should be valid JSON")
|
||||
}
|
||||
|
||||
pub(crate) async fn create_and_start_run_from_manifest(
|
||||
|
|
@ -90,17 +92,22 @@ pub(crate) async fn create_and_start_run_from_manifest(
|
|||
.method("POST")
|
||||
.uri(api("/runs"))
|
||||
.header("content-type", "application/json")
|
||||
.body(Body::from(serde_json::to_string(&manifest).unwrap()))
|
||||
.unwrap();
|
||||
.body(Body::from(
|
||||
serde_json::to_string(&manifest).expect("manifest fixture should serialize"),
|
||||
))
|
||||
.expect("create-run request should build");
|
||||
let response = app.clone().oneshot(req).await.unwrap();
|
||||
let body = body_json(response.into_body()).await;
|
||||
let run_id = body["id"].as_str().unwrap().to_string();
|
||||
let run_id = body["id"]
|
||||
.as_str()
|
||||
.expect("create-run response should include an id")
|
||||
.to_string();
|
||||
|
||||
let req = Request::builder()
|
||||
.method("POST")
|
||||
.uri(api(&format!("/runs/{run_id}/start")))
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
.expect("start-run request should build");
|
||||
app.clone().oneshot(req).await.unwrap();
|
||||
|
||||
run_id
|
||||
|
|
@ -134,7 +141,7 @@ pub(crate) async fn run_json(app: &axum::Router, run_id: &str) -> serde_json::Va
|
|||
.method("GET")
|
||||
.uri(api(&format!("/runs/{run_id}")))
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
.expect("run lookup request should build");
|
||||
let response = app.clone().oneshot(req).await.unwrap();
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
body_json(response.into_body()).await
|
||||
|
|
@ -147,7 +154,10 @@ pub(crate) async fn wait_for_run_status(
|
|||
) -> String {
|
||||
for _ in 0..POLL_ATTEMPTS {
|
||||
let body = run_json(app, run_id).await;
|
||||
let status = body["status"].as_str().unwrap().to_string();
|
||||
let status = body["status"]
|
||||
.as_str()
|
||||
.expect("run response should include a string status")
|
||||
.to_string();
|
||||
if expected.iter().any(|candidate| *candidate == status) {
|
||||
return status;
|
||||
}
|
||||
|
|
@ -163,7 +173,10 @@ pub(crate) async fn wait_for_run_status_not_in(
|
|||
) -> String {
|
||||
for _ in 0..POLL_ATTEMPTS {
|
||||
let body = run_json(app, run_id).await;
|
||||
let status = body["status"].as_str().unwrap().to_string();
|
||||
let status = body["status"]
|
||||
.as_str()
|
||||
.expect("run response should include a string status")
|
||||
.to_string();
|
||||
if unexpected.iter().all(|candidate| *candidate != status) {
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,14 +23,11 @@ use tower::ServiceExt;
|
|||
use super::helpers::test_app_state;
|
||||
|
||||
fn load_spec() -> Value {
|
||||
let spec_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.parent()
|
||||
.unwrap()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.join("docs/api-reference/fabro-api.yaml");
|
||||
let repo_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.ancestors()
|
||||
.nth(3)
|
||||
.expect("fabro-server crate should be nested under lib/crates/fabro-server");
|
||||
let spec_path = repo_root.join("docs/api-reference/fabro-api.yaml");
|
||||
let text = std::fs::read_to_string(&spec_path).expect("failed to read spec");
|
||||
serde_yaml::from_str(&text).expect("failed to parse spec")
|
||||
}
|
||||
|
|
@ -81,7 +78,9 @@ fn request_for(method: &Method, uri: &str) -> Request<Body> {
|
|||
} else {
|
||||
Body::empty()
|
||||
};
|
||||
builder.body(body).unwrap()
|
||||
builder
|
||||
.body(body)
|
||||
.expect("OpenAPI conformance request should build")
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@ async fn get_json(app: axum::Router, uri: &str) -> serde_json::Value {
|
|||
.uri(uri)
|
||||
.header("x-fabro-demo", "1")
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
.expect("pagination request should build");
|
||||
let response = app.clone().oneshot(req).await.unwrap();
|
||||
assert_eq!(response.status(), StatusCode::OK, "GET {uri} failed");
|
||||
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
|
||||
.await
|
||||
.unwrap();
|
||||
serde_json::from_slice(&body).unwrap()
|
||||
.expect("pagination response body should fit in memory");
|
||||
serde_json::from_slice(&body).expect("pagination response should be valid JSON")
|
||||
}
|
||||
|
||||
/// Assert that a value has the paginated shape: `{ data: [...], meta: {
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ fn completion_request(stream: bool) -> Request<Body> {
|
|||
"messages": [{"role": "user", "content": [{"kind": "text", "data": "Hello"}]}],
|
||||
"stream": stream
|
||||
}))
|
||||
.unwrap(),
|
||||
.expect("completion fixture should serialize"),
|
||||
))
|
||||
.unwrap()
|
||||
.expect("completion request should build")
|
||||
}
|
||||
|
||||
fn completion_request_with_model(stream: bool, model: &str) -> Request<Body> {
|
||||
|
|
@ -35,9 +35,9 @@ fn completion_request_with_model(stream: bool, model: &str) -> Request<Body> {
|
|||
"messages": [{"role": "user", "content": [{"kind": "text", "data": "Hi"}]}],
|
||||
"stream": stream
|
||||
}))
|
||||
.unwrap(),
|
||||
.expect("model completion fixture should serialize"),
|
||||
))
|
||||
.unwrap()
|
||||
.expect("completion request should build")
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
|
|
|
|||
|
|
@ -35,10 +35,12 @@ async fn wait_for_question_id(app: &axum::Router, run_id: &str) -> String {
|
|||
.method("GET")
|
||||
.uri(api(&format!("/runs/{run_id}/questions")))
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
.expect("questions request should build");
|
||||
let response = app.clone().oneshot(req).await.unwrap();
|
||||
let body = body_json(response.into_body()).await;
|
||||
let arr = body["data"].as_array().unwrap();
|
||||
let arr = body["data"]
|
||||
.as_array()
|
||||
.expect("questions response should include a data array");
|
||||
if let Some(question_id) = arr
|
||||
.first()
|
||||
.and_then(|item| item["id"].as_str())
|
||||
|
|
@ -57,10 +59,12 @@ async fn wait_for_question(app: &axum::Router, run_id: &str) -> serde_json::Valu
|
|||
.method("GET")
|
||||
.uri(api(&format!("/runs/{run_id}/questions")))
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
.expect("questions request should build");
|
||||
let response = app.clone().oneshot(req).await.unwrap();
|
||||
let body = body_json(response.into_body()).await;
|
||||
let arr = body["data"].as_array().unwrap();
|
||||
let arr = body["data"]
|
||||
.as_array()
|
||||
.expect("questions response should include a data array");
|
||||
if let Some(question) = arr.first() {
|
||||
return question.clone();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ async fn wait_for_checkpoint(app: &axum::Router, run_id: &str) -> serde_json::Va
|
|||
.method("GET")
|
||||
.uri(api(&format!("/runs/{run_id}/checkpoint")))
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
.expect("checkpoint request should build");
|
||||
let response = app.clone().oneshot(req).await.unwrap();
|
||||
if response.status() == StatusCode::OK {
|
||||
return body_json(response.into_body()).await;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue