This is an automated email from the ASF dual-hosted git repository.

nixonrodrigues pushed a commit to branch ATLAS-5409
in repository https://gitbox.apache.org/repos/asf/atlas.git

commit 9b995a2556ae89b4215c6193b4c18438157f8d4f
Author: nixonrodrigues <[email protected]>
AuthorDate: Fri Jul 24 19:50:51 2026 +0530

    ATLAS-5352 :- Add Unit Testcases for Relationship
---
 .../simple/AtlasSimpleAuthorizerTest.java          |  94 ++++++++
 .../test/resources/atlas-simple-authz-policy.json  |  20 +-
 .../v2/AtlasRelationshipStoreV2ReadAuthTest.java   | 240 +++++++++++++++++++++
 .../web/rest/SearchDownloadFileValidatorTest.java  | 136 ++++++++++++
 4 files changed, 488 insertions(+), 2 deletions(-)

diff --git 
a/authorization/src/test/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizerTest.java
 
b/authorization/src/test/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizerTest.java
index d61ae7afc..2dd677065 100644
--- 
a/authorization/src/test/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizerTest.java
+++ 
b/authorization/src/test/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizerTest.java
@@ -50,6 +50,12 @@ public class AtlasSimpleAuthorizerTest {
     private static final String USER_FINANCE_PII      = "financePII";
     private static final String USER_IN_ADMIN_GROUP   = "admin-group-user";
     private static final String USER_IN_UNKNOWN_GROUP = "unknown-group-user";
+    private static final String USER_REL_READER       = "relreader";
+    private static final String USER_RANGER_TAG_SYNC  = "rangertagsync";
+
+    private static final String SALES_FACT_TABLE_QN        = "sales_fact@cl1";
+    private static final String SALES_FACT_SALES_COLUMN_QN = 
"Sales.sales_fact.sales@cl1";
+    private static final String SALES_FACT_TIME_COLUMN_QN  = 
"Sales.sales_fact.time_id@cl1";
 
     private static final Map<String, Set<String>> USER_GROUPS       = new 
HashMap<>();
     private static final List<AtlasPrivilege>     ENTITY_PRIVILEGES = new 
ArrayList<>();
@@ -336,6 +342,92 @@ public class AtlasSimpleAuthorizerTest {
         }
     }
 
