@ -10,6 +10,20 @@ use wiremock::{Mock, MockServer, ResponseTemplate};
async fn setup_mock_server ( ) -> MockServer {
let server = MockServer ::start ( ) . await ;
// Source page with links to articles (for Phase 1 heuristic extraction)
let base = server . uri ( ) ;
Mock ::given ( method ( "GET" ) )
. and ( path ( "/blog" ) )
. respond_with ( ResponseTemplate ::new ( 200 ) . set_body_string ( format! (
r #" < html > < body >
< a href = "{base}/article-1" > Article One < / a >
< a href = "{base}/article-2" > Article Two < / a >
< a href = "{base}/article-3" > Article Three < / a >
< / body > < / html > " #
) ) )
. mount ( & server )
. await ;
// Article pages
for i in 1 ..= 5 {
Mock ::given ( method ( "GET" ) )
@ -77,12 +91,13 @@ async fn phase1_with_llm_link_extraction_classifies_articles() {
// Use LLM link extraction to bypass SSRF on source page
let ( user_id , session ) = setup_user_with_settings ( & app , vec! [ "AI News" ] , 4 , true ) . await ;
// Add a source (URL doesn't matter much — LLM mock will return article URLs)
let source = serde_json ::json ! ( { "title" : "Test Source" , "url" : "https://example.com/blog" } ) ;
// Add a source pointing to wiremock (same host as article URLs)
let source_url = format! ( "{}/blog" , mock_server . uri ( ) ) ;
let source = serde_json ::json ! ( { "title" : "Test Source" , "url" : source_url } ) ;
let ( status , _ ) = app . post_with_session ( "/api/v1/sources" , & source , & session ) . await ;
assert! ( status . is_success ( ) ) ;
// Mock provider: LLM link extraction returns wiremock article URLs
// Mock provider: LLM link extraction returns wiremock article URLs (same domain)
let article_urls : Vec < String > = ( 1 ..= 3 )
. map ( | i | format! ( "{}/article-{}" , mock_server . uri ( ) , i ) )
. collect ( ) ;
@ -187,7 +202,8 @@ async fn category_overflow_spills_to_autre() {
// max_items_per_category=1, but LLM classifies all articles to "AI News"
let ( user_id , session ) = setup_user_with_settings ( & app , vec! [ "AI News" ] , 1 , true ) . await ;
let source = serde_json ::json ! ( { "title" : "Test Source" , "url" : "https://example.com/blog" } ) ;
let source_url = format! ( "{}/blog" , mock_server . uri ( ) ) ;
let source = serde_json ::json ! ( { "title" : "Test Source" , "url" : source_url } ) ;
app . post_with_session ( "/api/v1/sources" , & source , & session ) . await ;
let article_urls : Vec < String > = ( 1 ..= 3 )