@@ -3277,11 +3277,28 @@ mod tests {
3277
3277
use mcp_types:: ContentBlock ;
3278
3278
use mcp_types:: TextContent ;
3279
3279
use pretty_assertions:: assert_eq;
3280
+ use serde:: Deserialize ;
3280
3281
use serde_json:: json;
3281
3282
use std:: path:: PathBuf ;
3282
3283
use std:: sync:: Arc ;
3283
3284
use std:: time:: Duration as StdDuration ;
3284
3285
3286
+ fn test_echo_command ( ) -> Vec < String > {
3287
+ if cfg ! ( windows) {
3288
+ vec ! [
3289
+ "cmd.exe" . to_string( ) ,
3290
+ "/C" . to_string( ) ,
3291
+ "echo hi" . to_string( ) ,
3292
+ ]
3293
+ } else {
3294
+ vec ! [
3295
+ "/bin/sh" . to_string( ) ,
3296
+ "-c" . to_string( ) ,
3297
+ "echo hi" . to_string( ) ,
3298
+ ]
3299
+ }
3300
+ }
3301
+
3285
3302
#[ test]
3286
3303
fn reconstruct_history_matches_live_compactions ( ) {
3287
3304
let ( session, turn_context) = make_session_and_context ( ) ;
@@ -3678,18 +3695,19 @@ mod tests {
3678
3695
turn_context. approval_policy = AskForApproval :: OnFailure ;
3679
3696
3680
3697
let params = ExecParams {
3681
- command : vec ! [
3682
- "/bin/sh" . to_string( ) ,
3683
- "-c" . to_string( ) ,
3684
- "echo hi" . to_string( ) ,
3685
- ] ,
3698
+ command : test_echo_command ( ) ,
3686
3699
cwd : turn_context. cwd . clone ( ) ,
3687
3700
timeout_ms : Some ( 1000 ) ,
3688
3701
env : HashMap :: new ( ) ,
3689
3702
with_escalated_permissions : Some ( true ) ,
3690
3703
justification : Some ( "test" . to_string ( ) ) ,
3691
3704
} ;
3692
3705
3706
+ let params2 = ExecParams {
3707
+ with_escalated_permissions : Some ( false ) ,
3708
+ ..params. clone ( )
3709
+ } ;
3710
+
3693
3711
let mut turn_diff_tracker = TurnDiffTracker :: new ( ) ;
3694
3712
3695
3713
let sub_id = "test-sub" . to_string ( ) ;
@@ -3720,19 +3738,6 @@ mod tests {
3720
3738
// Force DangerFullAccess to avoid platform sandbox dependencies in tests.
3721
3739
turn_context. sandbox_policy = SandboxPolicy :: DangerFullAccess ;
3722
3740
3723
- let params2 = ExecParams {
3724
- command : vec ! [
3725
- "/bin/sh" . to_string( ) ,
3726
- "-c" . to_string( ) ,
3727
- "echo hi" . to_string( ) ,
3728
- ] ,
3729
- cwd : turn_context. cwd . clone ( ) ,
3730
- timeout_ms : Some ( 1000 ) ,
3731
- env : HashMap :: new ( ) ,
3732
- with_escalated_permissions : Some ( false ) ,
3733
- justification : Some ( "test" . to_string ( ) ) ,
3734
- } ;
3735
-
3736
3741
let resp2 = handle_container_exec_with_params (
3737
3742
params2,
3738
3743
& session,
@@ -3747,11 +3752,24 @@ mod tests {
3747
3752
panic ! ( "expected FunctionCallOutput on retry" ) ;
3748
3753
} ;
3749
3754
3750
- // Parse the structured exec output and assert success without new structs
3751
- let v: serde_json:: Value =
3755
+ #[ derive( Deserialize ) ]
3756
+ struct ResponseExecMetadata {
3757
+ exit_code : i32 ,
3758
+ duration_seconds : f32 ,
3759
+ }
3760
+
3761
+ #[ derive( Deserialize ) ]
3762
+ struct ResponseExecOutput {
3763
+ output : String ,
3764
+ metadata : ResponseExecMetadata ,
3765
+ }
3766
+
3767
+ let exec_output: ResponseExecOutput =
3752
3768
serde_json:: from_str ( & output. content ) . expect ( "valid exec output json" ) ;
3753
- assert_eq ! ( v[ "metadata" ] [ "exit_code" ] . as_i64( ) , Some ( 0 ) ) ;
3754
- assert ! ( v[ "output" ] . as_str( ) . unwrap_or( "" ) . contains( "hi" ) ) ;
3769
+
3770
+ assert_eq ! ( exec_output. metadata. exit_code, 0 ) ;
3771
+ assert ! ( exec_output. metadata. duration_seconds >= 0.0 ) ;
3772
+ assert ! ( exec_output. output. contains( "hi" ) ) ;
3755
3773
assert_eq ! ( output. success, Some ( true ) ) ;
3756
3774
}
3757
3775
}
0 commit comments