+    @Test
+    public void 
testRelationshipRead_AllowsWhenWildcardEntityIdsPermitBothEnds() {
+        assertRelationshipReadAllowed(USER_RANGER_TAG_SYNC, 
SALES_FACT_TABLE_QN, SALES_FACT_SALES_COLUMN_QN);
+    }
+
+    @Test
+    public void 
testRelationshipRead_AllowsWhenPartialEntityIdsPermitBothEnds() {
+        assertRelationshipReadAllowed(USER_REL_READER, SALES_FACT_TABLE_QN, 
SALES_FACT_SALES_COLUMN_QN);
+    }
+
+    @Test
+    public void 
testRelationshipRead_DeniesWhenPartialEntityIdsPermitOnlyTableEnd() {
+        assertEntityReadAllowed(USER_REL_READER, "Table", SALES_FACT_TABLE_QN);
+        assertEntityReadDenied(USER_REL_READER, "Column", 
SALES_FACT_TIME_COLUMN_QN);
+        assertRelationshipReadDenied(USER_REL_READER, SALES_FACT_TABLE_QN, 
SALES_FACT_TIME_COLUMN_QN);
+    }
+
+    @Test
+    public void 
testRelationshipRead_DeniesWhenPartialEntityIdsPermitOnlyColumnEnd() {
+        assertEntityReadDenied(USER_REL_READER, "Table", "other_table@cl1");
+        assertEntityReadAllowed(USER_REL_READER, "Column", 
SALES_FACT_SALES_COLUMN_QN);
+        assertRelationshipReadDenied(USER_REL_READER, "other_table@cl1", 
SALES_FACT_SALES_COLUMN_QN);
+    }
+
+    @Test
+    public void testRelationshipRead_DeniesWhenUserHasNoEntityRead() {
+        assertEntityReadDenied(USER_IN_UNKNOWN_GROUP, "Table", 
SALES_FACT_TABLE_QN);
+        assertEntityReadDenied(USER_IN_UNKNOWN_GROUP, "Column", 
SALES_FACT_SALES_COLUMN_QN);
+        assertRelationshipReadDenied(USER_IN_UNKNOWN_GROUP, 
SALES_FACT_TABLE_QN, SALES_FACT_SALES_COLUMN_QN);
+    }
+
+    private void assertRelationshipReadAllowed(String userName, String 
end1QualifiedName, String end2QualifiedName) {
+        assertEntityReadAllowed(userName, "Table", end1QualifiedName);
+        assertEntityReadAllowed(userName, "Column", end2QualifiedName);
+
+        AssertJUnit.assertTrue("user " + userName + " should be allowed 
relationship read on "
+                        + end1QualifiedName + " and " + end2QualifiedName,
+                isRelationshipReadAllowed(userName, end1QualifiedName, 
end2QualifiedName));
+    }
+
+    private void assertRelationshipReadDenied(String userName, String 
end1QualifiedName, String end2QualifiedName) {
+        AssertJUnit.assertFalse("user " + userName + " should be denied 
relationship read on "
+                        + end1QualifiedName + " and " + end2QualifiedName,
+                isRelationshipReadAllowed(userName, end1QualifiedName, 
end2QualifiedName));
+    }
+
+    private void assertEntityReadAllowed(String userName, String typeName, 
String qualifiedName) {
+        AssertJUnit.assertTrue("user " + userName + " should have entity-read 
on " + qualifiedName,
+                isEntityReadAllowed(userName, typeName, qualifiedName));
+    }
+
+    private void assertEntityReadDenied(String userName, String typeName, 
String qualifiedName) {
+        AssertJUnit.assertFalse("user " + userName + " should not have 
entity-read on " + qualifiedName,
+                isEntityReadAllowed(userName, typeName, qualifiedName));
+    }
+
+    private boolean isRelationshipReadAllowed(String userName, String 
end1QualifiedName, String end2QualifiedName) {
+        return isEntityReadAllowed(userName, "Table", end1QualifiedName)
+                && isEntityReadAllowed(userName, "Column", end2QualifiedName);
+    }
+
+    private boolean isEntityReadAllowed(String userName, String typeName, 
String qualifiedName) {
+        try {
+            AtlasEntityAccessRequest request = new 
AtlasEntityAccessRequest(null, AtlasPrivilege.ENTITY_READ,
+                    createEntityHeader(typeName, qualifiedName));
+
+            setUser(request, userName);
+
+            return authorizer.isAccessAllowed(request);
+        } catch (Exception e) {
+            LOG.error("Exception in AtlasSimpleAuthorizerTest", e);
+
+            AssertJUnit.fail();
+
+            return false;
+        }
+    }
+
+    private AtlasEntityHeader createEntityHeader(String typeName, String 
qualifiedName) {
+        Map<String, Object> attributes = new HashMap<>();
+
+        attributes.put("qualifiedName", qualifiedName);
+
+        return new AtlasEntityHeader(typeName, attributes);
+    }
+
     private void setUser(AtlasAccessRequest request, String userName) {
         Set<String> userGroups = USER_GROUPS.get(userName);
 
@@ -351,6 +443,8 @@ public class AtlasSimpleAuthorizerTest {
         USER_GROUPS.put(USER_FINANCE_PII, 
Collections.singleton("FINANCE_PII"));
         USER_GROUPS.put(USER_IN_ADMIN_GROUP, 
Collections.singleton("ROLE_ADMIN"));
         USER_GROUPS.put(USER_IN_UNKNOWN_GROUP, 
Collections.singleton("UNKNOWN_GROUP"));
+        USER_GROUPS.put(USER_REL_READER, 
Collections.singleton("REL_PARTIAL_READ"));
+        USER_GROUPS.put(USER_RANGER_TAG_SYNC, 
Collections.singleton("RANGER_TAG_SYNC"));
 
         ENTITY_PRIVILEGES.add(AtlasPrivilege.ENTITY_CREATE);
         ENTITY_PRIVILEGES.add(AtlasPrivilege.ENTITY_UPDATE);
diff --git a/authorization/src/test/resources/atlas-simple-authz-policy.json 
b/authorization/src/test/resources/atlas-simple-authz-policy.json
index cada90447..f4a254cbb 100644
--- a/authorization/src/test/resources/atlas-simple-authz-policy.json
+++ b/authorization/src/test/resources/atlas-simple-authz-policy.json
@@ -127,6 +127,20 @@
           "classifications":       [ "PII.*" ]
         }
       ]
