@@ -39,9 +39,14 @@ use crate::{
3939 operations:: { self , Operation } ,
4040} ;
4141
42+ pub ( super ) mod init_tracker;
4243pub ( super ) mod mock_runtime;
4344pub ( super ) mod runtime;
4445
46+ pub ( crate ) use init_tracker:: {
47+ ContractInitTracker , InitCheckResult , SLOW_INIT_THRESHOLD , STALE_INIT_THRESHOLD ,
48+ } ;
49+
4550#[ derive( Debug ) ]
4651pub struct ExecutorError {
4752 inner : Either < Box < RequestError > , anyhow:: Error > ,
@@ -521,30 +526,6 @@ pub(crate) trait ContractExecutor: Send + 'static {
521526 fn get_subscription_info ( & self ) -> Vec < crate :: message:: SubscriptionInfo > ;
522527}
523528
524- /// A WASM executor which will run any contracts, delegates, etc. registered.
525- ///
526- /// This executor will monitor the store directories and databases to detect state changes.
527- /// Represents an operation that's waiting for a contract to finish initializing
528- #[ derive( Debug ) ]
529- struct QueuedOperation {
530- update : Either < WrappedState , StateDelta < ' static > > ,
531- related_contracts : RelatedContracts < ' static > ,
532- /// When this operation was queued
533- queued_at : std:: time:: Instant ,
534- }
535-
536- /// Tracks the initialization state of a contract
537- #[ derive( Debug ) ]
538- enum ContractInitState {
539- /// Contract is currently being initialized (validation in progress)
540- Initializing {
541- /// Operations waiting for initialization to complete
542- queued_ops : Vec < QueuedOperation > ,
543- /// When initialization started
544- started_at : std:: time:: Instant ,
545- } ,
546- }
547-
548529/// Consumers of the executor are required to poll for new changes in order to be notified
549530/// of changes or can alternatively use the notification channel.
550531pub struct Executor < R = Runtime > {
@@ -558,7 +539,7 @@ pub struct Executor<R = Runtime> {
558539 /// Attested contract instances for a given delegate.
559540 delegate_attested_ids : HashMap < DelegateKey , Vec < ContractInstanceId > > ,
560541 /// Tracks contracts that are being initialized and operations queued for them
561- contract_init_state : HashMap < ContractKey , ContractInitState > ,
542+ init_tracker : ContractInitTracker ,
562543
563544 event_loop_channel : Option < ExecutorToEventLoopChannel < ExecutorHalve > > ,
564545}
@@ -580,7 +561,7 @@ impl<R> Executor<R> {
580561 update_notifications : HashMap :: default ( ) ,
581562 subscriber_summaries : HashMap :: default ( ) ,
582563 delegate_attested_ids : HashMap :: default ( ) ,
583- contract_init_state : HashMap :: default ( ) ,
564+ init_tracker : ContractInitTracker :: new ( ) ,
584565 event_loop_channel,
585566 } )
586567 }
@@ -668,3 +649,164 @@ impl<R> Executor<R> {
668649 subscriptions
669650 }
670651}
652+
653+ /// Test fixtures for creating contract-related test data.
654+ ///
655+ /// These helpers make it easier to write unit tests for contract module code
656+ /// by providing convenient constructors for common types.
657+ #[ cfg( test) ]
658+ pub ( crate ) mod test_fixtures {
659+ use freenet_stdlib:: prelude:: * ;
660+
661+ /// Create a test contract key with arbitrary but consistent data
662+ pub fn make_contract_key ( ) -> ContractKey {
663+ let code = ContractCode :: from ( vec ! [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] ) ;
664+ let params = Parameters :: from ( vec ! [ 10 , 20 , 30 , 40 ] ) ;
665+ ContractKey :: from_params_and_code ( & params, & code)
666+ }
667+
668+ /// Create a test contract key with custom code bytes
669+ pub fn make_contract_key_with_code ( code_bytes : & [ u8 ] ) -> ContractKey {
670+ let code = ContractCode :: from ( code_bytes. to_vec ( ) ) ;
671+ let params = Parameters :: from ( vec ! [ 10 , 20 , 30 , 40 ] ) ;
672+ ContractKey :: from_params_and_code ( & params, & code)
673+ }
674+
675+ /// Create a test wrapped state from raw bytes
676+ pub fn make_state ( data : & [ u8 ] ) -> WrappedState {
677+ WrappedState :: new ( data. to_vec ( ) )
678+ }
679+
680+ /// Create test parameters from raw bytes
681+ pub fn make_params ( data : & [ u8 ] ) -> Parameters < ' static > {
682+ Parameters :: from ( data. to_vec ( ) )
683+ }
684+
685+ /// Create a test state delta from raw bytes
686+ pub fn make_delta ( data : & [ u8 ] ) -> StateDelta < ' static > {
687+ StateDelta :: from ( data. to_vec ( ) )
688+ }
689+ }
690+
691+ #[ cfg( test) ]
692+ mod tests {
693+ use super :: * ;
694+
695+ mod executor_error_tests {
696+ use super :: * ;
697+
698+ #[ test]
699+ fn test_executor_error_other_is_not_request ( ) {
700+ let err = ExecutorError :: other ( anyhow:: anyhow!( "some error" ) ) ;
701+ assert ! ( !err. is_request( ) ) ;
702+ assert ! ( !err. is_fatal( ) ) ;
703+ }
704+
705+ #[ test]
706+ fn test_executor_error_request_is_request ( ) {
707+ let err = ExecutorError :: request ( StdContractError :: Put {
708+ key : test_fixtures:: make_contract_key ( ) ,
709+ cause : "test" . into ( ) ,
710+ } ) ;
711+ assert ! ( err. is_request( ) ) ;
712+ assert ! ( !err. is_fatal( ) ) ;
713+ }
714+
715+ #[ test]
716+ fn test_executor_error_internal_error ( ) {
717+ let err = ExecutorError :: internal_error ( ) ;
718+ assert ! ( !err. is_request( ) ) ;
719+ assert ! ( !err. is_fatal( ) ) ;
720+ assert ! ( err. to_string( ) . contains( "internal error" ) ) ;
721+ }
722+
723+ #[ test]
724+ fn test_executor_error_display_left ( ) {
725+ let err = ExecutorError :: request ( StdContractError :: Put {
726+ key : test_fixtures:: make_contract_key ( ) ,
727+ cause : "test cause" . into ( ) ,
728+ } ) ;
729+ let display = err. to_string ( ) ;
730+ assert ! ( display. contains( "test cause" ) || display. contains( "Put" ) ) ;
731+ }
732+
733+ #[ test]
734+ fn test_executor_error_display_right ( ) {
735+ let err = ExecutorError :: other ( anyhow:: anyhow!( "custom error message" ) ) ;
736+ assert ! ( err. to_string( ) . contains( "custom error message" ) ) ;
737+ }
738+
739+ #[ test]
740+ fn test_executor_error_from_request_error ( ) {
741+ let request_err = RequestError :: ContractError ( StdContractError :: Put {
742+ key : test_fixtures:: make_contract_key ( ) ,
743+ cause : "from conversion" . into ( ) ,
744+ } ) ;
745+ let err: ExecutorError = request_err. into ( ) ;
746+ assert ! ( err. is_request( ) ) ;
747+ }
748+
749+ #[ test]
750+ fn test_executor_error_from_boxed_request_error ( ) {
751+ let request_err = Box :: new ( RequestError :: ContractError ( StdContractError :: Put {
752+ key : test_fixtures:: make_contract_key ( ) ,
753+ cause : "boxed" . into ( ) ,
754+ } ) ) ;
755+ let err: ExecutorError = request_err. into ( ) ;
756+ assert ! ( err. is_request( ) ) ;
757+ }
758+
759+ #[ test]
760+ fn test_unwrap_request_succeeds_for_request_error ( ) {
761+ let key = test_fixtures:: make_contract_key ( ) ;
762+ let err = ExecutorError :: request ( StdContractError :: Put {
763+ key,
764+ cause : "unwrap test" . into ( ) ,
765+ } ) ;
766+ let _unwrapped = err. unwrap_request ( ) ; // Should not panic
767+ }
768+
769+ #[ test]
770+ #[ should_panic]
771+ fn test_unwrap_request_panics_for_other_error ( ) {
772+ let err = ExecutorError :: other ( anyhow:: anyhow!( "not a request" ) ) ;
773+ let _unwrapped = err. unwrap_request ( ) ; // Should panic
774+ }
775+ }
776+
777+ mod test_fixtures_tests {
778+ use super :: * ;
779+
780+ #[ test]
781+ fn test_make_contract_key_is_consistent ( ) {
782+ let key1 = test_fixtures:: make_contract_key ( ) ;
783+ let key2 = test_fixtures:: make_contract_key ( ) ;
784+ assert_eq ! ( key1, key2) ;
785+ }
786+
787+ #[ test]
788+ fn test_make_contract_key_with_different_code ( ) {
789+ let key1 = test_fixtures:: make_contract_key_with_code ( & [ 1 , 2 , 3 ] ) ;
790+ let key2 = test_fixtures:: make_contract_key_with_code ( & [ 4 , 5 , 6 ] ) ;
791+ assert_ne ! ( key1, key2) ;
792+ }
793+
794+ #[ test]
795+ fn test_make_state ( ) {
796+ let state = test_fixtures:: make_state ( & [ 1 , 2 , 3 , 4 ] ) ;
797+ assert_eq ! ( state. as_ref( ) , & [ 1 , 2 , 3 , 4 ] ) ;
798+ }
799+
800+ #[ test]
801+ fn test_make_params ( ) {
802+ let params = test_fixtures:: make_params ( & [ 10 , 20 ] ) ;
803+ assert_eq ! ( params. as_ref( ) , & [ 10 , 20 ] ) ;
804+ }
805+
806+ #[ test]
807+ fn test_make_delta ( ) {
808+ let delta = test_fixtures:: make_delta ( & [ 100 , 200 ] ) ;
809+ assert_eq ! ( delta. as_ref( ) , & [ 100 , 200 ] ) ;
810+ }
811+ }
812+ }
0 commit comments