@@ -470,6 +470,59 @@ mod migrate_command {
470470#[ cfg( feature = "cloud" ) ]
471471mod deploy_command {
472472 use super :: * ;
473+ use std:: io:: Write ;
474+ use std:: net:: TcpListener ;
475+ use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
476+ use std:: sync:: Arc ;
477+ use std:: thread;
478+ use std:: time:: Duration ;
479+
480+ fn spawn_mock_deploy_status_server ( deploy_id : & str ) -> ( String , thread:: JoinHandle < ( ) > ) {
481+ let listener = TcpListener :: bind ( "127.0.0.1:0" ) . expect ( "bind mock cloud" ) ;
482+ let port = listener. local_addr ( ) . expect ( "addr" ) . port ( ) ;
483+ let cloud_url = format ! ( "http://127.0.0.1:{port}" ) ;
484+ let id = deploy_id. to_string ( ) ;
485+ let hits = Arc :: new ( AtomicUsize :: new ( 0 ) ) ;
486+
487+ let handle = thread:: spawn ( move || {
488+ listener. set_nonblocking ( true ) . ok ( ) ;
489+ let deadline = std:: time:: Instant :: now ( ) + Duration :: from_secs ( 30 ) ;
490+ while hits. load ( Ordering :: SeqCst ) < 2 && std:: time:: Instant :: now ( ) < deadline {
491+ if let Ok ( ( mut stream, _) ) = listener. accept ( ) {
492+ let mut buf = [ 0u8 ; 4096 ] ;
493+ let _ = std:: io:: Read :: read ( & mut stream, & mut buf) ;
494+ let body = format ! (
495+ r#"{{"deploy_id":"{id}","status":"live","url":"http://127.0.0.1:59999"}}"#
496+ ) ;
497+ let response = format ! (
498+ "HTTP/1.1 200 OK\r \n Content-Type: application/json\r \n Content-Length: {}\r \n Connection: close\r \n \r \n {body}" ,
499+ body. len( )
500+ ) ;
501+ let _ = stream. write_all ( response. as_bytes ( ) ) ;
502+ hits. fetch_add ( 1 , Ordering :: SeqCst ) ;
503+ } else {
504+ thread:: sleep ( Duration :: from_millis ( 20 ) ) ;
505+ }
506+ }
507+ } ) ;
508+
509+ ( cloud_url, handle)
510+ }
511+
512+ fn write_cloud_config ( home : & std:: path:: Path , cloud_url : & str , token : & str ) {
513+ let dir = home. join ( ".rustapi" ) ;
514+ fs:: create_dir_all ( & dir) . expect ( "config dir" ) ;
515+ let config = serde_json:: json!( {
516+ "token" : token,
517+ "cloud_url" : cloud_url,
518+ "user" : { "login" : "cli-test" , "tier" : "hobby" }
519+ } ) ;
520+ fs:: write (
521+ dir. join ( "config.json" ) ,
522+ serde_json:: to_string_pretty ( & config) . expect ( "json" ) ,
523+ )
524+ . expect ( "write config" ) ;
525+ }
473526
474527 #[ test]
475528 fn test_deploy_status_help ( ) {
@@ -488,4 +541,25 @@ mod deploy_command {
488541 . success ( )
489542 . stdout ( predicate:: str:: contains ( "RustAPI Cloud" ) ) ;
490543 }
544+
545+ #[ test]
546+ fn test_deploy_status_fetches_live_response_from_cloud ( ) {
547+ let deploy_id = "cli-mock-deploy-1" ;
548+ let ( cloud_url, server) = spawn_mock_deploy_status_server ( deploy_id) ;
549+ let home = tempdir ( ) . expect ( "cli home" ) ;
550+ write_cloud_config ( home. path ( ) , & cloud_url, "mock-jwt-token" ) ;
551+
552+ cargo_rustapi ( )
553+ . env ( "USERPROFILE" , home. path ( ) )
554+ . env ( "HOME" , home. path ( ) )
555+ . args ( [ "deploy" , "status" , deploy_id] )
556+ . assert ( )
557+ . success ( )
558+ . stdout ( predicate:: str:: contains ( deploy_id) )
559+ . stdout ( predicate:: str:: contains ( "live" ) )
560+ . stdout ( predicate:: str:: contains ( "URL:" ) )
561+ . stdout ( predicate:: str:: contains ( "http://127.0.0.1:59999" ) ) ;
562+
563+ server. join ( ) . expect ( "mock server thread" ) ;
564+ }
491565}
0 commit comments