@@ -402,6 +402,75 @@ mod scheduler_reconcile {
402402 Arc :: new ( RwLock :: new ( accounts) )
403403 }
404404
405+ fn ecs_request ( action : & str , body : serde_json:: Value ) -> AwsRequest {
406+ AwsRequest {
407+ service : "ecs" . into ( ) ,
408+ action : action. into ( ) ,
409+ region : "us-east-1" . into ( ) ,
410+ account_id : ACCOUNT . into ( ) ,
411+ request_id : uuid:: Uuid :: new_v4 ( ) . to_string ( ) ,
412+ headers : http:: HeaderMap :: new ( ) ,
413+ query_params : std:: collections:: HashMap :: new ( ) ,
414+ body : bytes:: Bytes :: from ( serde_json:: to_vec ( & body) . unwrap ( ) ) ,
415+ body_stream : parking_lot:: Mutex :: new ( None ) ,
416+ path_segments : Vec :: new ( ) ,
417+ raw_path : "/" . into ( ) ,
418+ raw_query : String :: new ( ) ,
419+ method : http:: Method :: POST ,
420+ is_query_protocol : false ,
421+ access_key_id : None ,
422+ principal : None ,
423+ }
424+ }
425+
426+ #[ tokio:: test]
427+ async fn update_service_applies_extended_fields ( ) {
428+ // UpdateService previously read only desiredCount/taskDefinition/
429+ // lifecycleHooks and dropped everything else (bug-audit 2026-06-20, 1.15).
430+ let state = empty_state ( ) ;
431+ {
432+ let mut g = state. write ( ) ;
433+ let st = g. get_or_create ( ACCOUNT ) ;
434+ st. services
435+ . insert ( "default/api" . to_string ( ) , make_service ( 2 ) ) ;
436+ }
437+ let svc = EcsService :: new ( state. clone ( ) ) ;
438+
439+ let body = serde_json:: json!( {
440+ "service" : "api" ,
441+ "cluster" : "default" ,
442+ "enableExecuteCommand" : true ,
443+ "enableECSManagedTags" : true ,
444+ "healthCheckGracePeriodSeconds" : 120 ,
445+ "platformVersion" : "1.4.0" ,
446+ "propagateTags" : "SERVICE" ,
447+ "networkConfiguration" : { "awsvpcConfiguration" : { "subnets" : [ "subnet-aaa" ] } } ,
448+ "deploymentConfiguration" : {
449+ "minimumHealthyPercent" : 50 ,
450+ "maximumPercent" : 200 ,
451+ "deploymentCircuitBreaker" : { "enable" : true , "rollback" : true }
452+ }
453+ } ) ;
454+ svc. update_service ( & ecs_request ( "UpdateService" , body) )
455+ . expect ( "UpdateService" ) ;
456+
457+ let g = state. read ( ) ;
458+ let s = & g. get ( ACCOUNT ) . unwrap ( ) . services [ "default/api" ] ;
459+ assert ! ( s. enable_execute_command, "enableExecuteCommand must apply" ) ;
460+ assert ! ( s. enable_ecs_managed_tags) ;
461+ assert_eq ! ( s. health_check_grace_period_seconds, Some ( 120 ) ) ;
462+ assert_eq ! ( s. platform_version. as_deref( ) , Some ( "1.4.0" ) ) ;
463+ assert_eq ! ( s. propagate_tags. as_deref( ) , Some ( "SERVICE" ) ) ;
464+ assert ! ( s. network_configuration. is_some( ) ) ;
465+ assert_eq ! ( s. minimum_healthy_percent, Some ( 50 ) ) ;
466+ assert_eq ! ( s. maximum_percent, Some ( 200 ) ) ;
467+ assert ! ( s
468+ . circuit_breaker
469+ . as_ref( )
470+ . map( |c| c. enable)
471+ . unwrap_or( false ) ) ;
472+ }
473+
405474 /// No snapshot store (memory mode) -> no persist hook for the CFN provisioner.
406475 #[ test]
407476 fn snapshot_hook_is_none_without_store ( ) {
0 commit comments