@ -13,6 +13,7 @@
mod common ;
mod common ;
use axum ::body ::Body ;
use axum ::http ::StatusCode ;
use axum ::http ::StatusCode ;
fn require_test_db ( ) -> bool {
fn require_test_db ( ) -> bool {
@ -602,3 +603,97 @@ async fn generate_twice_returns_error_for_second() {
) ;
) ;
assert_eq! ( resp2 [ "error" ] , "bad_request" ) ;
assert_eq! ( resp2 [ "error" ] , "bad_request" ) ;
}
}
// ═══════════════════════════════════════════════════════════════════════════
// Generation Pipeline — Model Resolution
// ═══════════════════════════════════════════════════════════════════════════
/// Verify that triggering generation with a configured provider exercises
/// the model resolution SQL query against the real database schema.
/// The generation will fail at the LLM call (fake API key), but that confirms
/// settings load, model resolution, provider creation, and schema building
/// all succeed — which is the code path that had the admin_provider_models bug.
#[ tokio::test ]
async fn generate_pipeline_resolves_model_from_admin_config ( ) {
if ! require_test_db ( ) {
eprintln! ( "SKIPPED: TEST_DATABASE_URL not set" ) ;
return ;
}
let app = common ::TestApp ::new ( ) . await ;
let ( user_id , session ) = app
. create_authenticated_user ( "synth-model-resolve@example.com" )
. await ;
// Configure user settings with provider and categories
let settings = serde_json ::json ! ( {
"categories" : [ "Test Category" ] ,
"ai_provider" : "openai" ,
"ai_model" : "" ,
"ai_model_writing" : ""
} ) ;
let ( settings_status , _ ) = app
. put_with_session ( "/api/v1/settings" , & settings , & session )
. await ;
assert_eq! ( settings_status , StatusCode ::OK , "Settings save should succeed" ) ;
// Store a fake API key — we don't need a real one, just need to get past
// model resolution and into the LLM call
let key_body = serde_json ::json ! ( {
"provider_name" : "openai" ,
"api_key" : "sk-fake-test-key-for-model-resolution"
} ) ;
let ( key_status , _ ) = app
. post_with_session ( "/api/v1/user/api-keys" , & key_body , & session )
. await ;
assert_eq! ( key_status , StatusCode ::OK , "API key store should succeed" ) ;
// Add a source so the pipeline has something to work with
let source_body = serde_json ::json ! ( {
"title" : "Test Source" ,
"url" : "https://example.com"
} ) ;
let ( source_status , _ ) = app
. post_with_session ( "/api/v1/sources" , & source_body , & session )
. await ;
assert_eq! ( source_status , StatusCode ::OK , "Source creation should succeed" ) ;
// Trigger generation — this will run async. The key assertion is that
// the HTTP trigger returns 202 (not 500) and the async job doesn't crash
// on a database error. It will fail at the LLM API call (fake key), which
// is expected and fine — the model resolution path was exercised.
let gen_body = serde_json ::json ! ( { } ) ;
let ( gen_status , gen_resp ) = app
. post_with_session ( "/api/v1/syntheses/generate" , & gen_body , & session )
. await ;
assert_eq! (
gen_status ,
StatusCode ::ACCEPTED ,
"Generation trigger should succeed (202)"
) ;
let job_id = gen_resp [ "job_id" ] . as_str ( ) . expect ( "should have job_id" ) ;
// Wait briefly for the async job to attempt model resolution and LLM call
tokio ::time ::sleep ( std ::time ::Duration ::from_secs ( 3 ) ) . await ;
// Poll the progress endpoint — we expect an error from the LLM call (fake key),
// NOT a database error about a missing table. This confirms model resolution worked.
let progress_url = format! ( "/api/v1/syntheses/generate/{}/progress" , job_id ) ;
let req = axum ::http ::Request ::builder ( )
. method ( axum ::http ::Method ::GET )
. uri ( & progress_url )
. header ( "cookie" , format! ( "ai_synth_session={}" , session ) )
. header ( "x-requested-with" , "XMLHttpRequest" )
. body ( Body ::empty ( ) )
. unwrap ( ) ;
let ( _ , progress_text , _ ) = app . raw_request_text ( req ) . await ;
// The SSE stream should NOT contain a database error about a missing table.
// It should contain an LLM-related error (fake key) instead.
assert! (
! progress_text . contains ( "admin_provider_models" ) ,
"Generation must not reference non-existent admin_provider_models table. Got: {}" ,
progress_text
) ;
}