1212
1313use super :: assertion:: run_assertions;
1414use super :: block_stream:: StaticStreamBuilder ;
15+ use super :: mock_arweave:: MockArweaveResolver ;
1516use super :: mock_chain;
1617use super :: mock_ipfs:: MockIpfsClient ;
1718use super :: noop:: { NoopAdapterSelector , StaticBlockRefetcher } ;
@@ -24,7 +25,7 @@ use graph::amp::FlightClient;
2425use graph:: blockchain:: block_stream:: BlockWithTriggers ;
2526use graph:: blockchain:: { BlockPtr , BlockchainMap , ChainIdentifier } ;
2627use graph:: cheap_clone:: CheapClone ;
27- use graph:: components:: link_resolver:: { ArweaveClient , FileLinkResolver } ;
28+ use graph:: components:: link_resolver:: FileLinkResolver ;
2829use graph:: components:: metrics:: MetricsRegistry ;
2930use graph:: components:: network_provider:: {
3031 AmpChainNames , ChainName , ProviderCheckStrategy , ProviderManager ,
@@ -81,6 +82,14 @@ fn make_test_logger(verbose: u8) -> Logger {
8182 }
8283}
8384
85+ /// Mock file data passed to `setup_context`.
86+ struct MockData {
87+ ipfs_files : HashMap < ContentPath , graph:: bytes:: Bytes > ,
88+ ipfs_unresolved_tx : tokio:: sync:: mpsc:: UnboundedSender < ContentPath > ,
89+ arweave_files : HashMap < String , graph:: bytes:: Bytes > ,
90+ arweave_unresolved_tx : tokio:: sync:: mpsc:: UnboundedSender < String > ,
91+ }
92+
8493struct TestStores {
8594 network_name : ChainName ,
8695 /// Listens for chain head updates — needed by the Chain constructor.
@@ -307,6 +316,20 @@ pub async fn run_single_test(
307316
308317 let ( unresolved_tx, mut unresolved_rx) = tokio:: sync:: mpsc:: unbounded_channel :: < ContentPath > ( ) ;
309318
319+ let mut mock_arweave_files: HashMap < String , graph:: bytes:: Bytes > = HashMap :: new ( ) ;
320+ for entry in & test_file. arweave_files {
321+ let content = entry. resolve ( & test_file_dir) . with_context ( || {
322+ format ! (
323+ "Failed to resolve mock Arweave file for txId '{}'" ,
324+ entry. tx_id
325+ )
326+ } ) ?;
327+ mock_arweave_files. insert ( entry. tx_id . clone ( ) , content) ;
328+ }
329+
330+ let ( arweave_unresolved_tx, mut arweave_unresolved_rx) =
331+ tokio:: sync:: mpsc:: unbounded_channel :: < String > ( ) ;
332+
310333 // Create the database for this test. For pgtemp, the `db` value must
311334 // stay alive for the duration of the test — dropping it destroys the database.
312335 let db = create_test_database ( opt, & manifest_info. build_dir ) ?;
@@ -317,15 +340,14 @@ pub async fn run_single_test(
317340
318341 let chain = setup_chain ( & logger, blocks. clone ( ) , & stores) . await ?;
319342
320- let ctx = setup_context (
321- & logger,
322- & stores,
323- & chain,
324- manifest_info,
325- mock_files,
326- unresolved_tx,
327- )
328- . await ?;
343+ let mock_data = MockData {
344+ ipfs_files : mock_files,
345+ ipfs_unresolved_tx : unresolved_tx,
346+ arweave_files : mock_arweave_files,
347+ arweave_unresolved_tx,
348+ } ;
349+
350+ let ctx = setup_context ( & logger, & stores, & chain, manifest_info, mock_data) . await ?;
329351
330352 // Populate eth_call cache with mock responses before starting indexer.
331353 // This ensures handlers can successfully retrieve mocked contract call results.
@@ -362,25 +384,51 @@ pub async fn run_single_test(
362384 Ok ( ( ) ) => {
363385 // Drain any CIDs that were requested but not found in the mock.
364386 // Deduplicate so each missing CID is listed once.
365- let mut unresolved : Vec < ContentPath > = Vec :: new ( ) ;
387+ let mut unresolved_ipfs : Vec < ContentPath > = Vec :: new ( ) ;
366388 while let Ok ( cid) = unresolved_rx. try_recv ( ) {
367- if !unresolved . contains ( & cid) {
368- unresolved . push ( cid) ;
389+ if !unresolved_ipfs . contains ( & cid) {
390+ unresolved_ipfs . push ( cid) ;
369391 }
370392 }
371393
372- if !unresolved. is_empty ( ) {
373- let cid_list = unresolved
394+ let mut unresolved_arweave: Vec < String > = Vec :: new ( ) ;
395+ while let Ok ( tx_id) = arweave_unresolved_rx. try_recv ( ) {
396+ if !unresolved_arweave. contains ( & tx_id) {
397+ unresolved_arweave. push ( tx_id) ;
398+ }
399+ }
400+
401+ let mut missing_parts: Vec < String > = Vec :: new ( ) ;
402+
403+ if !unresolved_ipfs. is_empty ( ) {
404+ let list = unresolved_ipfs
374405 . iter ( )
375406 . map ( |p| format ! ( " - {}" , p) )
376407 . collect :: < Vec < _ > > ( )
377408 . join ( "\n " ) ;
409+ missing_parts. push ( format ! (
410+ "IPFS CIDs not found in mock 'files':\n {}\n \
411+ Add the missing CID(s) to the \" files\" array in your test JSON.",
412+ list
413+ ) ) ;
414+ }
415+
416+ if !unresolved_arweave. is_empty ( ) {
417+ let list = unresolved_arweave
418+ . iter ( )
419+ . map ( |id| format ! ( " - {}" , id) )
420+ . collect :: < Vec < _ > > ( )
421+ . join ( "\n " ) ;
422+ missing_parts. push ( format ! (
423+ "Arweave tx IDs not found in mock 'arweaveFiles':\n {}\n \
424+ Add the missing txId(s) to the \" arweaveFiles\" array in your test JSON.",
425+ list
426+ ) ) ;
427+ }
428+
429+ if !missing_parts. is_empty ( ) {
378430 Ok ( TestResult {
379- handler_error : Some ( format ! (
380- "File data source requested CID not found in mock 'files':\n {}\n \
381- Add the missing CID(s) to the \" files\" array in your test JSON.",
382- cid_list
383- ) ) ,
431+ handler_error : Some ( missing_parts. join ( "\n \n " ) ) ,
384432 assertions : vec ! [ ] ,
385433 } )
386434 } else {
@@ -670,8 +718,7 @@ async fn setup_context(
670718 stores : & TestStores ,
671719 chain : & Arc < Chain > ,
672720 manifest_info : & ManifestInfo ,
673- mock_files : HashMap < ContentPath , graph:: bytes:: Bytes > ,
674- unresolved_tx : tokio:: sync:: mpsc:: UnboundedSender < ContentPath > ,
721+ mock_data : MockData ,
675722) -> Result < TestContext > {
676723 let build_dir = & manifest_info. build_dir ;
677724 let manifest_path = & manifest_info. manifest_path ;
@@ -705,9 +752,9 @@ async fn setup_context(
705752 // FileLinkResolver handles manifest loading; the mock handles file data sources.
706753 let ipfs_metrics = IpfsMetrics :: new ( & mock_registry) ;
707754 let ipfs_client = Arc :: new ( MockIpfsClient {
708- files : mock_files ,
755+ files : mock_data . ipfs_files ,
709756 metrics : ipfs_metrics,
710- unresolved_tx,
757+ unresolved_tx : mock_data . ipfs_unresolved_tx ,
711758 } ) ;
712759
713760 let ipfs_service = ipfs_service (
@@ -717,9 +764,13 @@ async fn setup_context(
717764 env_vars. mappings . ipfs_request_limit ,
718765 ) ;
719766
720- let arweave_resolver = Arc :: new ( ArweaveClient :: default ( ) ) ;
767+ let arweave_resolver: Arc < dyn graph:: components:: link_resolver:: ArweaveResolver > =
768+ Arc :: new ( MockArweaveResolver {
769+ files : mock_data. arweave_files ,
770+ unresolved_tx : mock_data. arweave_unresolved_tx ,
771+ } ) ;
721772 let arweave_service = arweave_service (
722- arweave_resolver. cheap_clone ( ) ,
773+ arweave_resolver,
723774 env_vars. mappings . ipfs_request_limit ,
724775 graph:: components:: link_resolver:: FileSizeLimit :: MaxBytes (
725776 env_vars. mappings . max_ipfs_file_bytes as u64 ,
0 commit comments