Copilot commented on code in PR #17295: URL: https://github.com/apache/pinot/pull/17295#discussion_r2584025982
########## pinot-spi/src/test/java/org/apache/pinot/spi/utils/builder/UserConfigBuilderTest.java: ########## @@ -0,0 +1,261 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.pinot.spi.utils.builder; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.pinot.spi.config.user.AccessType; +import org.apache.pinot.spi.config.user.ComponentType; +import org.apache.pinot.spi.config.user.RoleType; +import org.apache.pinot.spi.config.user.UserConfig; +import org.testng.Assert; +import org.testng.annotations.Test; + + +/** + * Tests for {@link UserConfigBuilder} + */ +public class UserConfigBuilderTest { + + private static final String TEST_USERNAME = "testUser"; + private static final String TEST_PASSWORD = "testPassword"; + + @Test + public void testBasicUserConfigBuild() { + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.USER) + .build(); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), TEST_USERNAME, "Username should match"); + Assert.assertEquals(userConfig.getPassword(), TEST_PASSWORD, "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.BROKER, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.USER, "Role type should match"); + Assert.assertNull(userConfig.getTables(), "Tables should be null when not set"); + Assert.assertNull(userConfig.getExcludeTables(), "Exclude tables should be null when not set"); + Assert.assertNull(userConfig.getPermissios(), "Permissions should be null when not set"); Review Comment: Corrected spelling of 'getPermissios' to 'getPermissions'. ```suggestion Assert.assertNull(userConfig.getPermissions(), "Permissions should be null when not set"); ``` ########## pinot-spi/src/test/java/org/apache/pinot/spi/utils/builder/UserConfigBuilderTest.java: ########## @@ -0,0 +1,261 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.pinot.spi.utils.builder; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.pinot.spi.config.user.AccessType; +import org.apache.pinot.spi.config.user.ComponentType; +import org.apache.pinot.spi.config.user.RoleType; +import org.apache.pinot.spi.config.user.UserConfig; +import org.testng.Assert; +import org.testng.annotations.Test; + + +/** + * Tests for {@link UserConfigBuilder} + */ +public class UserConfigBuilderTest { + + private static final String TEST_USERNAME = "testUser"; + private static final String TEST_PASSWORD = "testPassword"; + + @Test + public void testBasicUserConfigBuild() { + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.USER) + .build(); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), TEST_USERNAME, "Username should match"); + Assert.assertEquals(userConfig.getPassword(), TEST_PASSWORD, "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.BROKER, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.USER, "Role type should match"); + Assert.assertNull(userConfig.getTables(), "Tables should be null when not set"); + Assert.assertNull(userConfig.getExcludeTables(), "Exclude tables should be null when not set"); + Assert.assertNull(userConfig.getPermissios(), "Permissions should be null when not set"); + Assert.assertNull(userConfig.getRlsFilters(), "RLS filters should be null when not set"); + } + + @Test + public void testUserConfigWithTableList() { + List<String> tableList = Arrays.asList("table1", "table2", "table3"); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.CONTROLLER) + .setRoleType(RoleType.ADMIN) + .setTableList(tableList) + .build(); + + Assert.assertNotNull(userConfig.getTables(), "Tables should not be null"); + Assert.assertEquals(userConfig.getTables(), tableList, "Table list should match"); + Assert.assertEquals(userConfig.getTables().size(), 3, "Table list size should be 3"); + } + + @Test + public void testUserConfigWithExcludeTableList() { + List<String> excludeTableList = Arrays.asList("excludeTable1", "excludeTable2"); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.SERVER) + .setRoleType(RoleType.USER) + .setExcludeTableList(excludeTableList) + .build(); + + Assert.assertNotNull(userConfig.getExcludeTables(), "Exclude tables should not be null"); + Assert.assertEquals(userConfig.getExcludeTables(), excludeTableList, "Exclude table list should match"); + Assert.assertEquals(userConfig.getExcludeTables().size(), 2, "Exclude table list size should be 2"); + } + + @Test + public void testUserConfigWithPermissionList() { + List<AccessType> permissionList = Arrays.asList(AccessType.READ, AccessType.CREATE, AccessType.UPDATE); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.MINION) + .setRoleType(RoleType.ADMIN) + .setPermissionList(permissionList) + .build(); + + Assert.assertNotNull(userConfig.getPermissios(), "Permissions should not be null"); + Assert.assertEquals(userConfig.getPermissios(), permissionList, "Permission list should match"); + Assert.assertEquals(userConfig.getPermissios().size(), 3, "Permission list size should be 3"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.READ), "Should contain READ permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.CREATE), "Should contain CREATE permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.UPDATE), "Should contain UPDATE permission"); + } + + @Test + public void testUserConfigWithRlsFilters() { + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("filter1", "filter2")); + rlsFilters.put("table2", Arrays.asList("filter3")); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.PROXY) + .setRoleType(RoleType.USER) + .setRlsFilters(rlsFilters) + .build(); + + Assert.assertNotNull(userConfig.getRlsFilters(), "RLS filters should not be null"); + Assert.assertEquals(userConfig.getRlsFilters(), rlsFilters, "RLS filters should match"); + Assert.assertEquals(userConfig.getRlsFilters().size(), 2, "RLS filters map size should be 2"); + Assert.assertTrue(userConfig.getRlsFilters().containsKey("table1"), "Should contain table1 filters"); + Assert.assertTrue(userConfig.getRlsFilters().containsKey("table2"), "Should contain table2 filters"); + Assert.assertEquals(userConfig.getRlsFilters().get("table1").size(), 2, "table1 should have 2 filters"); + Assert.assertEquals(userConfig.getRlsFilters().get("table2").size(), 1, "table2 should have 1 filter"); + } + + @Test + public void testUserConfigWithAllFields() { + List<String> tableList = Arrays.asList("table1", "table2"); + List<String> excludeTableList = Arrays.asList("excludeTable1"); + List<AccessType> permissionList = Arrays.asList(AccessType.READ, AccessType.UPDATE, AccessType.DELETE); + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("country='US'", "department='Engineering'")); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername("adminUser") + .setPassword("adminPass123") + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.ADMIN) + .setTableList(tableList) + .setExcludeTableList(excludeTableList) + .setPermissionList(permissionList) + .setRlsFilters(rlsFilters) + .build(); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), "adminUser", "Username should match"); + Assert.assertEquals(userConfig.getPassword(), "adminPass123", "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.BROKER, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.ADMIN, "Role type should match"); + Assert.assertEquals(userConfig.getTables(), tableList, "Table list should match"); + Assert.assertEquals(userConfig.getExcludeTables(), excludeTableList, "Exclude table list should match"); + Assert.assertEquals(userConfig.getPermissios(), permissionList, "Permission list should match"); Review Comment: Corrected spelling of 'getPermissios' to 'getPermissions'. ```suggestion Assert.assertEquals(userConfig.getPermissions(), permissionList, "Permission list should match"); ``` ########## pinot-spi/src/test/java/org/apache/pinot/spi/utils/builder/UserConfigBuilderTest.java: ########## @@ -0,0 +1,261 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.pinot.spi.utils.builder; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.pinot.spi.config.user.AccessType; +import org.apache.pinot.spi.config.user.ComponentType; +import org.apache.pinot.spi.config.user.RoleType; +import org.apache.pinot.spi.config.user.UserConfig; +import org.testng.Assert; +import org.testng.annotations.Test; + + +/** + * Tests for {@link UserConfigBuilder} + */ +public class UserConfigBuilderTest { + + private static final String TEST_USERNAME = "testUser"; + private static final String TEST_PASSWORD = "testPassword"; + + @Test + public void testBasicUserConfigBuild() { + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.USER) + .build(); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), TEST_USERNAME, "Username should match"); + Assert.assertEquals(userConfig.getPassword(), TEST_PASSWORD, "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.BROKER, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.USER, "Role type should match"); + Assert.assertNull(userConfig.getTables(), "Tables should be null when not set"); + Assert.assertNull(userConfig.getExcludeTables(), "Exclude tables should be null when not set"); + Assert.assertNull(userConfig.getPermissios(), "Permissions should be null when not set"); + Assert.assertNull(userConfig.getRlsFilters(), "RLS filters should be null when not set"); + } + + @Test + public void testUserConfigWithTableList() { + List<String> tableList = Arrays.asList("table1", "table2", "table3"); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.CONTROLLER) + .setRoleType(RoleType.ADMIN) + .setTableList(tableList) + .build(); + + Assert.assertNotNull(userConfig.getTables(), "Tables should not be null"); + Assert.assertEquals(userConfig.getTables(), tableList, "Table list should match"); + Assert.assertEquals(userConfig.getTables().size(), 3, "Table list size should be 3"); + } + + @Test + public void testUserConfigWithExcludeTableList() { + List<String> excludeTableList = Arrays.asList("excludeTable1", "excludeTable2"); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.SERVER) + .setRoleType(RoleType.USER) + .setExcludeTableList(excludeTableList) + .build(); + + Assert.assertNotNull(userConfig.getExcludeTables(), "Exclude tables should not be null"); + Assert.assertEquals(userConfig.getExcludeTables(), excludeTableList, "Exclude table list should match"); + Assert.assertEquals(userConfig.getExcludeTables().size(), 2, "Exclude table list size should be 2"); + } + + @Test + public void testUserConfigWithPermissionList() { + List<AccessType> permissionList = Arrays.asList(AccessType.READ, AccessType.CREATE, AccessType.UPDATE); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.MINION) + .setRoleType(RoleType.ADMIN) + .setPermissionList(permissionList) + .build(); + + Assert.assertNotNull(userConfig.getPermissios(), "Permissions should not be null"); + Assert.assertEquals(userConfig.getPermissios(), permissionList, "Permission list should match"); + Assert.assertEquals(userConfig.getPermissios().size(), 3, "Permission list size should be 3"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.READ), "Should contain READ permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.CREATE), "Should contain CREATE permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.UPDATE), "Should contain UPDATE permission"); Review Comment: Multiple occurrences of 'getPermissios' should be corrected to 'getPermissions'. ```suggestion Assert.assertNotNull(userConfig.getPermissions(), "Permissions should not be null"); Assert.assertEquals(userConfig.getPermissions(), permissionList, "Permission list should match"); Assert.assertEquals(userConfig.getPermissions().size(), 3, "Permission list size should be 3"); Assert.assertTrue(userConfig.getPermissions().contains(AccessType.READ), "Should contain READ permission"); Assert.assertTrue(userConfig.getPermissions().contains(AccessType.CREATE), "Should contain CREATE permission"); Assert.assertTrue(userConfig.getPermissions().contains(AccessType.UPDATE), "Should contain UPDATE permission"); ``` ########## pinot-common/src/test/java/org/apache/pinot/common/utils/config/AccessControlUserConfigUtilsTest.java: ########## @@ -0,0 +1,559 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.pinot.common.utils.config; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.helix.zookeeper.datamodel.ZNRecord; +import org.apache.pinot.spi.config.user.AccessType; +import org.apache.pinot.spi.config.user.ComponentType; +import org.apache.pinot.spi.config.user.RoleType; +import org.apache.pinot.spi.config.user.UserConfig; +import org.apache.pinot.spi.utils.JsonUtils; +import org.apache.pinot.spi.utils.builder.UserConfigBuilder; +import org.testng.Assert; +import org.testng.annotations.Test; + + +/** + * Tests for {@link AccessControlUserConfigUtils} + */ +public class AccessControlUserConfigUtilsTest { + + private static final String TEST_USERNAME = "testUser"; + private static final String TEST_PASSWORD = "testPassword"; + + @Test + public void testFromZNRecordWithMandatoryFieldsOnly() { + // Create ZNRecord with only mandatory fields + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.BROKER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + znRecord.setSimpleFields(simpleFields); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), TEST_USERNAME, "Username should match"); + Assert.assertEquals(userConfig.getPassword(), TEST_PASSWORD, "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.BROKER, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.USER, "Role type should match"); + Assert.assertNull(userConfig.getTables(), "Tables should be null"); + Assert.assertNull(userConfig.getExcludeTables(), "Exclude tables should be null"); + Assert.assertNull(userConfig.getPermissios(), "Permissions should be null"); + Assert.assertNull(userConfig.getRlsFilters(), "RLS filters should be null"); + } + + @Test + public void testFromZNRecordWithTableList() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.CONTROLLER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.ADMIN.toString()); + znRecord.setSimpleFields(simpleFields); + + List<String> tableList = Arrays.asList("table1", "table2", "table3"); + znRecord.setListField(UserConfig.TABLES_KEY, tableList); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getTables(), "Tables should not be null"); + Assert.assertEquals(userConfig.getTables(), tableList, "Table list should match"); + Assert.assertEquals(userConfig.getTables().size(), 3, "Table list size should be 3"); + } + + @Test + public void testFromZNRecordWithExcludeTableList() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.SERVER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + znRecord.setSimpleFields(simpleFields); + + List<String> excludeTableList = Arrays.asList("excludeTable1", "excludeTable2"); + znRecord.setListField(UserConfig.EXCLUDE_TABLES_KEY, excludeTableList); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getExcludeTables(), "Exclude tables should not be null"); + Assert.assertEquals(userConfig.getExcludeTables(), excludeTableList, "Exclude table list should match"); + Assert.assertEquals(userConfig.getExcludeTables().size(), 2, "Exclude table list size should be 2"); + } + + @Test + public void testFromZNRecordWithPermissionList() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.MINION.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.ADMIN.toString()); + znRecord.setSimpleFields(simpleFields); + + List<String> permissionListStr = Arrays.asList("READ", "CREATE", "UPDATE"); + znRecord.setListField(UserConfig.PERMISSIONS_KEY, permissionListStr); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getPermissios(), "Permissions should not be null"); + Assert.assertEquals(userConfig.getPermissios().size(), 3, "Permission list size should be 3"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.READ), "Should contain READ permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.CREATE), "Should contain CREATE permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.UPDATE), "Should contain UPDATE permission"); Review Comment: Multiple occurrences of 'getPermissios' should be corrected to 'getPermissions'. ```suggestion Assert.assertNotNull(userConfig.getPermissions(), "Permissions should not be null"); Assert.assertEquals(userConfig.getPermissions().size(), 3, "Permission list size should be 3"); Assert.assertTrue(userConfig.getPermissions().contains(AccessType.READ), "Should contain READ permission"); Assert.assertTrue(userConfig.getPermissions().contains(AccessType.CREATE), "Should contain CREATE permission"); Assert.assertTrue(userConfig.getPermissions().contains(AccessType.UPDATE), "Should contain UPDATE permission"); ``` ########## pinot-common/src/test/java/org/apache/pinot/common/utils/config/AccessControlUserConfigUtilsTest.java: ########## @@ -0,0 +1,559 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.pinot.common.utils.config; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.helix.zookeeper.datamodel.ZNRecord; +import org.apache.pinot.spi.config.user.AccessType; +import org.apache.pinot.spi.config.user.ComponentType; +import org.apache.pinot.spi.config.user.RoleType; +import org.apache.pinot.spi.config.user.UserConfig; +import org.apache.pinot.spi.utils.JsonUtils; +import org.apache.pinot.spi.utils.builder.UserConfigBuilder; +import org.testng.Assert; +import org.testng.annotations.Test; + + +/** + * Tests for {@link AccessControlUserConfigUtils} + */ +public class AccessControlUserConfigUtilsTest { + + private static final String TEST_USERNAME = "testUser"; + private static final String TEST_PASSWORD = "testPassword"; + + @Test + public void testFromZNRecordWithMandatoryFieldsOnly() { + // Create ZNRecord with only mandatory fields + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.BROKER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + znRecord.setSimpleFields(simpleFields); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), TEST_USERNAME, "Username should match"); + Assert.assertEquals(userConfig.getPassword(), TEST_PASSWORD, "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.BROKER, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.USER, "Role type should match"); + Assert.assertNull(userConfig.getTables(), "Tables should be null"); + Assert.assertNull(userConfig.getExcludeTables(), "Exclude tables should be null"); + Assert.assertNull(userConfig.getPermissios(), "Permissions should be null"); Review Comment: Corrected spelling of 'getPermissios' to 'getPermissions'. ```suggestion Assert.assertNull(userConfig.getPermissions(), "Permissions should be null"); ``` ########## pinot-spi/src/test/java/org/apache/pinot/spi/utils/builder/UserConfigBuilderTest.java: ########## @@ -0,0 +1,261 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.pinot.spi.utils.builder; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.pinot.spi.config.user.AccessType; +import org.apache.pinot.spi.config.user.ComponentType; +import org.apache.pinot.spi.config.user.RoleType; +import org.apache.pinot.spi.config.user.UserConfig; +import org.testng.Assert; +import org.testng.annotations.Test; + + +/** + * Tests for {@link UserConfigBuilder} + */ +public class UserConfigBuilderTest { + + private static final String TEST_USERNAME = "testUser"; + private static final String TEST_PASSWORD = "testPassword"; + + @Test + public void testBasicUserConfigBuild() { + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.USER) + .build(); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), TEST_USERNAME, "Username should match"); + Assert.assertEquals(userConfig.getPassword(), TEST_PASSWORD, "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.BROKER, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.USER, "Role type should match"); + Assert.assertNull(userConfig.getTables(), "Tables should be null when not set"); + Assert.assertNull(userConfig.getExcludeTables(), "Exclude tables should be null when not set"); + Assert.assertNull(userConfig.getPermissios(), "Permissions should be null when not set"); + Assert.assertNull(userConfig.getRlsFilters(), "RLS filters should be null when not set"); + } + + @Test + public void testUserConfigWithTableList() { + List<String> tableList = Arrays.asList("table1", "table2", "table3"); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.CONTROLLER) + .setRoleType(RoleType.ADMIN) + .setTableList(tableList) + .build(); + + Assert.assertNotNull(userConfig.getTables(), "Tables should not be null"); + Assert.assertEquals(userConfig.getTables(), tableList, "Table list should match"); + Assert.assertEquals(userConfig.getTables().size(), 3, "Table list size should be 3"); + } + + @Test + public void testUserConfigWithExcludeTableList() { + List<String> excludeTableList = Arrays.asList("excludeTable1", "excludeTable2"); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.SERVER) + .setRoleType(RoleType.USER) + .setExcludeTableList(excludeTableList) + .build(); + + Assert.assertNotNull(userConfig.getExcludeTables(), "Exclude tables should not be null"); + Assert.assertEquals(userConfig.getExcludeTables(), excludeTableList, "Exclude table list should match"); + Assert.assertEquals(userConfig.getExcludeTables().size(), 2, "Exclude table list size should be 2"); + } + + @Test + public void testUserConfigWithPermissionList() { + List<AccessType> permissionList = Arrays.asList(AccessType.READ, AccessType.CREATE, AccessType.UPDATE); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.MINION) + .setRoleType(RoleType.ADMIN) + .setPermissionList(permissionList) + .build(); + + Assert.assertNotNull(userConfig.getPermissios(), "Permissions should not be null"); + Assert.assertEquals(userConfig.getPermissios(), permissionList, "Permission list should match"); + Assert.assertEquals(userConfig.getPermissios().size(), 3, "Permission list size should be 3"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.READ), "Should contain READ permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.CREATE), "Should contain CREATE permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.UPDATE), "Should contain UPDATE permission"); + } + + @Test + public void testUserConfigWithRlsFilters() { + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("filter1", "filter2")); + rlsFilters.put("table2", Arrays.asList("filter3")); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.PROXY) + .setRoleType(RoleType.USER) + .setRlsFilters(rlsFilters) + .build(); + + Assert.assertNotNull(userConfig.getRlsFilters(), "RLS filters should not be null"); + Assert.assertEquals(userConfig.getRlsFilters(), rlsFilters, "RLS filters should match"); + Assert.assertEquals(userConfig.getRlsFilters().size(), 2, "RLS filters map size should be 2"); + Assert.assertTrue(userConfig.getRlsFilters().containsKey("table1"), "Should contain table1 filters"); + Assert.assertTrue(userConfig.getRlsFilters().containsKey("table2"), "Should contain table2 filters"); + Assert.assertEquals(userConfig.getRlsFilters().get("table1").size(), 2, "table1 should have 2 filters"); + Assert.assertEquals(userConfig.getRlsFilters().get("table2").size(), 1, "table2 should have 1 filter"); + } + + @Test + public void testUserConfigWithAllFields() { + List<String> tableList = Arrays.asList("table1", "table2"); + List<String> excludeTableList = Arrays.asList("excludeTable1"); + List<AccessType> permissionList = Arrays.asList(AccessType.READ, AccessType.UPDATE, AccessType.DELETE); + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("country='US'", "department='Engineering'")); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername("adminUser") + .setPassword("adminPass123") + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.ADMIN) + .setTableList(tableList) + .setExcludeTableList(excludeTableList) + .setPermissionList(permissionList) + .setRlsFilters(rlsFilters) + .build(); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), "adminUser", "Username should match"); + Assert.assertEquals(userConfig.getPassword(), "adminPass123", "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.BROKER, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.ADMIN, "Role type should match"); + Assert.assertEquals(userConfig.getTables(), tableList, "Table list should match"); + Assert.assertEquals(userConfig.getExcludeTables(), excludeTableList, "Exclude table list should match"); + Assert.assertEquals(userConfig.getPermissios(), permissionList, "Permission list should match"); + Assert.assertEquals(userConfig.getRlsFilters(), rlsFilters, "RLS filters should match"); + } + + @Test + public void testBuilderChaining() { + UserConfigBuilder builder = new UserConfigBuilder(); + + // Verify that each setter returns the builder instance for chaining + UserConfigBuilder result1 = builder.setUsername(TEST_USERNAME); + Assert.assertSame(result1, builder, "setUsername should return the builder instance"); + + UserConfigBuilder result2 = builder.setPassword(TEST_PASSWORD); + Assert.assertSame(result2, builder, "setPassword should return the builder instance"); + + UserConfigBuilder result3 = builder.setComponentType(ComponentType.BROKER); + Assert.assertSame(result3, builder, "setComponentType should return the builder instance"); + + UserConfigBuilder result4 = builder.setRoleType(RoleType.USER); + Assert.assertSame(result4, builder, "setRoleType should return the builder instance"); + + UserConfigBuilder result5 = builder.setTableList(Arrays.asList("table1")); + Assert.assertSame(result5, builder, "setTableList should return the builder instance"); + + UserConfigBuilder result6 = builder.setExcludeTableList(Arrays.asList("excludeTable1")); + Assert.assertSame(result6, builder, "setExcludeTableList should return the builder instance"); + + UserConfigBuilder result7 = builder.setPermissionList(Arrays.asList(AccessType.READ)); + Assert.assertSame(result7, builder, "setPermissionList should return the builder instance"); + + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("filter1")); + UserConfigBuilder result8 = builder.setRlsFilters(rlsFilters); + Assert.assertSame(result8, builder, "setRlsFilters should return the builder instance"); + } + + @Test + public void testMultipleComponentTypes() { + // Test with different component types + ComponentType[] componentTypes = { + ComponentType.CONTROLLER, ComponentType.BROKER, ComponentType.SERVER, + ComponentType.MINION, ComponentType.PROXY + }; + + for (ComponentType componentType : componentTypes) { + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(componentType) + .setRoleType(RoleType.USER) + .build(); + + Assert.assertEquals(userConfig.getComponentType(), componentType, + "Component type should match for " + componentType); + } + } + + @Test + public void testMultipleRoleTypes() { + // Test with different role types + RoleType[] roleTypes = {RoleType.ADMIN, RoleType.USER}; + + for (RoleType roleType : roleTypes) { + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(roleType) + .build(); + + Assert.assertEquals(userConfig.getRoleType(), roleType, + "Role type should match for " + roleType); + } + } + + @Test + public void testAllAccessTypes() { + // Test with all access types + List<AccessType> allPermissions = Arrays.asList( + AccessType.CREATE, AccessType.READ, AccessType.UPDATE, AccessType.DELETE + ); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.ADMIN) + .setPermissionList(allPermissions) + .build(); + + Assert.assertEquals(userConfig.getPermissios().size(), 4, "Should have all 4 access types"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.CREATE), "Should contain CREATE"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.READ), "Should contain READ"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.UPDATE), "Should contain UPDATE"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.DELETE), "Should contain DELETE"); Review Comment: Multiple occurrences of 'getPermissios' should be corrected to 'getPermissions'. ```suggestion Assert.assertEquals(userConfig.getPermissions().size(), 4, "Should have all 4 access types"); Assert.assertTrue(userConfig.getPermissions().contains(AccessType.CREATE), "Should contain CREATE"); Assert.assertTrue(userConfig.getPermissions().contains(AccessType.READ), "Should contain READ"); Assert.assertTrue(userConfig.getPermissions().contains(AccessType.UPDATE), "Should contain UPDATE"); Assert.assertTrue(userConfig.getPermissions().contains(AccessType.DELETE), "Should contain DELETE"); ``` ########## pinot-common/src/test/java/org/apache/pinot/common/utils/config/AccessControlUserConfigUtilsTest.java: ########## @@ -0,0 +1,559 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.pinot.common.utils.config; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.helix.zookeeper.datamodel.ZNRecord; +import org.apache.pinot.spi.config.user.AccessType; +import org.apache.pinot.spi.config.user.ComponentType; +import org.apache.pinot.spi.config.user.RoleType; +import org.apache.pinot.spi.config.user.UserConfig; +import org.apache.pinot.spi.utils.JsonUtils; +import org.apache.pinot.spi.utils.builder.UserConfigBuilder; +import org.testng.Assert; +import org.testng.annotations.Test; + + +/** + * Tests for {@link AccessControlUserConfigUtils} + */ +public class AccessControlUserConfigUtilsTest { + + private static final String TEST_USERNAME = "testUser"; + private static final String TEST_PASSWORD = "testPassword"; + + @Test + public void testFromZNRecordWithMandatoryFieldsOnly() { + // Create ZNRecord with only mandatory fields + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.BROKER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + znRecord.setSimpleFields(simpleFields); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), TEST_USERNAME, "Username should match"); + Assert.assertEquals(userConfig.getPassword(), TEST_PASSWORD, "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.BROKER, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.USER, "Role type should match"); + Assert.assertNull(userConfig.getTables(), "Tables should be null"); + Assert.assertNull(userConfig.getExcludeTables(), "Exclude tables should be null"); + Assert.assertNull(userConfig.getPermissios(), "Permissions should be null"); + Assert.assertNull(userConfig.getRlsFilters(), "RLS filters should be null"); + } + + @Test + public void testFromZNRecordWithTableList() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.CONTROLLER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.ADMIN.toString()); + znRecord.setSimpleFields(simpleFields); + + List<String> tableList = Arrays.asList("table1", "table2", "table3"); + znRecord.setListField(UserConfig.TABLES_KEY, tableList); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getTables(), "Tables should not be null"); + Assert.assertEquals(userConfig.getTables(), tableList, "Table list should match"); + Assert.assertEquals(userConfig.getTables().size(), 3, "Table list size should be 3"); + } + + @Test + public void testFromZNRecordWithExcludeTableList() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.SERVER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + znRecord.setSimpleFields(simpleFields); + + List<String> excludeTableList = Arrays.asList("excludeTable1", "excludeTable2"); + znRecord.setListField(UserConfig.EXCLUDE_TABLES_KEY, excludeTableList); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getExcludeTables(), "Exclude tables should not be null"); + Assert.assertEquals(userConfig.getExcludeTables(), excludeTableList, "Exclude table list should match"); + Assert.assertEquals(userConfig.getExcludeTables().size(), 2, "Exclude table list size should be 2"); + } + + @Test + public void testFromZNRecordWithPermissionList() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.MINION.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.ADMIN.toString()); + znRecord.setSimpleFields(simpleFields); + + List<String> permissionListStr = Arrays.asList("READ", "CREATE", "UPDATE"); + znRecord.setListField(UserConfig.PERMISSIONS_KEY, permissionListStr); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getPermissios(), "Permissions should not be null"); + Assert.assertEquals(userConfig.getPermissios().size(), 3, "Permission list size should be 3"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.READ), "Should contain READ permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.CREATE), "Should contain CREATE permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.UPDATE), "Should contain UPDATE permission"); + } + + @Test + public void testFromZNRecordWithRlsFilters() throws JsonProcessingException { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.BROKER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("country='US'", "department='Engineering'")); + rlsFilters.put("table2", Arrays.asList("region='WEST'")); + simpleFields.put(UserConfig.RLS_FILTERS_KEY, JsonUtils.objectToString(rlsFilters)); + + znRecord.setSimpleFields(simpleFields); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getRlsFilters(), "RLS filters should not be null"); + Assert.assertEquals(userConfig.getRlsFilters().size(), 2, "RLS filters map size should be 2"); + Assert.assertTrue(userConfig.getRlsFilters().containsKey("table1"), "Should contain table1 filters"); + Assert.assertTrue(userConfig.getRlsFilters().containsKey("table2"), "Should contain table2 filters"); + Assert.assertEquals(userConfig.getRlsFilters().get("table1").size(), 2, "table1 should have 2 filters"); + Assert.assertEquals(userConfig.getRlsFilters().get("table2").size(), 1, "table2 should have 1 filter"); + // Verify actual filter values + Assert.assertEquals(userConfig.getRlsFilters().get("table1").get(0), "country='US'"); + Assert.assertEquals(userConfig.getRlsFilters().get("table1").get(1), "department='Engineering'"); + Assert.assertEquals(userConfig.getRlsFilters().get("table2").get(0), "region='WEST'"); + } + + @Test + public void testFromZNRecordWithMalformedRlsFilters() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.BROKER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + simpleFields.put(UserConfig.RLS_FILTERS_KEY, "invalid-json-{malformed"); + znRecord.setSimpleFields(simpleFields); + + // Should not throw exception, but log error and continue + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertNull(userConfig.getRlsFilters(), "RLS filters should be null due to malformed JSON"); + } + + @Test + public void testFromZNRecordWithAllFields() throws JsonProcessingException { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, "adminUser"); + simpleFields.put(UserConfig.PASSWORD_KEY, "adminPass123"); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.PROXY.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.ADMIN.toString()); + + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("filter1", "filter2")); + simpleFields.put(UserConfig.RLS_FILTERS_KEY, JsonUtils.objectToString(rlsFilters)); + znRecord.setSimpleFields(simpleFields); + + List<String> tableList = Arrays.asList("table1", "table2"); + List<String> excludeTableList = Arrays.asList("excludeTable1"); + List<String> permissionListStr = Arrays.asList("READ", "UPDATE", "DELETE"); + + znRecord.setListField(UserConfig.TABLES_KEY, tableList); + znRecord.setListField(UserConfig.EXCLUDE_TABLES_KEY, excludeTableList); + znRecord.setListField(UserConfig.PERMISSIONS_KEY, permissionListStr); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), "adminUser", "Username should match"); + Assert.assertEquals(userConfig.getPassword(), "adminPass123", "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.PROXY, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.ADMIN, "Role type should match"); + Assert.assertEquals(userConfig.getTables(), tableList, "Table list should match"); + Assert.assertEquals(userConfig.getExcludeTables(), excludeTableList, "Exclude table list should match"); + Assert.assertEquals(userConfig.getPermissios().size(), 3, "Permission list size should match"); + Assert.assertNotNull(userConfig.getRlsFilters(), "RLS filters should not be null"); + } + + @Test + public void testToZNRecordWithMandatoryFieldsOnly() throws JsonProcessingException { + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.USER) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + + Assert.assertNotNull(znRecord, "ZNRecord should not be null"); + Assert.assertEquals(znRecord.getId(), TEST_USERNAME, "ZNRecord ID should match username"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.USERNAME_KEY), TEST_USERNAME, "Username should match"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.PASSWORD_KEY), TEST_PASSWORD, "Password should match"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.COMPONET_KEY), ComponentType.BROKER.toString(), + "Component type should match"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.ROLE_KEY), RoleType.USER.toString(), + "Role type should match"); + Assert.assertNull(znRecord.getListField(UserConfig.TABLES_KEY), "Tables should be null"); + Assert.assertNull(znRecord.getListField(UserConfig.EXCLUDE_TABLES_KEY), "Exclude tables should be null"); + Assert.assertNull(znRecord.getListField(UserConfig.PERMISSIONS_KEY), "Permissions should be null"); + Assert.assertNull(znRecord.getSimpleField(UserConfig.RLS_FILTERS_KEY), "RLS filters should be null"); + } + + @Test + public void testToZNRecordWithTableList() throws JsonProcessingException { + List<String> tableList = Arrays.asList("table1", "table2", "table3"); + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.CONTROLLER) + .setRoleType(RoleType.ADMIN) + .setTableList(tableList) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + + Assert.assertNotNull(znRecord.getListField(UserConfig.TABLES_KEY), "Tables should not be null"); + Assert.assertEquals(znRecord.getListField(UserConfig.TABLES_KEY), tableList, "Table list should match"); + Assert.assertEquals(znRecord.getListField(UserConfig.TABLES_KEY).size(), 3, "Table list size should be 3"); + } + + @Test + public void testToZNRecordWithExcludeTableList() throws JsonProcessingException { + List<String> excludeTableList = Arrays.asList("excludeTable1", "excludeTable2"); + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.SERVER) + .setRoleType(RoleType.USER) + .setExcludeTableList(excludeTableList) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + + Assert.assertNotNull(znRecord.getListField(UserConfig.EXCLUDE_TABLES_KEY), "Exclude tables should not be null"); + Assert.assertEquals(znRecord.getListField(UserConfig.EXCLUDE_TABLES_KEY), excludeTableList, + "Exclude table list should match"); + Assert.assertEquals(znRecord.getListField(UserConfig.EXCLUDE_TABLES_KEY).size(), 2, + "Exclude table list size should be 2"); + } + + @Test + public void testToZNRecordWithPermissionList() throws JsonProcessingException { + List<AccessType> permissionList = Arrays.asList(AccessType.READ, AccessType.CREATE, AccessType.UPDATE); + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.MINION) + .setRoleType(RoleType.ADMIN) + .setPermissionList(permissionList) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + + List<String> permissionListStr = znRecord.getListField(UserConfig.PERMISSIONS_KEY); + Assert.assertNotNull(permissionListStr, "Permissions should not be null"); + Assert.assertEquals(permissionListStr.size(), 3, "Permission list size should be 3"); + Assert.assertTrue(permissionListStr.contains("READ"), "Should contain READ permission"); + Assert.assertTrue(permissionListStr.contains("CREATE"), "Should contain CREATE permission"); + Assert.assertTrue(permissionListStr.contains("UPDATE"), "Should contain UPDATE permission"); + } + + @Test + public void testToZNRecordWithRlsFilters() throws IOException { + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("country='US'", "department='Engineering'")); + rlsFilters.put("table2", Arrays.asList("region='WEST'")); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.USER) + .setRlsFilters(rlsFilters) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + + String rlsFiltersJson = znRecord.getSimpleField(UserConfig.RLS_FILTERS_KEY); + Assert.assertNotNull(rlsFiltersJson, "RLS filters should not be null"); + + // Deserialize and verify + Map<String, List<String>> deserializedFilters = JsonUtils.stringToObject( + rlsFiltersJson, new com.fasterxml.jackson.core.type.TypeReference<Map<String, List<String>>>() { + } + ); + Assert.assertEquals(deserializedFilters.size(), 2, "RLS filters map size should be 2"); + Assert.assertTrue(deserializedFilters.containsKey("table1"), "Should contain table1 filters"); + Assert.assertTrue(deserializedFilters.containsKey("table2"), "Should contain table2 filters"); + // Verify actual filter values + Assert.assertEquals(deserializedFilters.get("table1").get(0), "country='US'"); + Assert.assertEquals(deserializedFilters.get("table1").get(1), "department='Engineering'"); + Assert.assertEquals(deserializedFilters.get("table2").get(0), "region='WEST'"); + } + + @Test + public void testToZNRecordWithAllFields() throws JsonProcessingException { + List<String> tableList = Arrays.asList("table1", "table2"); + List<String> excludeTableList = Arrays.asList("excludeTable1"); + List<AccessType> permissionList = Arrays.asList(AccessType.READ, AccessType.UPDATE, AccessType.DELETE); + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("filter1", "filter2")); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername("adminUser") + .setPassword("adminPass123") + .setComponentType(ComponentType.PROXY) + .setRoleType(RoleType.ADMIN) + .setTableList(tableList) + .setExcludeTableList(excludeTableList) + .setPermissionList(permissionList) + .setRlsFilters(rlsFilters) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + + Assert.assertNotNull(znRecord, "ZNRecord should not be null"); + Assert.assertEquals(znRecord.getId(), "adminUser", "ZNRecord ID should match username"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.USERNAME_KEY), "adminUser", "Username should match"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.PASSWORD_KEY), "adminPass123", "Password should match"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.COMPONET_KEY), ComponentType.PROXY.toString(), + "Component type should match"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.ROLE_KEY), RoleType.ADMIN.toString(), + "Role type should match"); + Assert.assertEquals(znRecord.getListField(UserConfig.TABLES_KEY), tableList, "Table list should match"); + Assert.assertEquals(znRecord.getListField(UserConfig.EXCLUDE_TABLES_KEY), excludeTableList, + "Exclude table list should match"); + Assert.assertNotNull(znRecord.getListField(UserConfig.PERMISSIONS_KEY), "Permissions should not be null"); + Assert.assertNotNull(znRecord.getSimpleField(UserConfig.RLS_FILTERS_KEY), "RLS filters should not be null"); + } + + @Test + public void testRoundTripConversionWithMandatoryFields() throws JsonProcessingException { + UserConfig originalConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.USER) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(originalConfig); + UserConfig reconstructedConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertEquals(reconstructedConfig.getUserName(), originalConfig.getUserName(), + "Username should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getPassword(), originalConfig.getPassword(), + "Password should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getComponentType(), originalConfig.getComponentType(), + "Component type should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getRoleType(), originalConfig.getRoleType(), + "Role type should match after round-trip"); + } + + @Test + public void testRoundTripConversionWithAllFields() throws JsonProcessingException { + List<String> tableList = Arrays.asList("table1", "table2"); + List<String> excludeTableList = Arrays.asList("excludeTable1"); + List<AccessType> permissionList = Arrays.asList(AccessType.CREATE, AccessType.READ, AccessType.UPDATE, + AccessType.DELETE); + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("country='US'", "department='Engineering'")); + rlsFilters.put("table2", Arrays.asList("region='WEST'")); + + UserConfig originalConfig = new UserConfigBuilder() + .setUsername("fullTestUser") + .setPassword("fullTestPassword") + .setComponentType(ComponentType.CONTROLLER) + .setRoleType(RoleType.ADMIN) + .setTableList(tableList) + .setExcludeTableList(excludeTableList) + .setPermissionList(permissionList) + .setRlsFilters(rlsFilters) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(originalConfig); + UserConfig reconstructedConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertEquals(reconstructedConfig.getUserName(), originalConfig.getUserName(), + "Username should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getPassword(), originalConfig.getPassword(), + "Password should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getComponentType(), originalConfig.getComponentType(), + "Component type should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getRoleType(), originalConfig.getRoleType(), + "Role type should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getTables(), originalConfig.getTables(), + "Tables should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getExcludeTables(), originalConfig.getExcludeTables(), + "Exclude tables should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getPermissios().size(), originalConfig.getPermissios().size(), Review Comment: Multiple occurrences of 'getPermissios' should be corrected to 'getPermissions'. ```suggestion Assert.assertEquals(reconstructedConfig.getPermissions().size(), originalConfig.getPermissions().size(), ``` ########## pinot-common/src/test/java/org/apache/pinot/common/utils/config/AccessControlUserConfigUtilsTest.java: ########## @@ -0,0 +1,559 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.pinot.common.utils.config; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.helix.zookeeper.datamodel.ZNRecord; +import org.apache.pinot.spi.config.user.AccessType; +import org.apache.pinot.spi.config.user.ComponentType; +import org.apache.pinot.spi.config.user.RoleType; +import org.apache.pinot.spi.config.user.UserConfig; +import org.apache.pinot.spi.utils.JsonUtils; +import org.apache.pinot.spi.utils.builder.UserConfigBuilder; +import org.testng.Assert; +import org.testng.annotations.Test; + + +/** + * Tests for {@link AccessControlUserConfigUtils} + */ +public class AccessControlUserConfigUtilsTest { + + private static final String TEST_USERNAME = "testUser"; + private static final String TEST_PASSWORD = "testPassword"; + + @Test + public void testFromZNRecordWithMandatoryFieldsOnly() { + // Create ZNRecord with only mandatory fields + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.BROKER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + znRecord.setSimpleFields(simpleFields); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), TEST_USERNAME, "Username should match"); + Assert.assertEquals(userConfig.getPassword(), TEST_PASSWORD, "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.BROKER, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.USER, "Role type should match"); + Assert.assertNull(userConfig.getTables(), "Tables should be null"); + Assert.assertNull(userConfig.getExcludeTables(), "Exclude tables should be null"); + Assert.assertNull(userConfig.getPermissios(), "Permissions should be null"); + Assert.assertNull(userConfig.getRlsFilters(), "RLS filters should be null"); + } + + @Test + public void testFromZNRecordWithTableList() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.CONTROLLER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.ADMIN.toString()); + znRecord.setSimpleFields(simpleFields); + + List<String> tableList = Arrays.asList("table1", "table2", "table3"); + znRecord.setListField(UserConfig.TABLES_KEY, tableList); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getTables(), "Tables should not be null"); + Assert.assertEquals(userConfig.getTables(), tableList, "Table list should match"); + Assert.assertEquals(userConfig.getTables().size(), 3, "Table list size should be 3"); + } + + @Test + public void testFromZNRecordWithExcludeTableList() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.SERVER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + znRecord.setSimpleFields(simpleFields); + + List<String> excludeTableList = Arrays.asList("excludeTable1", "excludeTable2"); + znRecord.setListField(UserConfig.EXCLUDE_TABLES_KEY, excludeTableList); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getExcludeTables(), "Exclude tables should not be null"); + Assert.assertEquals(userConfig.getExcludeTables(), excludeTableList, "Exclude table list should match"); + Assert.assertEquals(userConfig.getExcludeTables().size(), 2, "Exclude table list size should be 2"); + } + + @Test + public void testFromZNRecordWithPermissionList() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.MINION.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.ADMIN.toString()); + znRecord.setSimpleFields(simpleFields); + + List<String> permissionListStr = Arrays.asList("READ", "CREATE", "UPDATE"); + znRecord.setListField(UserConfig.PERMISSIONS_KEY, permissionListStr); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getPermissios(), "Permissions should not be null"); + Assert.assertEquals(userConfig.getPermissios().size(), 3, "Permission list size should be 3"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.READ), "Should contain READ permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.CREATE), "Should contain CREATE permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.UPDATE), "Should contain UPDATE permission"); + } + + @Test + public void testFromZNRecordWithRlsFilters() throws JsonProcessingException { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.BROKER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("country='US'", "department='Engineering'")); + rlsFilters.put("table2", Arrays.asList("region='WEST'")); + simpleFields.put(UserConfig.RLS_FILTERS_KEY, JsonUtils.objectToString(rlsFilters)); + + znRecord.setSimpleFields(simpleFields); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getRlsFilters(), "RLS filters should not be null"); + Assert.assertEquals(userConfig.getRlsFilters().size(), 2, "RLS filters map size should be 2"); + Assert.assertTrue(userConfig.getRlsFilters().containsKey("table1"), "Should contain table1 filters"); + Assert.assertTrue(userConfig.getRlsFilters().containsKey("table2"), "Should contain table2 filters"); + Assert.assertEquals(userConfig.getRlsFilters().get("table1").size(), 2, "table1 should have 2 filters"); + Assert.assertEquals(userConfig.getRlsFilters().get("table2").size(), 1, "table2 should have 1 filter"); + // Verify actual filter values + Assert.assertEquals(userConfig.getRlsFilters().get("table1").get(0), "country='US'"); + Assert.assertEquals(userConfig.getRlsFilters().get("table1").get(1), "department='Engineering'"); + Assert.assertEquals(userConfig.getRlsFilters().get("table2").get(0), "region='WEST'"); + } + + @Test + public void testFromZNRecordWithMalformedRlsFilters() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.BROKER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + simpleFields.put(UserConfig.RLS_FILTERS_KEY, "invalid-json-{malformed"); + znRecord.setSimpleFields(simpleFields); + + // Should not throw exception, but log error and continue + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertNull(userConfig.getRlsFilters(), "RLS filters should be null due to malformed JSON"); + } + + @Test + public void testFromZNRecordWithAllFields() throws JsonProcessingException { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, "adminUser"); + simpleFields.put(UserConfig.PASSWORD_KEY, "adminPass123"); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.PROXY.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.ADMIN.toString()); + + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("filter1", "filter2")); + simpleFields.put(UserConfig.RLS_FILTERS_KEY, JsonUtils.objectToString(rlsFilters)); + znRecord.setSimpleFields(simpleFields); + + List<String> tableList = Arrays.asList("table1", "table2"); + List<String> excludeTableList = Arrays.asList("excludeTable1"); + List<String> permissionListStr = Arrays.asList("READ", "UPDATE", "DELETE"); + + znRecord.setListField(UserConfig.TABLES_KEY, tableList); + znRecord.setListField(UserConfig.EXCLUDE_TABLES_KEY, excludeTableList); + znRecord.setListField(UserConfig.PERMISSIONS_KEY, permissionListStr); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), "adminUser", "Username should match"); + Assert.assertEquals(userConfig.getPassword(), "adminPass123", "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.PROXY, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.ADMIN, "Role type should match"); + Assert.assertEquals(userConfig.getTables(), tableList, "Table list should match"); + Assert.assertEquals(userConfig.getExcludeTables(), excludeTableList, "Exclude table list should match"); + Assert.assertEquals(userConfig.getPermissios().size(), 3, "Permission list size should match"); + Assert.assertNotNull(userConfig.getRlsFilters(), "RLS filters should not be null"); + } + + @Test + public void testToZNRecordWithMandatoryFieldsOnly() throws JsonProcessingException { + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.USER) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + + Assert.assertNotNull(znRecord, "ZNRecord should not be null"); + Assert.assertEquals(znRecord.getId(), TEST_USERNAME, "ZNRecord ID should match username"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.USERNAME_KEY), TEST_USERNAME, "Username should match"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.PASSWORD_KEY), TEST_PASSWORD, "Password should match"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.COMPONET_KEY), ComponentType.BROKER.toString(), + "Component type should match"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.ROLE_KEY), RoleType.USER.toString(), + "Role type should match"); + Assert.assertNull(znRecord.getListField(UserConfig.TABLES_KEY), "Tables should be null"); + Assert.assertNull(znRecord.getListField(UserConfig.EXCLUDE_TABLES_KEY), "Exclude tables should be null"); + Assert.assertNull(znRecord.getListField(UserConfig.PERMISSIONS_KEY), "Permissions should be null"); + Assert.assertNull(znRecord.getSimpleField(UserConfig.RLS_FILTERS_KEY), "RLS filters should be null"); + } + + @Test + public void testToZNRecordWithTableList() throws JsonProcessingException { + List<String> tableList = Arrays.asList("table1", "table2", "table3"); + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.CONTROLLER) + .setRoleType(RoleType.ADMIN) + .setTableList(tableList) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + + Assert.assertNotNull(znRecord.getListField(UserConfig.TABLES_KEY), "Tables should not be null"); + Assert.assertEquals(znRecord.getListField(UserConfig.TABLES_KEY), tableList, "Table list should match"); + Assert.assertEquals(znRecord.getListField(UserConfig.TABLES_KEY).size(), 3, "Table list size should be 3"); + } + + @Test + public void testToZNRecordWithExcludeTableList() throws JsonProcessingException { + List<String> excludeTableList = Arrays.asList("excludeTable1", "excludeTable2"); + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.SERVER) + .setRoleType(RoleType.USER) + .setExcludeTableList(excludeTableList) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + + Assert.assertNotNull(znRecord.getListField(UserConfig.EXCLUDE_TABLES_KEY), "Exclude tables should not be null"); + Assert.assertEquals(znRecord.getListField(UserConfig.EXCLUDE_TABLES_KEY), excludeTableList, + "Exclude table list should match"); + Assert.assertEquals(znRecord.getListField(UserConfig.EXCLUDE_TABLES_KEY).size(), 2, + "Exclude table list size should be 2"); + } + + @Test + public void testToZNRecordWithPermissionList() throws JsonProcessingException { + List<AccessType> permissionList = Arrays.asList(AccessType.READ, AccessType.CREATE, AccessType.UPDATE); + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.MINION) + .setRoleType(RoleType.ADMIN) + .setPermissionList(permissionList) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + + List<String> permissionListStr = znRecord.getListField(UserConfig.PERMISSIONS_KEY); + Assert.assertNotNull(permissionListStr, "Permissions should not be null"); + Assert.assertEquals(permissionListStr.size(), 3, "Permission list size should be 3"); + Assert.assertTrue(permissionListStr.contains("READ"), "Should contain READ permission"); + Assert.assertTrue(permissionListStr.contains("CREATE"), "Should contain CREATE permission"); + Assert.assertTrue(permissionListStr.contains("UPDATE"), "Should contain UPDATE permission"); + } + + @Test + public void testToZNRecordWithRlsFilters() throws IOException { + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("country='US'", "department='Engineering'")); + rlsFilters.put("table2", Arrays.asList("region='WEST'")); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.USER) + .setRlsFilters(rlsFilters) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + + String rlsFiltersJson = znRecord.getSimpleField(UserConfig.RLS_FILTERS_KEY); + Assert.assertNotNull(rlsFiltersJson, "RLS filters should not be null"); + + // Deserialize and verify + Map<String, List<String>> deserializedFilters = JsonUtils.stringToObject( + rlsFiltersJson, new com.fasterxml.jackson.core.type.TypeReference<Map<String, List<String>>>() { + } + ); + Assert.assertEquals(deserializedFilters.size(), 2, "RLS filters map size should be 2"); + Assert.assertTrue(deserializedFilters.containsKey("table1"), "Should contain table1 filters"); + Assert.assertTrue(deserializedFilters.containsKey("table2"), "Should contain table2 filters"); + // Verify actual filter values + Assert.assertEquals(deserializedFilters.get("table1").get(0), "country='US'"); + Assert.assertEquals(deserializedFilters.get("table1").get(1), "department='Engineering'"); + Assert.assertEquals(deserializedFilters.get("table2").get(0), "region='WEST'"); + } + + @Test + public void testToZNRecordWithAllFields() throws JsonProcessingException { + List<String> tableList = Arrays.asList("table1", "table2"); + List<String> excludeTableList = Arrays.asList("excludeTable1"); + List<AccessType> permissionList = Arrays.asList(AccessType.READ, AccessType.UPDATE, AccessType.DELETE); + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("filter1", "filter2")); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername("adminUser") + .setPassword("adminPass123") + .setComponentType(ComponentType.PROXY) + .setRoleType(RoleType.ADMIN) + .setTableList(tableList) + .setExcludeTableList(excludeTableList) + .setPermissionList(permissionList) + .setRlsFilters(rlsFilters) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + + Assert.assertNotNull(znRecord, "ZNRecord should not be null"); + Assert.assertEquals(znRecord.getId(), "adminUser", "ZNRecord ID should match username"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.USERNAME_KEY), "adminUser", "Username should match"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.PASSWORD_KEY), "adminPass123", "Password should match"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.COMPONET_KEY), ComponentType.PROXY.toString(), + "Component type should match"); + Assert.assertEquals(znRecord.getSimpleField(UserConfig.ROLE_KEY), RoleType.ADMIN.toString(), + "Role type should match"); + Assert.assertEquals(znRecord.getListField(UserConfig.TABLES_KEY), tableList, "Table list should match"); + Assert.assertEquals(znRecord.getListField(UserConfig.EXCLUDE_TABLES_KEY), excludeTableList, + "Exclude table list should match"); + Assert.assertNotNull(znRecord.getListField(UserConfig.PERMISSIONS_KEY), "Permissions should not be null"); + Assert.assertNotNull(znRecord.getSimpleField(UserConfig.RLS_FILTERS_KEY), "RLS filters should not be null"); + } + + @Test + public void testRoundTripConversionWithMandatoryFields() throws JsonProcessingException { + UserConfig originalConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.USER) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(originalConfig); + UserConfig reconstructedConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertEquals(reconstructedConfig.getUserName(), originalConfig.getUserName(), + "Username should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getPassword(), originalConfig.getPassword(), + "Password should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getComponentType(), originalConfig.getComponentType(), + "Component type should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getRoleType(), originalConfig.getRoleType(), + "Role type should match after round-trip"); + } + + @Test + public void testRoundTripConversionWithAllFields() throws JsonProcessingException { + List<String> tableList = Arrays.asList("table1", "table2"); + List<String> excludeTableList = Arrays.asList("excludeTable1"); + List<AccessType> permissionList = Arrays.asList(AccessType.CREATE, AccessType.READ, AccessType.UPDATE, + AccessType.DELETE); + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("country='US'", "department='Engineering'")); + rlsFilters.put("table2", Arrays.asList("region='WEST'")); + + UserConfig originalConfig = new UserConfigBuilder() + .setUsername("fullTestUser") + .setPassword("fullTestPassword") + .setComponentType(ComponentType.CONTROLLER) + .setRoleType(RoleType.ADMIN) + .setTableList(tableList) + .setExcludeTableList(excludeTableList) + .setPermissionList(permissionList) + .setRlsFilters(rlsFilters) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(originalConfig); + UserConfig reconstructedConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertEquals(reconstructedConfig.getUserName(), originalConfig.getUserName(), + "Username should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getPassword(), originalConfig.getPassword(), + "Password should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getComponentType(), originalConfig.getComponentType(), + "Component type should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getRoleType(), originalConfig.getRoleType(), + "Role type should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getTables(), originalConfig.getTables(), + "Tables should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getExcludeTables(), originalConfig.getExcludeTables(), + "Exclude tables should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getPermissios().size(), originalConfig.getPermissios().size(), + "Permissions size should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getRlsFilters().size(), originalConfig.getRlsFilters().size(), + "RLS filters size should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getRlsFilters().get("table1"), + originalConfig.getRlsFilters().get("table1"), "RLS filters for table1 should match after round-trip"); + Assert.assertEquals(reconstructedConfig.getRlsFilters().get("table2"), + originalConfig.getRlsFilters().get("table2"), "RLS filters for table2 should match after round-trip"); + // Verify actual filter values + Assert.assertEquals(reconstructedConfig.getRlsFilters().get("table1").get(0), "country='US'"); + Assert.assertEquals(reconstructedConfig.getRlsFilters().get("table1").get(1), "department='Engineering'"); + Assert.assertEquals(reconstructedConfig.getRlsFilters().get("table2").get(0), "region='WEST'"); + } + + @Test + public void testDifferentComponentTypes() throws JsonProcessingException { + ComponentType[] componentTypes = { + ComponentType.CONTROLLER, ComponentType.BROKER, ComponentType.SERVER, + ComponentType.MINION, ComponentType.PROXY + }; + + for (ComponentType componentType : componentTypes) { + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(componentType) + .setRoleType(RoleType.USER) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + UserConfig reconstructedConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertEquals(reconstructedConfig.getComponentType(), componentType, + "Component type should match for " + componentType); + } + } + + @Test + public void testDifferentRoleTypes() throws JsonProcessingException { + RoleType[] roleTypes = {RoleType.ADMIN, RoleType.USER}; + + for (RoleType roleType : roleTypes) { + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(roleType) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + UserConfig reconstructedConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertEquals(reconstructedConfig.getRoleType(), roleType, "Role type should match for " + roleType); + } + } + + @Test + public void testAllAccessTypes() throws JsonProcessingException { + List<AccessType> allPermissions = Arrays.asList( + AccessType.CREATE, AccessType.READ, AccessType.UPDATE, AccessType.DELETE + ); + + UserConfig userConfig = new UserConfigBuilder() + .setUsername(TEST_USERNAME) + .setPassword(TEST_PASSWORD) + .setComponentType(ComponentType.BROKER) + .setRoleType(RoleType.ADMIN) + .setPermissionList(allPermissions) + .build(); + + ZNRecord znRecord = AccessControlUserConfigUtils.toZNRecord(userConfig); + UserConfig reconstructedConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertEquals(reconstructedConfig.getPermissios().size(), 4, "Should have all 4 access types"); + Assert.assertTrue(reconstructedConfig.getPermissios().contains(AccessType.CREATE), "Should contain CREATE"); + Assert.assertTrue(reconstructedConfig.getPermissios().contains(AccessType.READ), "Should contain READ"); + Assert.assertTrue(reconstructedConfig.getPermissios().contains(AccessType.UPDATE), "Should contain UPDATE"); + Assert.assertTrue(reconstructedConfig.getPermissios().contains(AccessType.DELETE), "Should contain DELETE"); Review Comment: Multiple occurrences of 'getPermissios' should be corrected to 'getPermissions'. ```suggestion Assert.assertEquals(reconstructedConfig.getPermissions().size(), 4, "Should have all 4 access types"); Assert.assertTrue(reconstructedConfig.getPermissions().contains(AccessType.CREATE), "Should contain CREATE"); Assert.assertTrue(reconstructedConfig.getPermissions().contains(AccessType.READ), "Should contain READ"); Assert.assertTrue(reconstructedConfig.getPermissions().contains(AccessType.UPDATE), "Should contain UPDATE"); Assert.assertTrue(reconstructedConfig.getPermissions().contains(AccessType.DELETE), "Should contain DELETE"); ``` ########## pinot-common/src/test/java/org/apache/pinot/common/utils/config/AccessControlUserConfigUtilsTest.java: ########## @@ -0,0 +1,559 @@ +/** + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.pinot.common.utils.config; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.helix.zookeeper.datamodel.ZNRecord; +import org.apache.pinot.spi.config.user.AccessType; +import org.apache.pinot.spi.config.user.ComponentType; +import org.apache.pinot.spi.config.user.RoleType; +import org.apache.pinot.spi.config.user.UserConfig; +import org.apache.pinot.spi.utils.JsonUtils; +import org.apache.pinot.spi.utils.builder.UserConfigBuilder; +import org.testng.Assert; +import org.testng.annotations.Test; + + +/** + * Tests for {@link AccessControlUserConfigUtils} + */ +public class AccessControlUserConfigUtilsTest { + + private static final String TEST_USERNAME = "testUser"; + private static final String TEST_PASSWORD = "testPassword"; + + @Test + public void testFromZNRecordWithMandatoryFieldsOnly() { + // Create ZNRecord with only mandatory fields + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.BROKER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + znRecord.setSimpleFields(simpleFields); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), TEST_USERNAME, "Username should match"); + Assert.assertEquals(userConfig.getPassword(), TEST_PASSWORD, "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.BROKER, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.USER, "Role type should match"); + Assert.assertNull(userConfig.getTables(), "Tables should be null"); + Assert.assertNull(userConfig.getExcludeTables(), "Exclude tables should be null"); + Assert.assertNull(userConfig.getPermissios(), "Permissions should be null"); + Assert.assertNull(userConfig.getRlsFilters(), "RLS filters should be null"); + } + + @Test + public void testFromZNRecordWithTableList() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.CONTROLLER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.ADMIN.toString()); + znRecord.setSimpleFields(simpleFields); + + List<String> tableList = Arrays.asList("table1", "table2", "table3"); + znRecord.setListField(UserConfig.TABLES_KEY, tableList); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getTables(), "Tables should not be null"); + Assert.assertEquals(userConfig.getTables(), tableList, "Table list should match"); + Assert.assertEquals(userConfig.getTables().size(), 3, "Table list size should be 3"); + } + + @Test + public void testFromZNRecordWithExcludeTableList() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.SERVER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + znRecord.setSimpleFields(simpleFields); + + List<String> excludeTableList = Arrays.asList("excludeTable1", "excludeTable2"); + znRecord.setListField(UserConfig.EXCLUDE_TABLES_KEY, excludeTableList); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getExcludeTables(), "Exclude tables should not be null"); + Assert.assertEquals(userConfig.getExcludeTables(), excludeTableList, "Exclude table list should match"); + Assert.assertEquals(userConfig.getExcludeTables().size(), 2, "Exclude table list size should be 2"); + } + + @Test + public void testFromZNRecordWithPermissionList() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.MINION.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.ADMIN.toString()); + znRecord.setSimpleFields(simpleFields); + + List<String> permissionListStr = Arrays.asList("READ", "CREATE", "UPDATE"); + znRecord.setListField(UserConfig.PERMISSIONS_KEY, permissionListStr); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getPermissios(), "Permissions should not be null"); + Assert.assertEquals(userConfig.getPermissios().size(), 3, "Permission list size should be 3"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.READ), "Should contain READ permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.CREATE), "Should contain CREATE permission"); + Assert.assertTrue(userConfig.getPermissios().contains(AccessType.UPDATE), "Should contain UPDATE permission"); + } + + @Test + public void testFromZNRecordWithRlsFilters() throws JsonProcessingException { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.BROKER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("country='US'", "department='Engineering'")); + rlsFilters.put("table2", Arrays.asList("region='WEST'")); + simpleFields.put(UserConfig.RLS_FILTERS_KEY, JsonUtils.objectToString(rlsFilters)); + + znRecord.setSimpleFields(simpleFields); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig.getRlsFilters(), "RLS filters should not be null"); + Assert.assertEquals(userConfig.getRlsFilters().size(), 2, "RLS filters map size should be 2"); + Assert.assertTrue(userConfig.getRlsFilters().containsKey("table1"), "Should contain table1 filters"); + Assert.assertTrue(userConfig.getRlsFilters().containsKey("table2"), "Should contain table2 filters"); + Assert.assertEquals(userConfig.getRlsFilters().get("table1").size(), 2, "table1 should have 2 filters"); + Assert.assertEquals(userConfig.getRlsFilters().get("table2").size(), 1, "table2 should have 1 filter"); + // Verify actual filter values + Assert.assertEquals(userConfig.getRlsFilters().get("table1").get(0), "country='US'"); + Assert.assertEquals(userConfig.getRlsFilters().get("table1").get(1), "department='Engineering'"); + Assert.assertEquals(userConfig.getRlsFilters().get("table2").get(0), "region='WEST'"); + } + + @Test + public void testFromZNRecordWithMalformedRlsFilters() { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, TEST_USERNAME); + simpleFields.put(UserConfig.PASSWORD_KEY, TEST_PASSWORD); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.BROKER.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.USER.toString()); + simpleFields.put(UserConfig.RLS_FILTERS_KEY, "invalid-json-{malformed"); + znRecord.setSimpleFields(simpleFields); + + // Should not throw exception, but log error and continue + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertNull(userConfig.getRlsFilters(), "RLS filters should be null due to malformed JSON"); + } + + @Test + public void testFromZNRecordWithAllFields() throws JsonProcessingException { + ZNRecord znRecord = new ZNRecord(TEST_USERNAME); + Map<String, String> simpleFields = new HashMap<>(); + simpleFields.put(UserConfig.USERNAME_KEY, "adminUser"); + simpleFields.put(UserConfig.PASSWORD_KEY, "adminPass123"); + simpleFields.put(UserConfig.COMPONET_KEY, ComponentType.PROXY.toString()); + simpleFields.put(UserConfig.ROLE_KEY, RoleType.ADMIN.toString()); + + Map<String, List<String>> rlsFilters = new HashMap<>(); + rlsFilters.put("table1", Arrays.asList("filter1", "filter2")); + simpleFields.put(UserConfig.RLS_FILTERS_KEY, JsonUtils.objectToString(rlsFilters)); + znRecord.setSimpleFields(simpleFields); + + List<String> tableList = Arrays.asList("table1", "table2"); + List<String> excludeTableList = Arrays.asList("excludeTable1"); + List<String> permissionListStr = Arrays.asList("READ", "UPDATE", "DELETE"); + + znRecord.setListField(UserConfig.TABLES_KEY, tableList); + znRecord.setListField(UserConfig.EXCLUDE_TABLES_KEY, excludeTableList); + znRecord.setListField(UserConfig.PERMISSIONS_KEY, permissionListStr); + + UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); + + Assert.assertNotNull(userConfig, "UserConfig should not be null"); + Assert.assertEquals(userConfig.getUserName(), "adminUser", "Username should match"); + Assert.assertEquals(userConfig.getPassword(), "adminPass123", "Password should match"); + Assert.assertEquals(userConfig.getComponentType(), ComponentType.PROXY, "Component type should match"); + Assert.assertEquals(userConfig.getRoleType(), RoleType.ADMIN, "Role type should match"); + Assert.assertEquals(userConfig.getTables(), tableList, "Table list should match"); + Assert.assertEquals(userConfig.getExcludeTables(), excludeTableList, "Exclude table list should match"); + Assert.assertEquals(userConfig.getPermissios().size(), 3, "Permission list size should match"); Review Comment: Corrected spelling of 'getPermissios' to 'getPermissions'. ```suggestion Assert.assertEquals(userConfig.getPermissions().size(), 3, "Permission list size should match"); ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
