@@ -2801,18 +2801,16 @@ func TestArtifactoryDeleteByProps(t *testing.T) {
28012801 cleanArtifactoryTest ()
28022802}
28032803
2804- // TestArtifactoryDeleteCountsWithPartial404 tests that delete returns accurate
2805- // success/fail counts when 404 errors occur due to files being deleted between
2806- // GetPathsToDelete and DeleteFiles (race condition scenario).
2807- func TestArtifactoryDeleteCountsWithPartial404 (t * testing.T ) {
2804+ // TestArtifactoryDeleteCountsWithFull404 tests that delete returns accurate
2805+ // counts when ALL files are already deleted (all 404 errors).
2806+ func TestArtifactoryDeleteCountsWithFull404 (t * testing.T ) {
28082807 initArtifactoryTest (t , "" )
28092808
2810- // Step 1: Upload more than 5 test files (using testdata/a/ which has 9 .in files)
2809+ // Step 1: Upload test files
28112810 runRt (t , "upload" , "testdata/a/*.in" , tests .RtRepo1 + "/delete-404-test/" , "--flat=true" )
2812- runRt (t , "upload" , "testdata/a/b/*.in" , tests .RtRepo1 + "/delete-404-test/" , "--flat=true" )
2813- runRt (t , "upload" , "testdata/a/b/c/*.in" , tests .RtRepo1 + "/delete-404-test/" , "--flat=true" )
2811+ t .Log ("Uploaded test files" )
28142812
2815- // Verify we have more than 5 files uploaded
2813+ // Step 2: Search to find all uploaded files
28162814 searchSpec := spec .NewBuilder ().
28172815 Pattern (tests .RtRepo1 + "/delete-404-test/*.in" ).
28182816 BuildSpec ()
@@ -2823,10 +2821,10 @@ func TestArtifactoryDeleteCountsWithPartial404(t *testing.T) {
28232821 totalFiles , err := reader .Length ()
28242822 assert .NoError (t , err )
28252823 readerCloseAndAssert (t , reader )
2826- assert .Greater (t , totalFiles , 5 , "Should have uploaded more than 5 files for this test" )
2827- t .Logf ("Uploaded %d files for delete-404 test " , totalFiles )
2824+ assert .Greater (t , totalFiles , 0 , "Should have uploaded files for this test" )
2825+ t .Logf ("Found %d files to delete" , totalFiles )
28282826
2829- // Step 2 : Create delete command and get paths to delete
2827+ // Step 3 : Create delete command and get paths to delete
28302828 deleteSpec := spec .NewBuilder ().
28312829 Pattern (tests .RtRepo1 + "/delete-404-test/*.in" ).
28322830 BuildSpec ()
@@ -2838,92 +2836,157 @@ func TestArtifactoryDeleteCountsWithPartial404(t *testing.T) {
28382836 SetDryRun (false ).
28392837 SetQuiet (true )
28402838
2841- // Get paths to delete (this queries Artifactory for matching files)
2839+ // Get paths to delete
28422840 pathsReader , err := deleteCommand .GetPathsToDelete ()
28432841 assert .NoError (t , err )
28442842
2845- // Verify reader has the expected number of items
2843+ // Verify reader has the expected files
28462844 readerLength , err := pathsReader .Length ()
28472845 assert .NoError (t , err )
28482846 assert .Equal (t , totalFiles , readerLength , "Reader should contain all uploaded files" )
2849- t .Logf ("PathsReader contains %d items (expected %d)" , readerLength , totalFiles )
2850-
2851- // Reset the reader after Length() consumed it - required before passing to DeleteFiles
2847+ t .Logf ("PathsReader contains %d items" , readerLength )
28522848 pathsReader .Reset ()
28532849
2854- // Step 3: Simulate race condition - delete some files directly BEFORE calling DeleteFiles
2855- // This will cause 404 errors when DeleteFiles tries to delete them
2856- filesToPreDelete := 3
2857- preDeleteSpec1 := spec .NewBuilder ().Pattern (tests .RtRepo1 + "/delete-404-test/a1.in" ).BuildSpec ()
2858- preDeleteSuccess1 , preDeleteFail1 , err := tests .DeleteFiles (preDeleteSpec1 , serverDetails )
2859- assert .NoError (t , err , "Failed to pre-delete a1.in" )
2860- t .Logf ("Pre-delete a1.in: success=%d, fail=%d" , preDeleteSuccess1 , preDeleteFail1 )
2861-
2862- preDeleteSpec2 := spec .NewBuilder ().Pattern (tests .RtRepo1 + "/delete-404-test/a2.in" ).BuildSpec ()
2863- preDeleteSuccess2 , preDeleteFail2 , err := tests .DeleteFiles (preDeleteSpec2 , serverDetails )
2864- assert .NoError (t , err , "Failed to pre-delete a2.in" )
2865- t .Logf ("Pre-delete a2.in: success=%d, fail=%d" , preDeleteSuccess2 , preDeleteFail2 )
2866-
2867- preDeleteSpec3 := spec .NewBuilder ().Pattern (tests .RtRepo1 + "/delete-404-test/a3.in" ).BuildSpec ()
2868- preDeleteSuccess3 , preDeleteFail3 , err := tests .DeleteFiles (preDeleteSpec3 , serverDetails )
2869- assert .NoError (t , err , "Failed to pre-delete a3.in" )
2870- t .Logf ("Pre-delete a3.in: success=%d, fail=%d" , preDeleteSuccess3 , preDeleteFail3 )
2871-
2872- // Verify pre-deletion actually removed the files
2873- totalPreDeleted := preDeleteSuccess1 + preDeleteSuccess2 + preDeleteSuccess3
2874- assert .Equal (t , filesToPreDelete , totalPreDeleted ,
2875- "Pre-deletion should have deleted %d files, but deleted %d" , filesToPreDelete , totalPreDeleted )
2876-
2877- // Double-check by searching - should now have (totalFiles - filesToPreDelete) files
2850+ // Step 4: Delete all files (first delete - should all succeed)
2851+ successCount1 , failCount1 , deleteErr1 := deleteCommand .DeleteFiles (pathsReader )
2852+ t .Logf ("First delete: success=%d, fail=%d, err=%v" , successCount1 , failCount1 , deleteErr1 )
2853+
2854+ assert .NoError (t , deleteErr1 , "First delete should succeed without errors" )
2855+ assert .Equal (t , totalFiles , successCount1 , "First delete should succeed for all %d files" , totalFiles )
2856+ assert .Equal (t , 0 , failCount1 , "First delete should have no failures" )
2857+
2858+ // Step 5: Verify all files are now gone
28782859 reader , err = searchCmd .Search ()
2879- assert .NoError (t , err , "Failed to search after pre-deletion" )
2880- filesAfterPreDelete , err := reader .Length ()
2860+ assert .NoError (t , err )
2861+ remainingFiles , err := reader .Length ()
2862+ assert .NoError (t , err )
2863+ readerCloseAndAssert (t , reader )
2864+ assert .Equal (t , 0 , remainingFiles , "All files should be deleted after first delete" )
2865+ t .Log ("Verified all files are deleted" )
2866+
2867+ // Step 6: Reset the reader and try to delete AGAIN (all should get 404)
2868+ pathsReader .Reset ()
2869+ successCount2 , failCount2 , deleteErr2 := deleteCommand .DeleteFiles (pathsReader )
2870+ gofrogio .Close (pathsReader , & err )
2871+
2872+ t .Logf ("Second delete (all 404): success=%d, fail=%d, err=%v" , successCount2 , failCount2 , deleteErr2 )
2873+
2874+ // Step 7: Verify the results - all should fail with 404
2875+ totalProcessed := successCount2 + failCount2
2876+ assert .Equal (t , totalFiles , totalProcessed ,
2877+ "Total processed (success=%d + fail=%d = %d) should equal totalFiles=%d" ,
2878+ successCount2 , failCount2 , totalProcessed , totalFiles )
2879+
2880+ assert .Equal (t , 0 , successCount2 ,
2881+ "Second delete should have 0 successes (files already deleted), got %d" , successCount2 )
2882+
2883+ assert .Equal (t , totalFiles , failCount2 ,
2884+ "Second delete should have %d failures (all 404), got %d" , totalFiles , failCount2 )
2885+
2886+ // Cleanup
2887+ cleanArtifactoryTest ()
2888+ }
2889+
2890+ // TestArtifactoryDeleteCountsWithPartial404 tests that delete returns accurate
2891+ // counts when SOME files are already deleted (partial 404 errors).
2892+ func TestArtifactoryDeleteCountsWithPartial404 (t * testing.T ) {
2893+ initArtifactoryTest (t , "" )
2894+
2895+ // Step 1: Upload 5 specific test files
2896+ runRt (t , "upload" , "testdata/a/a1.in" , tests .RtRepo1 + "/delete-partial-404/" , "--flat=true" )
2897+ runRt (t , "upload" , "testdata/a/a2.in" , tests .RtRepo1 + "/delete-partial-404/" , "--flat=true" )
2898+ runRt (t , "upload" , "testdata/a/a3.in" , tests .RtRepo1 + "/delete-partial-404/" , "--flat=true" )
2899+ runRt (t , "upload" , "testdata/a/b/b1.in" , tests .RtRepo1 + "/delete-partial-404/" , "--flat=true" )
2900+ runRt (t , "upload" , "testdata/a/b/b2.in" , tests .RtRepo1 + "/delete-partial-404/" , "--flat=true" )
2901+ t .Log ("Uploaded 5 test files" )
2902+
2903+ // Step 2: Verify we have 5 files
2904+ searchSpec := spec .NewBuilder ().
2905+ Pattern (tests .RtRepo1 + "/delete-partial-404/*.in" ).
2906+ BuildSpec ()
2907+ searchCmd := generic .NewSearchCommand ()
2908+ searchCmd .SetServerDetails (serverDetails ).SetSpec (searchSpec )
2909+ reader , err := searchCmd .Search ()
2910+ assert .NoError (t , err )
2911+ totalFiles , err := reader .Length ()
28812912 assert .NoError (t , err )
28822913 readerCloseAndAssert (t , reader )
2883- expectedAfterPreDelete := totalFiles - filesToPreDelete
2884- assert .Equal (t , expectedAfterPreDelete , filesAfterPreDelete ,
2885- "After pre-deleting %d files, should have %d remaining, but found %d" ,
2886- filesToPreDelete , expectedAfterPreDelete , filesAfterPreDelete )
2914+ assert .Equal (t , 5 , totalFiles , "Should have uploaded 5 files" )
2915+ t .Logf ("Verified %d files uploaded" , totalFiles )
2916+
2917+ // Step 3: Create delete command and get paths for ALL 5 files
2918+ deleteSpec := spec .NewBuilder ().
2919+ Pattern (tests .RtRepo1 + "/delete-partial-404/*.in" ).
2920+ BuildSpec ()
28872921
2888- t .Logf ("Pre-deleted %d files, verified %d files remaining (expected %d)" ,
2889- totalPreDeleted , filesAfterPreDelete , expectedAfterPreDelete )
2922+ deleteCommand := generic .NewDeleteCommand ()
2923+ deleteCommand .SetThreads (1 ).
2924+ SetSpec (deleteSpec ).
2925+ SetServerDetails (serverDetails ).
2926+ SetDryRun (false ).
2927+ SetQuiet (true )
2928+
2929+ // Get paths for all 5 files
2930+ pathsReader , err := deleteCommand .GetPathsToDelete ()
2931+ assert .NoError (t , err )
2932+ readerLength , err := pathsReader .Length ()
2933+ assert .NoError (t , err )
2934+ assert .Equal (t , 5 , readerLength , "Reader should contain 5 files" )
2935+ t .Logf ("PathsReader contains %d items" , readerLength )
2936+ pathsReader .Reset ()
28902937
2891- // Step 4: Now call DeleteFiles with the original reader
2892- // The reader still contains paths to the pre-deleted files, so we'll get 404s
2938+ // Step 4: Delete only 2 files (a1.in and a2.in)
2939+ preDeleteSpec := spec .NewBuilder ().
2940+ Pattern (tests .RtRepo1 + "/delete-partial-404/a1.in" ).
2941+ BuildSpec ()
2942+ preDeleteSuccess1 , _ , err := tests .DeleteFiles (preDeleteSpec , serverDetails )
2943+ assert .NoError (t , err )
2944+ assert .Equal (t , 1 , preDeleteSuccess1 , "Should have deleted a1.in" )
2945+ t .Log ("Pre-deleted a1.in" )
2946+
2947+ preDeleteSpec2 := spec .NewBuilder ().
2948+ Pattern (tests .RtRepo1 + "/delete-partial-404/a2.in" ).
2949+ BuildSpec ()
2950+ preDeleteSuccess2 , _ , err := tests .DeleteFiles (preDeleteSpec2 , serverDetails )
2951+ assert .NoError (t , err )
2952+ assert .Equal (t , 1 , preDeleteSuccess2 , "Should have deleted a2.in" )
2953+ t .Log ("Pre-deleted a2.in" )
2954+
2955+ // Step 5: Verify only 3 files remain
2956+ reader , err = searchCmd .Search ()
2957+ assert .NoError (t , err )
2958+ remainingFiles , err := reader .Length ()
2959+ assert .NoError (t , err )
2960+ readerCloseAndAssert (t , reader )
2961+ assert .Equal (t , 3 , remainingFiles , "Should have 3 files remaining after pre-delete" )
2962+ t .Logf ("Verified %d files remaining after pre-deleting 2" , remainingFiles )
2963+
2964+ // Step 6: Now try to delete ALL 5 files using original pathsReader
2965+ // Expected: 3 success (a3, b1, b2), 2 fail (a1, a2 already deleted = 404)
28932966 successCount , failCount , deleteErr := deleteCommand .DeleteFiles (pathsReader )
28942967 gofrogio .Close (pathsReader , & err )
28952968
2896- // Step 5: Verify the fix - counts should be properly returned even with 404 errors
2897- // Before the fix: successCount=0, failCount=0 (bug!)
2898- // After the fix: successCount + failCount should equal totalFiles
28992969 t .Logf ("Delete result: success=%d, fail=%d, err=%v" , successCount , failCount , deleteErr )
29002970
2901- // Calculate expected values for clearer error messages
2902- expectedSuccessful := totalFiles - filesToPreDelete
2971+ // Step 7: Verify counts
29032972 totalProcessed := successCount + failCount
2973+ assert .Equal (t , 5 , totalProcessed ,
2974+ "Total processed (success=%d + fail=%d = %d) should equal 5" ,
2975+ successCount , failCount , totalProcessed )
29042976
2905- // The total of success + fail should equal what we tried to delete
2906- assert .Equal (t , totalFiles , totalProcessed ,
2907- "Total processed (success=%d + fail=%d = %d) should equal totalFiles=%d" ,
2908- successCount , failCount , totalProcessed , totalFiles )
2977+ assert .Equal (t , 3 , successCount ,
2978+ "Should have 3 successes (a3, b1, b2 still existed), got %d" , successCount )
29092979
2910- // We should have some successful deletes (files that weren't pre-deleted)
2911- assert .Equal (t , expectedSuccessful , successCount ,
2912- "Success count=%d should match expected=%d (totalFiles=%d - preDeleted=%d)" ,
2913- successCount , expectedSuccessful , totalFiles , filesToPreDelete )
2980+ assert .Equal (t , 2 , failCount ,
2981+ "Should have 2 failures (a1, a2 already deleted = 404), got %d" , failCount )
29142982
2915- // We should have some failures (the pre-deleted files that returned 404)
2916- assert .Equal (t , filesToPreDelete , failCount ,
2917- "Fail count=%d should match pre-deleted files=%d" ,
2918- failCount , filesToPreDelete )
2919-
2920- // Verify all files are now gone
2983+ // Step 8: Verify all files are now gone
29212984 reader , err = searchCmd .Search ()
29222985 assert .NoError (t , err )
2923- remainingFiles , err := reader .Length ()
2986+ finalCount , err := reader .Length ()
29242987 assert .NoError (t , err )
29252988 readerCloseAndAssert (t , reader )
2926- assert .Equal (t , 0 , remainingFiles , "All files should be deleted" )
2989+ assert .Equal (t , 0 , finalCount , "All files should be deleted" )
29272990
29282991 // Cleanup
29292992 cleanArtifactoryTest ()
0 commit comments