+    },
+
+    "REL_PARTIAL_READ": {
+      "entityPermissions": [
+        {
+          "privileges":            [ "entity-read", 
"entity-read-classification" ],
+          "entityTypes":           [ ".*" ],
+          "entityIds":             [ "sales_fact@cl1", 
"Sales.sales_fact.sales@cl1" ],
+          "entityClassifications": [ ".*" ],
+          "labels":                [ ".*" ],
+          "businessMetadata":      [ ".*" ],
+          "attributes":            [ ".*" ]
+        }
+      ]
     }
   },
 
@@ -134,7 +148,8 @@
     "admin":          [ "ROLE_ADMIN" ],
     "rangertagsync":  [ "DATA_SCIENTIST" ],
     "dataScientist1": [ "DATA_SCIENTIST"],
-    "dataSteward1":   [ "DATA_STEWARD"]
+    "dataSteward1":   [ "DATA_STEWARD"],
+    "relreader":      [ "REL_PARTIAL_READ" ]
   },
 
   "groupRoles": {
@@ -145,6 +160,7 @@
     "FINANCE":         [ "FINANCE" ],
     "FINANCE_PII":     [ "FINANCE_PII" ],
     "RANGER_TAG_SYNC": [ "DATA_SCIENTIST" ],
-    "DATA_STEWARD_EX": [ "DATA_STEWARD_EX" ]
+    "DATA_STEWARD_EX": [ "DATA_STEWARD_EX" ],
+    "REL_PARTIAL_READ":[ "REL_PARTIAL_READ" ]
   }
 }
diff --git 
a/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreV2ReadAuthTest.java
 
