@@ -4924,11 +4924,11 @@ fn print_mcp_human_report(
49244924mod tests {
49254925 use super :: * ;
49264926 use crate :: auth:: LoginContext ;
4927+ use actix_web:: { web, App , HttpResponse , HttpServer } ;
49274928 use std:: env;
49284929 use std:: ffi:: OsString ;
4929- use std:: io:: { Read , Write } ;
49304930 use std:: net:: TcpListener ;
4931- use std:: sync:: { Mutex , OnceLock } ;
4931+ use std:: sync:: { Arc , Mutex , OnceLock } ;
49324932 use std:: time:: { SystemTime , UNIX_EPOCH } ;
49334933
49344934 fn cwd_test_lock ( ) -> & ' static Mutex < ( ) > {
@@ -5002,84 +5002,53 @@ mod tests {
50025002 }
50035003 }
50045004
5005+ #[ derive( Default ) ]
5006+ struct ApiKeyTestState {
5007+ create_request_body : Mutex < Option < serde_json:: Value > > ,
5008+ }
5009+
50055010 #[ tokio:: test]
50065011 async fn maybe_create_api_key_for_oauth_uses_org_id_in_request_body ( ) {
5007- let listener = TcpListener :: bind ( "127.0.0.1:0" ) . expect ( "bind listener" ) ;
5008- let addr = listener. local_addr ( ) . expect ( "listener addr" ) ;
5009- let server = std:: thread:: spawn ( move || {
5010- let ( mut stream, _) = listener. accept ( ) . expect ( "accept list request" ) ;
5011- let mut buffer = [ 0u8 ; 4096 ] ;
5012- let read = stream. read ( & mut buffer) . expect ( "read list request" ) ;
5013- let request = String :: from_utf8_lossy ( & buffer[ ..read] ) ;
5014- assert ! ( request. starts_with( "GET /v1/api_key HTTP/1.1" ) ) ;
5015- let response = concat ! (
5016- "HTTP/1.1 200 OK\r \n " ,
5017- "Content-Type: application/json\r \n " ,
5018- "Content-Length: 14\r \n " ,
5019- "Connection: close\r \n " ,
5020- "\r \n " ,
5021- "{\" objects\" :[]}"
5022- ) ;
5023- stream
5024- . write_all ( response. as_bytes ( ) )
5025- . expect ( "write list response" ) ;
5026- stream. flush ( ) . expect ( "flush list response" ) ;
5027- drop ( stream) ;
5028-
5029- let ( mut stream, _) = listener. accept ( ) . expect ( "accept create request" ) ;
5030- let mut header_buf = Vec :: new ( ) ;
5031- let mut temp = [ 0u8 ; 1024 ] ;
5032- let header_end;
5033- loop {
5034- let read = stream. read ( & mut temp) . expect ( "read create request" ) ;
5035- assert ! ( read > 0 , "request closed before headers" ) ;
5036- header_buf. extend_from_slice ( & temp[ ..read] ) ;
5037- if let Some ( pos) = header_buf. windows ( 4 ) . position ( |w| w == b"\r \n \r \n " ) {
5038- header_end = pos + 4 ;
5039- break ;
5040- }
5041- }
5042- let headers = String :: from_utf8_lossy ( & header_buf[ ..header_end] ) ;
5043- assert ! ( headers. starts_with( "POST /v1/api_key HTTP/1.1" ) ) ;
5044- let content_length = headers
5045- . split ( "\r \n " )
5046- . find_map ( |line| {
5047- let ( name, value) = line. split_once ( ':' ) ?;
5048- name. eq_ignore_ascii_case ( "content-length" )
5049- . then ( || value. trim ( ) . parse :: < usize > ( ) . expect ( "content length" ) )
5050- } )
5051- . expect ( "content-length header" ) ;
5052- let mut body = header_buf[ header_end..] . to_vec ( ) ;
5053- while body. len ( ) < content_length {
5054- let read = stream. read ( & mut temp) . expect ( "read request body" ) ;
5055- assert ! ( read > 0 , "request closed before body completed" ) ;
5056- body. extend_from_slice ( & temp[ ..read] ) ;
5057- }
5058- let json: serde_json:: Value =
5059- serde_json:: from_slice ( & body[ ..content_length] ) . expect ( "parse request body" ) ;
5060- assert_eq ! ( json. get( "org_id" ) . and_then( |v| v. as_str( ) ) , Some ( "org_123" ) ) ;
5061- assert ! ( json. get( "org_name" ) . is_none( ) ) ;
5062- assert ! ( json. get( "name" ) . and_then( |v| v. as_str( ) ) . is_some( ) ) ;
5063-
5064- let response = concat ! (
5065- "HTTP/1.1 200 OK\r \n " ,
5066- "Content-Type: application/json\r \n " ,
5067- "Content-Length: 17\r \n " ,
5068- "Connection: close\r \n " ,
5069- "\r \n " ,
5070- "{\" key\" :\" new-key\" }"
5071- ) ;
5072- stream
5073- . write_all ( response. as_bytes ( ) )
5074- . expect ( "write create response" ) ;
5075- stream. flush ( ) . expect ( "flush create response" ) ;
5076- } ) ;
5012+ let state = Arc :: new ( ApiKeyTestState :: default ( ) ) ;
5013+ let listener = TcpListener :: bind ( ( "127.0.0.1" , 0 ) ) . expect ( "bind mock server" ) ;
5014+ let addr = listener. local_addr ( ) . expect ( "mock server addr" ) ;
5015+ let api_url = format ! ( "http://{addr}" ) ;
5016+ let data = web:: Data :: new ( state. clone ( ) ) ;
5017+
5018+ let server = HttpServer :: new ( move || {
5019+ App :: new ( )
5020+ . app_data ( data. clone ( ) )
5021+ . route (
5022+ "/v1/api_key" ,
5023+ web:: get ( ) . to ( || async {
5024+ HttpResponse :: Ok ( ) . json ( serde_json:: json!( { "objects" : [ ] } ) )
5025+ } ) ,
5026+ )
5027+ . route (
5028+ "/v1/api_key" ,
5029+ web:: post ( ) . to (
5030+ |state : web:: Data < Arc < ApiKeyTestState > > ,
5031+ body : web:: Json < serde_json:: Value > | async move {
5032+ * state
5033+ . create_request_body
5034+ . lock ( )
5035+ . expect ( "lock create request body" ) = Some ( body. into_inner ( ) ) ;
5036+ HttpResponse :: Ok ( ) . json ( serde_json:: json!( { "key" : "new-key" } ) )
5037+ } ,
5038+ ) ,
5039+ )
5040+ } )
5041+ . workers ( 1 )
5042+ . listen ( listener)
5043+ . expect ( "listen mock server" )
5044+ . run ( ) ;
5045+ let handle = server. handle ( ) ;
5046+ tokio:: spawn ( server) ;
50775047
50785048 let mut base = make_base_args ( ) ;
50795049 base. quiet = true ;
50805050 base. quiet_source = Some ( ArgValueSource :: CommandLine ) ;
50815051
5082- let api_url = format ! ( "http://{addr}" ) ;
50835052 let ctx = make_login_context (
50845053 api_url,
50855054 "https://app.example.test" . to_string ( ) ,
@@ -5092,8 +5061,20 @@ mod tests {
50925061 . await
50935062 . expect ( "create api key" ) ;
50945063 assert_eq ! ( key, "new-key" ) ;
5064+ let request_body = state
5065+ . create_request_body
5066+ . lock ( )
5067+ . expect ( "lock create request body" )
5068+ . clone ( )
5069+ . expect ( "captured create request body" ) ;
5070+ assert_eq ! (
5071+ request_body. get( "org_id" ) . and_then( |v| v. as_str( ) ) ,
5072+ Some ( "org_123" )
5073+ ) ;
5074+ assert ! ( request_body. get( "org_name" ) . is_none( ) ) ;
5075+ assert ! ( request_body. get( "name" ) . and_then( |v| v. as_str( ) ) . is_some( ) ) ;
50955076
5096- server . join ( ) . expect ( "server join" ) ;
5077+ handle . stop ( true ) . await ;
50975078 }
50985079
50995080 #[ tokio:: test]
0 commit comments