55 type FileMetadata ,
66 shUser ,
77 sleep ,
8+ type SqlClient ,
89 waitFor
910} from "../../../util" ;
1011
@@ -17,15 +18,27 @@ await describeMspNet(
1718 indexerMode : "fishing" ,
1819 standaloneIndexer : true
1920 } ,
20- ( { before, createUserApi, createBspApi, createMsp1Api, it, getLaunchResponse } ) => {
21+ ( {
22+ before,
23+ createUserApi,
24+ createBspApi,
25+ createMsp1Api,
26+ createFishermanApi,
27+ it,
28+ getLaunchResponse,
29+ createSqlClient,
30+ createIndexerApi
31+ } ) => {
2132 let userApi : EnrichedBspApi ;
2233 let bspApi : EnrichedBspApi ;
2334 let mspApi : EnrichedBspApi ;
35+ let sql : SqlClient ;
2436
2537 const bucketId1 = "cloud-bucket-1" ;
2638 const bucketId2 = "cloud-bucket-2" ;
2739 let file1 : FileMetadata ;
2840 let file2 : FileMetadata ;
41+ let indexerApi : EnrichedBspApi ;
2942
3043 // Helper to build and sign a file deletion intention
3144 const buildSignedDelete = ( fileKey : string ) => {
@@ -44,9 +57,17 @@ await describeMspNet(
4457 userApi = await createUserApi ( ) ;
4558 bspApi = await createBspApi ( ) ;
4659 const maybeMspApi = await createMsp1Api ( ) ;
60+ sql = createSqlClient ( ) ;
4761
4862 assert ( maybeMspApi , "MSP API not available" ) ;
4963 mspApi = maybeMspApi ;
64+
65+ assert ( createFishermanApi , "Fisherman API not available" ) ;
66+ await createFishermanApi ( ) ;
67+
68+ assert ( createIndexerApi , "Indexer API not available" ) ;
69+ indexerApi = await createIndexerApi ( ) ;
70+ await indexerApi . indexer . waitForIndexing ( { producerApi : userApi , sql } ) ;
5071 } ) ;
5172
5273 it ( "Network launches and can be queried" , async ( ) => {
@@ -230,68 +251,73 @@ await describeMspNet(
230251 signer : shUser
231252 } ) ;
232253
233- // Fisherman submits delete_files extrinsics (MSP + BSP)
234- await userApi . assert . extrinsicPresent ( {
235- method : "deleteFiles" ,
236- module : "fileSystem" ,
237- checkTxPool : true ,
238- assertLength : 2 // 1 for MSP and 1 for BSP
239- } ) ;
240- const block = await userApi . block . seal ( ) ;
254+ // Finalize the block on the indexer node and wait for the indexer to process the block
255+ await indexerApi . indexer . waitForIndexing ( { producerApi : userApi , sql } ) ;
241256
242- // Verify file removed from first bucket's forest
243- await waitFor ( {
244- lambda : async ( ) =>
245- ( await mspApi . rpc . storagehubclient . isFileInForest ( file1 . bucketId , file1 . fileKey ) ) . isFalse
257+ // Wait for fisherman to process the file deletions
258+ await userApi . fisherman . retryableWaitAndVerifyBatchDeletions ( {
259+ blockProducerApi : userApi ,
260+ deletionType : "User" ,
261+ expectExt : 2 ,
262+ userApi,
263+ bspApi,
264+ expectedBspCount : 1 ,
265+ mspApi : mspApi ,
266+ expectedBucketCount : 1 ,
267+ maxRetries : 3
246268 } ) ;
247269
248- // Finalising block in MSP node to trigger the event to delete the file.
249- // First we make sure the MSP is caught up to the block.
250- // Actually, it should trigger, but the file still shouldn't be deleted.
251- await mspApi . wait . nodeCatchUpToChainTip ( userApi ) ;
252- await mspApi . block . finaliseBlock ( block . blockReceipt . blockHash . toString ( ) ) ;
270+ // Non-producer nodes must explicitly finalize imported blocks to trigger file deletion
271+ // Producer node (user) has finalized blocks, but BSP and MSP must finalize locally
272+ const finalisedBlockHash = await userApi . rpc . chain . getFinalizedHead ( ) ;
253273
254- // Verify that the file metadata from the first file was removed from
255- // the file storage of the MSP, meaning that it should respond that this
256- // fileKey is not in the file storage.
257- await waitFor ( {
258- lambda : async ( ) =>
259- ( await mspApi . rpc . storagehubclient . isFileInFileStorage ( file1 . fileKey ) ) . isFileNotFound
260- } ) ;
274+ await bspApi . wait . blockImported ( finalisedBlockHash . toString ( ) ) ;
275+ await bspApi . block . finaliseBlock ( finalisedBlockHash . toString ( ) ) ;
261276
262- // But verify MSP still has the file in file storage via the second file key,
263- // meaning that for that second file key it has both the file metadata and the file content
264- // (which was the same file content as the first file)
265- await waitFor ( {
266- lambda : async ( ) =>
267- ( await mspApi . rpc . storagehubclient . isFileInFileStorage ( file2 . fileKey ) ) . isFileFound
268- } ) ;
277+ await mspApi . wait . blockImported ( finalisedBlockHash . toString ( ) ) ;
278+ await mspApi . block . finaliseBlock ( finalisedBlockHash . toString ( ) ) ;
269279
270- // Verify file removed from BSP's forest
280+ // Verify that the file metadata from the second file was removed from
281+ // the file storage of the BSP and MSP, meaning that it should respond that this
282+ // fileKey is not in the file storage. Now the file content should have
283+ // been deleted from the file storage as well.
271284 await waitFor ( {
272- lambda : async ( ) =>
273- ( await bspApi . rpc . storagehubclient . isFileInForest ( null , file1 . fileKey ) ) . isFalse
274- } ) ;
285+ lambda : async ( ) => {
286+ // Check file is NOT in BSP forest
287+ const bspForestResult = await bspApi . rpc . storagehubclient . isFileInForest (
288+ null ,
289+ file1 . fileKey
290+ ) ;
291+ if ( bspForestResult . isTrue ) {
292+ return false ;
293+ }
275294
276- // Finalising block in BSP node to trigger the event to delete the file.
277- // First we make sure the BSP is caught up to the block.
278- await bspApi . wait . nodeCatchUpToChainTip ( userApi ) ;
279- await bspApi . block . finaliseBlock ( block . blockReceipt . blockHash . toString ( ) ) ;
295+ // Check file is NOT in BSP file storage
296+ const bspFileStorageResult = await bspApi . rpc . storagehubclient . isFileInFileStorage (
297+ file1 . fileKey
298+ ) ;
299+ if ( bspFileStorageResult . isFileFound ) {
300+ return false ;
301+ }
280302
281- // Verify that the file metadata from the first file was removed from
282- // the file storage of the BSP, meaning that it should respond that this
283- // fileKey is not in the file storage.
284- await waitFor ( {
285- lambda : async ( ) =>
286- ( await bspApi . rpc . storagehubclient . isFileInFileStorage ( file1 . fileKey ) ) . isFileNotFound
287- } ) ;
303+ // Check file is NOT in MSP forest
304+ const mspForestResult = await mspApi . rpc . storagehubclient . isFileInForest (
305+ file2 . bucketId ,
306+ file1 . fileKey
307+ ) ;
308+ if ( mspForestResult . isTrue ) {
309+ return false ;
310+ }
288311
289- // But verify BSP still has the file in file storage via the second file key,
290- // meaning that for that second file key it has both the file metadata and the file content
291- // (which was the same file content as the first file)
292- await waitFor ( {
293- lambda : async ( ) =>
294- ( await bspApi . rpc . storagehubclient . isFileInFileStorage ( file2 . fileKey ) ) . isFileFound
312+ // Check file is NOT in MSP file storage
313+ const mspFileStorageResult = await mspApi . rpc . storagehubclient . isFileInFileStorage (
314+ file1 . fileKey
315+ ) ;
316+ if ( mspFileStorageResult . isFileFound ) {
317+ return false ;
318+ }
319+ return true ;
320+ }
295321 } ) ;
296322 } ) ;
297323
0 commit comments