b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreV2ReadAuthTest.java
new file mode 100644
index 000000000..b8f4bf7ad
--- /dev/null
+++ 
b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreV2ReadAuthTest.java
@@ -0,0 +1,240 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE
+ * file distributed with this work for additional information regarding 
copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package org.apache.atlas.repository.store.graph.v2;
+
+import org.apache.atlas.AtlasErrorCode;
+import org.apache.atlas.authorize.AtlasAuthorizationUtils;
+import org.apache.atlas.authorize.AtlasEntityAccessRequest;
+import org.apache.atlas.authorize.AtlasPrivilege;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.instance.AtlasEntityHeader;
+import org.apache.atlas.model.instance.AtlasRelationship;
+import 
org.apache.atlas.model.instance.AtlasRelationship.AtlasRelationshipWithExtInfo;
+import org.apache.atlas.repository.graph.GraphHelper;
+import org.apache.atlas.repository.graphdb.AtlasEdge;
+import org.apache.atlas.repository.graphdb.AtlasGraph;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.repository.store.graph.v1.DeleteHandlerDelegate;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.MockitoAnnotations;
+import org.mockito.ArgumentCaptor;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class AtlasRelationshipStoreV2ReadAuthTest {
+    private static final String RELATIONSHIP_GUID     = "relationship-guid-1";
+    private static final String END1_GUID             = "end1-guid";
+    private static final String END2_GUID             = "end2-guid";
+    private static final String END1_QUALIFIED_NAME   = "sales_fact@cl1";
+    private static final String END2_QUALIFIED_NAME   = 
"Sales.sales_fact.sales@cl1";
+
+    @Mock
+    private AtlasGraph graph;
+
+    @Mock
+    private AtlasTypeRegistry typeRegistry;
+
+    @Mock
+    private DeleteHandlerDelegate deleteDelegate;
+
+    @Mock
+    private IAtlasEntityChangeNotifier entityChangeNotifier;
+
+    @Mock
+    private GraphHelper graphHelper;
+
+    @Mock
+    private EntityGraphRetriever entityRetriever;
+
+    @Mock
+    private AtlasEdge edge;
+
+    @Mock
+    private AtlasVertex end1Vertex;
+
+    @Mock
+    private AtlasVertex end2Vertex;
+
+    private AtlasRelationshipStoreV2 relationshipStore;
+
+    private AutoCloseable mocks;
+
+    @BeforeMethod
+    public void setUp() throws Exception {
+        mocks = MockitoAnnotations.openMocks(this);
+
+        relationshipStore = new AtlasRelationshipStoreV2(graph, typeRegistry, 
deleteDelegate, entityChangeNotifier);
+
+        setField("graphHelper", graphHelper);
+        setField("entityRetriever", entityRetriever);
+
+        when(graphHelper.getEdgeForGUID(RELATIONSHIP_GUID)).thenReturn(edge);
+        when(edge.getOutVertex()).thenReturn(end1Vertex);
+        when(edge.getInVertex()).thenReturn(end2Vertex);
+
+        
when(entityRetriever.toAtlasEntityHeaderWithClassifications(end1Vertex)).thenReturn(tableHeader(END1_QUALIFIED_NAME));
+        
when(entityRetriever.toAtlasEntityHeaderWithClassifications(end2Vertex)).thenReturn(columnHeader(END2_QUALIFIED_NAME));
+    }
+
+    @AfterMethod
+    public void tearDown() throws Exception {
+        if (mocks != null) {
+            mocks.close();
+        }
+    }
+
+    @Test
+    public void testGetById_VerifiesEntityReadOnBothEnds() throws Exception {
+        AtlasRelationship expectedRelationship = new 
AtlasRelationship("hive_table_columns");
+
+        
when(entityRetriever.mapEdgeToAtlasRelationship(edge)).thenReturn(expectedRelationship);
+
+        try (MockedStatic<AtlasAuthorizationUtils> authUtils = 
mockStatic(AtlasAuthorizationUtils.class)) {
+            authUtils.when(() -> 
AtlasAuthorizationUtils.verifyAccess(any(AtlasEntityAccessRequest.class), 
any(), any()))
+                    .thenAnswer(invocation -> null);
+
+            AtlasRelationship actualRelationship = 
relationshipStore.getById(RELATIONSHIP_GUID);
+
+            assertEquals(actualRelationship, expectedRelationship);
+            authUtils.verify(() -> 
AtlasAuthorizationUtils.verifyAccess(any(AtlasEntityAccessRequest.class), 
any(), any()), times(2));
+        }
+    }
+
+    @Test
+    public void testGetExtInfoById_VerifiesEntityReadOnBothEnds() throws 
Exception {
+        AtlasRelationshipWithExtInfo expectedRelationship = new 
AtlasRelationshipWithExtInfo(new AtlasRelationship("hive_table_columns"));
+
+        
when(entityRetriever.mapEdgeToAtlasRelationshipWithExtInfo(edge)).thenReturn(expectedRelationship);
+
+        try (MockedStatic<AtlasAuthorizationUtils> authUtils = 
mockStatic(AtlasAuthorizationUtils.class)) {
+            authUtils.when(() -> 
AtlasAuthorizationUtils.verifyAccess(any(AtlasEntityAccessRequest.class), 
any(), any()))
+                    .thenAnswer(invocation -> null);
+
+            AtlasRelationshipWithExtInfo actualRelationship = 
relationshipStore.getExtInfoById(RELATIONSHIP_GUID);
+
+            assertEquals(actualRelationship, expectedRelationship);
+            authUtils.verify(() -> 
AtlasAuthorizationUtils.verifyAccess(any(AtlasEntityAccessRequest.class), 
any(), any()), times(2));
+        }
+    }
+
+    @Test(expectedExceptions = AtlasBaseException.class)
+    public void testGetById_DeniesWhenEnd1EntityReadFails() throws Exception {
+        when(entityRetriever.mapEdgeToAtlasRelationship(edge)).thenReturn(new 
AtlasRelationship("hive_table_columns"));
+
+        try (MockedStatic<AtlasAuthorizationUtils> authUtils = 
mockStatic(AtlasAuthorizationUtils.class)) {
+            authUtils.when(() -> 
AtlasAuthorizationUtils.verifyAccess(any(AtlasEntityAccessRequest.class), 
eq("read relationship: end1 guid="), eq(END1_GUID)))
+                    .thenThrow(new 
AtlasBaseException(AtlasErrorCode.UNAUTHORIZED_ACCESS, END1_GUID, 
AtlasPrivilege.ENTITY_READ.getType()));
+
+            relationshipStore.getById(RELATIONSHIP_GUID);
+        }
+    }
+
+    @Test(expectedExceptions = AtlasBaseException.class)
+    public void testGetById_DeniesWhenEnd2EntityReadFails() throws Exception {
+        when(entityRetriever.mapEdgeToAtlasRelationship(edge)).thenReturn(new 
AtlasRelationship("hive_table_columns"));
+
+        try (MockedStatic<AtlasAuthorizationUtils> authUtils = 
mockStatic(AtlasAuthorizationUtils.class)) {
+            authUtils.when(() -> 
AtlasAuthorizationUtils.verifyAccess(any(AtlasEntityAccessRequest.class), 
eq("read relationship: end1 guid="), eq(END1_GUID)))
+                    .thenAnswer(invocation -> null);
+            authUtils.when(() -> 
AtlasAuthorizationUtils.verifyAccess(any(AtlasEntityAccessRequest.class), 
eq("read relationship: end2 guid="), eq(END2_GUID)))
+                    .thenThrow(new 
AtlasBaseException(AtlasErrorCode.UNAUTHORIZED_ACCESS, END2_GUID, 
AtlasPrivilege.ENTITY_READ.getType()));
+
+            relationshipStore.getById(RELATIONSHIP_GUID);
+        }
+    }
+
+    @Test
+    public void testGetById_PassesEndQualifiedNamesToEntityReadCheck() throws 
Exception {
+        when(entityRetriever.mapEdgeToAtlasRelationship(edge)).thenReturn(new 
AtlasRelationship("Table_Columns"));
+
+        ArgumentCaptor<AtlasEntityAccessRequest> requestCaptor = 
ArgumentCaptor.forClass(AtlasEntityAccessRequest.class);
+
+        try (MockedStatic<AtlasAuthorizationUtils> authUtils = 
mockStatic(AtlasAuthorizationUtils.class)) {
+            authUtils.when(() -> 
AtlasAuthorizationUtils.verifyAccess(requestCaptor.capture(), any(), any()))
+                    .thenAnswer(invocation -> null);
+
+            relationshipStore.getById(RELATIONSHIP_GUID);
+
+            List<AtlasEntityAccessRequest> requests = 
requestCaptor.getAllValues();
+
+            assertEquals(requests.size(), 2);
+            assertEquals(requests.get(0).getEntityId(), END1_QUALIFIED_NAME);
+            assertEquals(requests.get(1).getEntityId(), END2_QUALIFIED_NAME);
+            assertEquals(requests.get(0).getAction(), 
AtlasPrivilege.ENTITY_READ);
+            assertEquals(requests.get(1).getAction(), 
AtlasPrivilege.ENTITY_READ);
+        }
+    }
+
+    @Test
+    public void testGetById_AllowsWhenBothEndQualifiedNamesPermitted() throws 
Exception {
+        when(entityRetriever.mapEdgeToAtlasRelationship(edge)).thenReturn(new 
AtlasRelationship("Table_Columns"));
+
+        try (MockedStatic<AtlasAuthorizationUtils> authUtils = 
mockStatic(AtlasAuthorizationUtils.class)) {
+            authUtils.when(() -> 
AtlasAuthorizationUtils.verifyAccess(any(AtlasEntityAccessRequest.class), 
any(), any()))
+                    .thenAnswer(invocation -> {
+                        AtlasEntityAccessRequest request = 
invocation.getArgument(0);
+                        String                   entityId  = 
request.getEntityId();
+
+                        assertTrue(entityId.equals(END1_QUALIFIED_NAME) || 
entityId.equals(END2_QUALIFIED_NAME),
+                                "unexpected entityId for relationship read: " 
+ entityId);
+
+                        return null;
+                    });
+
+            AtlasRelationship actualRelationship = 
relationshipStore.getById(RELATIONSHIP_GUID);
+
+            assertEquals(actualRelationship.getTypeName(), "Table_Columns");
+            authUtils.verify(() -> 
AtlasAuthorizationUtils.verifyAccess(any(AtlasEntityAccessRequest.class), 
any(), any()), times(2));
+        }
+    }
+
+    private AtlasEntityHeader tableHeader(String qualifiedName) {
+        return createEntityHeader("Table", END1_GUID, qualifiedName);
+    }
+
+    private AtlasEntityHeader columnHeader(String qualifiedName) {
+        return createEntityHeader("Column", END2_GUID, qualifiedName);
+    }
+
+    private AtlasEntityHeader createEntityHeader(String typeName, String guid, 
String qualifiedName) {
+        Map<String, Object> attributes = new HashMap<>();
+
+        attributes.put("qualifiedName", qualifiedName);
+
+        return new AtlasEntityHeader(typeName, guid, attributes);
+    }
+
+    private void setField(String fieldName, Object value) throws Exception {
+        Field field = 
AtlasRelationshipStoreV2.class.getDeclaredField(fieldName);
+
+        field.setAccessible(true);
+        field.set(relationshipStore, value);
+    }
+}
diff --git 
a/webapp/src/test/java/org/apache/atlas/web/rest/SearchDownloadFileValidatorTest.java
 
