@@ -1919,4 +1919,79 @@ mod tests {
19191919 . tests ( 100 )
19201920 . quickcheck ( prop as fn ( u64 , u64 , TokenAmount , TokenAmount ) -> TestResult ) ;
19211921 }
1922+
1923+ #[ test]
1924+ fn negative_reservation_amount_fails ( ) {
1925+ let sender: ActorID = 50 ;
1926+ let mut exec = new_executor_with_actor ( sender, TokenAmount :: from_atto ( 1000u64 ) ) ;
1927+ // Construct a negative amount.
1928+ // TokenAmount is a wrapper around BigInt.
1929+ let negative_amt = TokenAmount :: from_atto ( 100u64 ) - TokenAmount :: from_atto ( 200u64 ) ;
1930+ assert ! ( negative_amt. is_negative( ) ) ;
1931+
1932+ let plan = vec ! [ ( Address :: new_id( sender) , negative_amt. clone( ) ) ] ;
1933+
1934+ let err = exec. begin_reservation_session ( & plan) . unwrap_err ( ) ;
1935+ match err {
1936+ ReservationError :: ReservationInvariant ( msg) => {
1937+ assert ! ( msg. contains( "negative reservation amount" ) ) ;
1938+ }
1939+ other => panic ! ( "expected ReservationInvariant, got {:?}" , other) ,
1940+ }
1941+
1942+ // Verify telemetry recorded the failure
1943+ let session = exec
1944+ . reservation_session
1945+ . lock ( )
1946+ . expect ( "reservation session mutex poisoned" ) ;
1947+ assert_eq ! ( session. telemetry. reservation_begin_failed, 1 ) ;
1948+ }
1949+
1950+ #[ test]
1951+ fn telemetry_state_updates ( ) {
1952+ let sender: ActorID = 60 ;
1953+ let mut exec = new_executor_with_actor ( sender, TokenAmount :: from_atto ( 1_000_000u64 ) ) ;
1954+ let plan = vec ! [ ( Address :: new_id( sender) , TokenAmount :: from_atto( 500u64 ) ) ] ;
1955+
1956+ // 1. Test failure increment
1957+ // Use a too-large plan to force failure
1958+ {
1959+ let poor_sender = 61 ;
1960+ let account_code = * exec. builtin_actors ( ) . get_account_code ( ) ;
1961+ exec. state_tree_mut ( )
1962+ . set_actor ( poor_sender, ActorState :: new_empty ( account_code, None ) ) ;
1963+ let fail_plan = vec ! [ ( Address :: new_id( poor_sender) , TokenAmount :: from_atto( 10u64 ) ) ] ;
1964+
1965+ exec. begin_reservation_session ( & fail_plan) . unwrap_err ( ) ;
1966+
1967+ let session = exec. reservation_session . lock ( ) . unwrap ( ) ;
1968+ assert_eq ! ( session. telemetry. reservation_begin_failed, 1 ) ;
1969+ assert_eq ! ( session. telemetry. reservations_open, 0 ) ;
1970+ }
1971+
1972+ // 2. Test success increment
1973+ exec. begin_reservation_session ( & plan) . unwrap ( ) ;
1974+ {
1975+ let session = exec. reservation_session . lock ( ) . unwrap ( ) ;
1976+ assert_eq ! ( session. telemetry. reservation_begin_failed, 1 ) ; // unchanged
1977+ assert_eq ! ( session. telemetry. reservations_open, 1 ) ;
1978+ assert_eq ! ( session. telemetry. reservation_total_per_sender. len( ) , 1 ) ;
1979+ assert_eq ! ( session. telemetry. reserved_remaining_per_sender. len( ) , 1 ) ;
1980+ }
1981+
1982+ // 3. Test end session decrement
1983+ // We must clear reservations manually to allow end_session (simulating consumption)
1984+ {
1985+ let mut session = exec. reservation_session . lock ( ) . unwrap ( ) ;
1986+ session. reservations . clear ( ) ;
1987+ }
1988+
1989+ exec. end_reservation_session ( ) . unwrap ( ) ;
1990+ {
1991+ let session = exec. reservation_session . lock ( ) . unwrap ( ) ;
1992+ assert_eq ! ( session. telemetry. reservations_open, 0 ) ;
1993+ assert ! ( session. telemetry. reservation_total_per_sender. is_empty( ) ) ;
1994+ assert ! ( session. telemetry. reserved_remaining_per_sender. is_empty( ) ) ;
1995+ }
1996+ }
19221997}
0 commit comments