@@ -2801,146 +2801,89 @@ func TestArtifactoryDeleteByProps(t *testing.T) {
28012801 cleanArtifactoryTest ()
28022802}
28032803
2804- // TestArtifactoryDeleteCountsNonExistentFiles tests that delete correctly handles
2805- // files that don't exist. The CLI searches first, so non-existent files return
2806- // All 3 files should return 404 on second delete attempt.
2807- // TestArtifactoryDeleteCountsNonExistentFiles tests that delete correctly counts
2808- // 404 failures when all files have already been deleted.
2809- // Files are placed in separate subfolders to prevent path reduction optimization.
2810- func TestArtifactoryDeleteCountsNonExistentFiles (t * testing.T ) {
2811- initArtifactoryTest (t , "" )
2812-
2813- // Step 1: Upload 3 specific test files in SEPARATE subfolders to prevent path reduction
2814- // Each file goes in its own subfolder so delete service can't optimize to folder delete
2815- testFiles := []string {"f1/a1.in" , "f2/a2.in" , "f3/a3.in" }
2816- sourceFiles := []string {"testdata/a/a1.in" , "testdata/a/a2.in" , "testdata/a/a3.in" }
2817- for i , f := range testFiles {
2818- runRt (t , "upload" , sourceFiles [i ], tests .RtRepo1 + "/delete-nonexistent/" + f )
2819- }
2820- t .Logf ("Uploaded %d test files: %v" , len (testFiles ), testFiles )
2821-
2822- // Step 2: Delete each file using direct DELETE API and verify success (HTTP 204)
2823- for _ , f := range testFiles {
2824- artifactPath := tests .RtRepo1 + "/delete-nonexistent/" + f
2825- success , err := tests .DeleteFileDirect (serverDetails , artifactPath )
2826- assert .NoError (t , err , "First delete of %s should not return error" , f )
2827- assert .True (t , success , "First delete of %s should succeed (HTTP 204)" , f )
2828- }
2829- t .Log ("First delete: all files deleted successfully (HTTP 204)" )
2830-
2831- // Step 3: Verify all files are now gone via search
2832- searchSpec := spec .NewBuilder ().
2833- Pattern (tests .RtRepo1 + "/delete-nonexistent/*" ).
2834- Recursive (true ).
2835- BuildSpec ()
2836- searchCmd := generic .NewSearchCommand ()
2837- searchCmd .SetServerDetails (serverDetails ).SetSpec (searchSpec )
2838- reader , err := searchCmd .Search ()
2839- assert .NoError (t , err )
2840- remainingFiles , err := reader .Length ()
2841- assert .NoError (t , err )
2842- readerCloseAndAssert (t , reader )
2843- assert .Equal (t , 0 , remainingFiles , "All files should be deleted" )
2844- t .Log ("Verified all files are deleted" )
2804+ // TestArtifactoryDeleteCountsPartialSuccess tests that delete correctly handles
2805+ // a mix of successful and failed deletions using CLI's DeleteFiles API.
2806+ // Uses permission-based failures (403) to reliably test partial success scenarios.
2807+ // - Files in RtRepo1: user has delete permission → success (204)
2808+ // - Files in RtRepo2: user has NO delete permission → failure (403)
2809+ func TestArtifactoryDeleteCountsPartialSuccess (t * testing.T ) {
2810+ initArtifactoryTest (t , "" )
28452811
2846- // Step 4: Try to delete ALL files AGAIN using CLI's DeleteFiles API
2847- // Build list of artifact paths
2848- var artifactPaths []string
2849- for _ , f := range testFiles {
2850- artifactPaths = append (artifactPaths , tests .RtRepo1 + "/delete-nonexistent/" + f )
2851- }
2852- t .Logf ("Attempting second delete of paths: %v" , artifactPaths )
2812+ // Test user credentials
2813+ testUser := "delete-test-user"
2814+ testPassword := "DeleteTest123!"
28532815
2854- // Use CLI's DeleteFiles API which should properly count 404s as failures
2855- // Error IS expected because all files return 404
2856- totalSuccess , totalFail , err := tests .DeleteFilesByPathsUsingCli (serverDetails , artifactPaths )
2857- // Error is expected when files don't exist (404 responses)
2858- t .Logf ("Second delete result: success=%d, fail=%d, err=%v" , totalSuccess , totalFail , err )
2816+ // Step 1: Create a test user
2817+ err := tests .CreateUserWithPassword (serverDetails , testUser , testPassword )
2818+ assert .NoError (t , err , "Failed to create test user" )
2819+ t .Logf ("Created test user: %s" , testUser )
28592820
2860- // Step 5: Verify - all 3 files should return 404 (failedCount=3)
2861- expectedSuccess := 0
2862- expectedFail := len (testFiles )
2863- t .Logf ("Expected: successCount=%d, failCount=%d" , expectedSuccess , expectedFail )
2864- t .Logf ("Actual: successCount=%d, failCount=%d" , totalSuccess , totalFail )
2865- assert .Equal (t , expectedSuccess , totalSuccess ,
2866- "Second delete should have 0 successes (all files already deleted), got %d" , totalSuccess )
2867- assert .Equal (t , expectedFail , totalFail ,
2868- "Second delete should have %d failures (all 404), got %d" , expectedFail , totalFail )
2821+ // Cleanup user at the end
2822+ defer func () {
2823+ _ = tests .DeleteUser (serverDetails , testUser )
2824+ t .Logf ("Cleaned up test user: %s" , testUser )
2825+ }()
28692826
2870- // Cleanup
2871- cleanArtifactoryTest ()
2872- }
2827+ // Step 2: Create permission target - user can delete from RtRepo1 but NOT from RtRepo2
2828+ permissionName := "delete-partial-test-perm"
2829+ err = tests .CreatePermissionTarget (serverDetails , permissionName , tests .RtRepo1 , testUser , []string {"read" , "write" , "delete" })
2830+ assert .NoError (t , err , "Failed to create permission target for RtRepo1" )
2831+ t .Logf ("Created permission target: %s (allows delete on %s)" , permissionName , tests .RtRepo1 )
28732832
2874- // TestArtifactoryDeleteCountsPartiallyDeleted tests that delete correctly handles
2875- // a mix of existing and non-existing files using CLI's DeleteFiles API.
2876- // - 3 existing files should return success
2877- // - 2 pre-deleted files should return failure (404)
2878- // Files are placed in separate subfolders to prevent path reduction optimization.
2879- func TestArtifactoryDeleteCountsPartiallyDeleted (t * testing.T ) {
2880- initArtifactoryTest (t , "" )
2833+ // Cleanup permission at the end
2834+ defer func () {
2835+ _ = tests .DeletePermissionTarget (serverDetails , permissionName )
2836+ t .Logf ("Cleaned up permission target: %s" , permissionName )
2837+ }()
28812838
2882- // Step 1 : Upload 5 specific test files in SEPARATE subfolders to prevent path reduction
2883- // Each file goes in its own subfolder so delete service can't optimize to folder delete
2884- testFiles := []string {"f1/a1.in" , "f2/a2.in" , "f3/a3.in" , "f4/b1.in" , "f5/b2 .in" }
2885- sourceFiles := []string {"testdata/a/a1.in" , "testdata/a/a2.in" , "testdata/a/a3.in" , "testdata/a/b/b1.in" , "testdata/a/b/b2 .in" }
2886- for i , f := range testFiles {
2887- runRt (t , "upload" , sourceFiles [i ], tests .RtRepo1 + "/delete-partial/" + f )
2839+ // Step 3 : Upload files as admin to both repos
2840+ // 3 files to RtRepo1 (will succeed with delete)
2841+ allowedFiles := []string {"f1/a1.in" , "f2/a2.in" , "f3/a3.in" }
2842+ sourceFilesAllowed := []string {"testdata/a/a1.in" , "testdata/a/a2.in" , "testdata/a/a3.in" }
2843+ for i , f := range allowedFiles {
2844+ runRt (t , "upload" , sourceFilesAllowed [i ], tests .RtRepo1 + "/delete-partial/" + f )
28882845 }
2889- t .Logf ("Uploaded %d test files: %v " , len (testFiles ), testFiles )
2846+ t .Logf ("Uploaded %d files to %s (delete allowed) " , len (allowedFiles ), tests . RtRepo1 )
28902847
2891- // Step 2: Pre-delete 2 files (f1/a1.in and f2/a2.in) using direct DELETE API
2892- filesToPreDelete := []string {"f1/a1.in" , "f2/a2.in" }
2893- for _ , f := range filesToPreDelete {
2894- artifactPath := tests .RtRepo1 + "/delete-partial/" + f
2895- success , err := tests .DeleteFileDirect (serverDetails , artifactPath )
2896- assert .NoError (t , err , "Pre-delete of %s should not return error" , f )
2897- assert .True (t , success , "Pre-delete of %s should succeed (HTTP 204)" , f )
2898- t .Logf ("Pre-deleted %s successfully (HTTP 204)" , f )
2848+ // 2 files to RtRepo2 (will fail with 403)
2849+ deniedFiles := []string {"f4/b1.in" , "f5/b2.in" }
2850+ sourceFilesDenied := []string {"testdata/a/b/b1.in" , "testdata/a/b/b2.in" }
2851+ for i , f := range deniedFiles {
2852+ runRt (t , "upload" , sourceFilesDenied [i ], tests .RtRepo2 + "/delete-partial/" + f )
28992853 }
2854+ t .Logf ("Uploaded %d files to %s (delete denied)" , len (deniedFiles ), tests .RtRepo2 )
29002855
2901- // Step 3: Verify pre-deleted files are gone via search
2902- for _ , f := range filesToPreDelete {
2903- searchSpec := spec .NewBuilder ().
2904- Pattern (tests .RtRepo1 + "/delete-partial/" + f ).
2905- BuildSpec ()
2906- searchCmd := generic .NewSearchCommand ()
2907- searchCmd .SetServerDetails (serverDetails ).SetSpec (searchSpec )
2908- reader , err := searchCmd .Search ()
2909- assert .NoError (t , err )
2910- count , err := reader .Length ()
2911- assert .NoError (t , err )
2912- readerCloseAndAssert (t , reader )
2913- assert .Equal (t , 0 , count , "File %s should be deleted" , f )
2914- }
2915- t .Log ("Verified pre-deleted files are gone" )
2856+ // Step 4: Create server details for the test user
2857+ testUserServerDetails := tests .CreateServerDetailsWithCredentials (serverDetails , testUser , testPassword )
29162858
2917- // Step 4: Now try to delete ALL 5 files using CLI's DeleteFiles API
2918- // - 3 files exist (f3/a3, f4/b1, f5/b2) → should return success
2919- // - 2 files don't exist (f1/a1, f2/a2) → should return failure (404)
2859+ // Step 5: Build list of all artifact paths (from both repos)
29202860 var artifactPaths []string
2921- for _ , f := range testFiles {
2861+ for _ , f := range allowedFiles {
29222862 artifactPaths = append (artifactPaths , tests .RtRepo1 + "/delete-partial/" + f )
29232863 }
2924- t .Logf ("Attempting to delete paths: %v" , artifactPaths )
2864+ for _ , f := range deniedFiles {
2865+ artifactPaths = append (artifactPaths , tests .RtRepo2 + "/delete-partial/" + f )
2866+ }
2867+ t .Logf ("Attempting to delete %d paths with limited user: %v" , len (artifactPaths ), artifactPaths )
29252868
2926- // Error IS expected because some files return 404
2927- totalSuccess , totalFail , err := tests .DeleteFilesByPathsUsingCli (serverDetails , artifactPaths )
2928- // Error is expected when some files don't exist (404 responses)
2929- t .Logf ("Delete all 5 files result: success=%d, fail=%d, err=%v" , totalSuccess , totalFail , err )
2869+ // Step 6: Delete using the test user's credentials
2870+ // - 3 files from RtRepo1 → should succeed (204)
2871+ // - 2 files from RtRepo2 → should fail (403)
2872+ totalSuccess , totalFail , err := tests .DeleteFilesByPathsUsingCli (testUserServerDetails , artifactPaths )
2873+ // Error IS expected because some files return 403
2874+ t .Logf ("Delete result: success=%d, fail=%d, err=%v" , totalSuccess , totalFail , err )
29302875
2931- // Step 5: Verify counts
2932- // 3 files existed (f3/a3, f4/b1, f5/b2) = 3 success
2933- // 2 files didn't exist (f1/a1, f2/a2) = 2 fail (404)
2934- expectedSuccess := len (testFiles ) - len (filesToPreDelete )
2935- expectedFail := len (filesToPreDelete )
2876+ // Step 7: Verify counts
2877+ expectedSuccess := len (allowedFiles )
2878+ expectedFail := len (deniedFiles )
29362879 t .Logf ("Expected: successCount=%d, failCount=%d" , expectedSuccess , expectedFail )
29372880 t .Logf ("Actual: successCount=%d, failCount=%d" , totalSuccess , totalFail )
29382881 assert .Equal (t , expectedSuccess , totalSuccess ,
2939- "Should have %d successes (f3/a3, f4/b1, f5/b2 still existed ), got %d" , expectedSuccess , totalSuccess )
2882+ "Should have %d successes (files from %s ), got %d" , expectedSuccess , tests . RtRepo1 , totalSuccess )
29402883 assert .Equal (t , expectedFail , totalFail ,
2941- "Should have %d failures (f1/a1, f2/a2 already deleted = 404 ), got %d" , expectedFail , totalFail )
2884+ "Should have %d failures (files from %s - 403 ), got %d" , expectedFail , tests . RtRepo2 , totalFail )
29422885
2943- // Step 6 : Verify all files are now gone
2886+ // Step 8 : Verify files from RtRepo1 are deleted
29442887 searchSpec := spec .NewBuilder ().
29452888 Pattern (tests .RtRepo1 + "/delete-partial/*" ).
29462889 Recursive (true ).
@@ -2949,10 +2892,24 @@ func TestArtifactoryDeleteCountsPartiallyDeleted(t *testing.T) {
29492892 searchCmd .SetServerDetails (serverDetails ).SetSpec (searchSpec )
29502893 reader , err := searchCmd .Search ()
29512894 assert .NoError (t , err )
2952- finalCount , err := reader .Length ()
2895+ repo1Count , err := reader .Length ()
29532896 assert .NoError (t , err )
29542897 readerCloseAndAssert (t , reader )
2955- assert .Equal (t , 0 , finalCount , "All files should be deleted" )
2898+ assert .Equal (t , 0 , repo1Count , "All files from %s should be deleted" , tests .RtRepo1 )
2899+
2900+ // Step 9: Verify files from RtRepo2 still exist (delete failed)
2901+ searchSpec2 := spec .NewBuilder ().
2902+ Pattern (tests .RtRepo2 + "/delete-partial/*" ).
2903+ Recursive (true ).
2904+ BuildSpec ()
2905+ searchCmd2 := generic .NewSearchCommand ()
2906+ searchCmd2 .SetServerDetails (serverDetails ).SetSpec (searchSpec2 )
2907+ reader2 , err := searchCmd2 .Search ()
2908+ assert .NoError (t , err )
2909+ repo2Count , err := reader2 .Length ()
2910+ assert .NoError (t , err )
2911+ readerCloseAndAssert (t , reader2 )
2912+ assert .Equal (t , len (deniedFiles ), repo2Count , "Files from %s should still exist (delete was denied)" , tests .RtRepo2 )
29562913
29572914 // Cleanup
29582915 cleanArtifactoryTest ()
0 commit comments