b/webapp/src/test/java/org/apache/atlas/web/rest/SearchDownloadFileValidatorTest.java
new file mode 100644
index 000000000..5764665ff
--- /dev/null
+++ 
b/webapp/src/test/java/org/apache/atlas/web/rest/SearchDownloadFileValidatorTest.java
@@ -0,0 +1,136 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE
+ * file distributed with this work for additional information regarding 
copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+package org.apache.atlas.web.rest;
+
+import org.apache.atlas.common.TestUtility;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.commons.io.FileUtils;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.expectThrows;
+
+public class SearchDownloadFileValidatorTest {
+    private static final String VALID_FILE_NAME = 
"admin_BASIC_2026-07-23_09-01-50.437.csv";
+
+    private File userDownloadDir;
+
+    @BeforeMethod
+    public void setUp() throws IOException {
+        userDownloadDir = 
Files.createTempDirectory("search-download-validator-test").toFile();
+    }
+
+    @AfterMethod
+    public void tearDown() throws IOException {
+        FileUtils.deleteDirectory(userDownloadDir);
+    }
+
+    @Test
+    public void testResolveDownloadFile_ValidFileName() throws Exception {
+        File expectedFile = new File(userDownloadDir, VALID_FILE_NAME);
+
+        assertTrue(expectedFile.createNewFile());
+
+        File resolvedFile = 
SearchDownloadFileValidator.resolveDownloadFile(VALID_FILE_NAME, 
userDownloadDir);
+
+        assertEquals(resolvedFile, expectedFile);
+    }
+
+    @Test
+    public void testResolveDownloadFile_ValidDslFileName() throws Exception {
+        String fileName     = "admin_DSL_2026-07-23_09-01-50.437.csv";
+        File   expectedFile = new File(userDownloadDir, fileName);
+
+        assertTrue(expectedFile.createNewFile());
+
+        File resolvedFile = 
SearchDownloadFileValidator.resolveDownloadFile(fileName, userDownloadDir);
+
+        assertEquals(resolvedFile, expectedFile);
+    }
+
+    @Test
+    public void testResolveDownloadFile_PathTraversal_ThrowsException() {
+        AtlasBaseException exception = expectThrows(AtlasBaseException.class,
+                () -> 
SearchDownloadFileValidator.resolveDownloadFile("../../../../conf/users-credentials.properties",
 userDownloadDir));
+
+        TestUtility.assertBadRequests(exception, 
SearchDownloadFileValidator.INVALID_DOWNLOAD_FILE_NAME_MSG);
+    }
+
+    @Test
+    public void 
testResolveDownloadFile_ParentDirectorySegment_ThrowsException() {
+        AtlasBaseException exception = expectThrows(AtlasBaseException.class,
+                () -> SearchDownloadFileValidator.resolveDownloadFile("..", 
userDownloadDir));
+
+        TestUtility.assertBadRequests(exception, 
SearchDownloadFileValidator.INVALID_DOWNLOAD_FILE_NAME_MSG);
+    }
+
+    @Test
+    public void testResolveDownloadFile_AbsolutePath_ThrowsException() {
+        AtlasBaseException exception = expectThrows(AtlasBaseException.class,
+                () -> 
SearchDownloadFileValidator.resolveDownloadFile("/etc/passwd", 
userDownloadDir));
+
+        TestUtility.assertBadRequests(exception, 
SearchDownloadFileValidator.INVALID_DOWNLOAD_FILE_NAME_MSG);
+    }
+
+    @Test
+    public void testResolveDownloadFile_InvalidExtension_ThrowsException() {
+        AtlasBaseException exception = expectThrows(AtlasBaseException.class,
+                () -> 
SearchDownloadFileValidator.resolveDownloadFile("admin_BASIC_2026-07-23_09-01-50.437.txt",
 userDownloadDir));
+
+        TestUtility.assertBadRequests(exception, 
SearchDownloadFileValidator.INVALID_DOWNLOAD_FILE_NAME_MSG);
+    }
+
+    @Test
+    public void testResolveDownloadFile_InvalidPrefix_ThrowsException() {
+        AtlasBaseException exception = expectThrows(AtlasBaseException.class,
+                () -> 
SearchDownloadFileValidator.resolveDownloadFile("results.csv", 
userDownloadDir));
+
+        TestUtility.assertBadRequests(exception, 
SearchDownloadFileValidator.INVALID_DOWNLOAD_FILE_NAME_MSG);
+    }
+
+    @Test
+    public void testResolveDownloadFile_BlankFileName_ThrowsException() {
+        AtlasBaseException exception = expectThrows(AtlasBaseException.class,
+                () -> SearchDownloadFileValidator.resolveDownloadFile("  ", 
userDownloadDir));
+
+        TestUtility.assertBadRequests(exception, 
SearchDownloadFileValidator.INVALID_DOWNLOAD_FILE_NAME_MSG);
+    }
+
+    @Test
+    public void 
testResolveDownloadFile_SymbolicLinkOutsideUserDir_ThrowsException() throws 
Exception {
+        File outsideDir  = 
Files.createTempDirectory("search-download-outside").toFile();
+        File outsideFile = new File(outsideDir, VALID_FILE_NAME);
+
+        try {
+            assertTrue(outsideFile.createNewFile());
+
+            File linkInUserDir = new File(userDownloadDir, VALID_FILE_NAME);
+
+            Files.createSymbolicLink(linkInUserDir.toPath(), 
outsideFile.toPath());
+
+            AtlasBaseException exception = 
expectThrows(AtlasBaseException.class,
+                    () -> 
SearchDownloadFileValidator.resolveDownloadFile(VALID_FILE_NAME, 
userDownloadDir));
+
+            TestUtility.assertBadRequests(exception, 
SearchDownloadFileValidator.INVALID_DOWNLOAD_FILE_NAME_MSG);
+        } finally {
+            FileUtils.deleteDirectory(outsideDir);
+        }
+    }
+}

Reply via email to