diff --git a/agents-common/pom.xml b/agents-common/pom.xml index 591deda888..335d0ec2fc 100644 --- a/agents-common/pom.xml +++ b/agents-common/pom.xml @@ -219,6 +219,18 @@ ${junit.jupiter.version} test + + org.mockito + mockito-inline + ${mockito.version} + test + + + org.mockito + mockito-junit-jupiter + ${mockito.version} + test + org.slf4j log4j-over-slf4j diff --git a/agents-common/src/test/java/org/apache/hadoop/security/TestKrbPasswordSaverLoginModule.java b/agents-common/src/test/java/org/apache/hadoop/security/TestKrbPasswordSaverLoginModule.java new file mode 100644 index 0000000000..6d9709dab1 --- /dev/null +++ b/agents-common/src/test/java/org/apache/hadoop/security/TestKrbPasswordSaverLoginModule.java @@ -0,0 +1,74 @@ +/* + * 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.hadoop.security; + +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** +* @generated by Cursor +* @description +*/ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestKrbPasswordSaverLoginModule { + @Test + public void test01_initialize_storesCredentialsInSharedState() throws Exception { + KrbPasswordSaverLoginModule module = new KrbPasswordSaverLoginModule(); + Map shared = new HashMap<>(); + Map options = new HashMap<>(); + options.put(KrbPasswordSaverLoginModule.USERNAME_PARAM, "user1"); + options.put(KrbPasswordSaverLoginModule.PASSWORD_PARAM, "secret"); + + module.initialize(new Subject(), (CallbackHandler) null, shared, options); + + assertEquals("user1", shared.get(KrbPasswordSaverLoginModule.USERNAME_PARAM)); + assertArrayEquals("secret".toCharArray(), (char[]) shared.get(KrbPasswordSaverLoginModule.PASSWORD_PARAM)); + } + + @Test + public void test02_login_commit_abort_logout_returnTrue() throws Exception { + KrbPasswordSaverLoginModule module = new KrbPasswordSaverLoginModule(); + assertTrue(module.login()); + assertTrue(module.commit()); + assertTrue(module.abort()); + assertTrue(module.logout()); + } + + @Test + public void test03_initialize_withNullOptions_doesNotPopulateShared() { + KrbPasswordSaverLoginModule module = new KrbPasswordSaverLoginModule(); + Map shared = new HashMap<>(); + module.initialize(new Subject(), (CallbackHandler) null, shared, null); + assertTrue(shared.isEmpty()); + } +} diff --git a/agents-common/src/test/java/org/apache/hadoop/security/TestSecureClientLogin.java b/agents-common/src/test/java/org/apache/hadoop/security/TestSecureClientLogin.java new file mode 100644 index 0000000000..22ba288439 --- /dev/null +++ b/agents-common/src/test/java/org/apache/hadoop/security/TestSecureClientLogin.java @@ -0,0 +1,222 @@ +/* + * 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.hadoop.security; + +import org.apache.hadoop.security.authentication.util.KerberosName; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import javax.security.auth.Subject; +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.security.Principal; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @generated by Cursor + * @description + */ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestSecureClientLogin { + @Test + public void test01_isKerberosCredentialExists_nullKeytab_returnsFalse() { + boolean valid = SecureClientLogin.isKerberosCredentialExists("user@EXAMPLE.COM", null); + assertEquals(false, valid); + } + + @Test + public void test02_isKerberosCredentialExists_missingFile_returnsFalse() { + File f = new File("/tmp/does-not-exist-" + System.nanoTime()); + boolean valid = SecureClientLogin.isKerberosCredentialExists("user@EXAMPLE.COM", f.getAbsolutePath()); + assertEquals(false, valid); + } + + @Test + public void test03_isKerberosCredentialExists_existingFileAndPrincipal_returnsTrue() throws Exception { + File f = File.createTempFile("keytab", ".kt"); + f.deleteOnExit(); + try (FileWriter w = new FileWriter(f)) { + w.write("dummy"); + } + boolean valid = SecureClientLogin.isKerberosCredentialExists("user@EXAMPLE.COM", f.getAbsolutePath()); + assertEquals(true, valid); + } + + @Test + public void test04_getPrincipal_noPattern_returnsSame() throws Exception { + String in = "user/host@EXAMPLE.COM"; + String out = SecureClientLogin.getPrincipal(in, "host"); + assertEquals(in, out); + } + + @Test + public void test05_getPrincipal_withPatternAndHost_replacesWithLowercase() throws Exception { + String out = SecureClientLogin.getPrincipal("user/_HOST@EXAMPLE.COM", "FooBar.Example.COM"); + assertEquals("user/foobar.example.com@EXAMPLE.COM", out); + } + + @Test + public void test05b_getPrincipal_withPatternAndWildcardHost_usesLocalHost() throws Exception { + String out = SecureClientLogin.getPrincipal("user/_HOST@EXAMPLE.COM", "0.0.0.0"); + assertTrue(out.startsWith("user/")); + assertTrue(out.endsWith("@EXAMPLE.COM")); + } + + @Test + public void test06_getPrincipal_withNullHost_throwsIOException() { + assertThrows(IOException.class, () -> SecureClientLogin.getPrincipal("user/_HOST@EXAMPLE.COM", null)); + } + + @Test + public void test07_login_returnsSubjectWithPrincipal() throws Exception { + Subject s = SecureClientLogin.login("alice"); + assertNotNull(s); + Set principals = SecureClientLogin.getUserPrincipals(s); + assertNotNull(principals); + assertTrue(principals.stream().anyMatch(p -> "alice".equals(p.getName()))); + } + + @Test + public void test08_getUserPrincipals_nullSubject_returnsNull() { + assertNull(SecureClientLogin.getUserPrincipals(null)); + } + + @Test + public void test09_loginUserFromKeytab_invalid_throwsException() { + assertThrows(Exception.class, + () -> SecureClientLogin.loginUserFromKeytab("user@EXAMPLE.COM", "/path/not/found")); + } + + @Test + public void test10_loginUserWithPassword_invalid_throwsException() { + assertThrows(Exception.class, () -> SecureClientLogin.loginUserWithPassword("user@EXAMPLE.COM", "badpass")); + } + + @Test + public void test11_loginUserFromKeytab_withNameRules_invalid_throwsException() { + assertThrows(Exception.class, + () -> SecureClientLogin.loginUserFromKeytab("user@EXAMPLE.COM", "/path/not/found", "DEFAULT")); + } + + @Test + public void test12_createUserPrincipal_returnsPrincipalWithName() { + Principal p = SecureClientLogin.createUserPrincipal("bob"); + assertNotNull(p); + assertEquals("bob", p.getName()); + } + + @Test + public void test13_secureClientLoginConfiguration_withKeytab_returnsSingleKerberosEntry() { + SecureClientLogin.SecureClientLoginConfiguration conf = new SecureClientLogin.SecureClientLoginConfiguration( + true, "user@EXAMPLE.COM", "/tmp/fake.keytab"); + AppConfigurationEntry[] entries = conf.getAppConfigurationEntry("hadoop-keytab-kerberos"); + assertNotNull(entries); + assertEquals(1, entries.length); + assertEquals(LoginModuleControlFlag.REQUIRED, entries[0].getControlFlag()); + assertEquals("user@EXAMPLE.COM", entries[0].getOptions().get("principal")); + assertEquals("true", entries[0].getOptions().get("useKeyTab")); + assertEquals("/tmp/fake.keytab", entries[0].getOptions().get("keyTab")); + } + + @Test + public void test14_secureClientLoginConfiguration_withPassword_returnsPwdSaverThenKerberos() { + SecureClientLogin.SecureClientLoginConfiguration conf = new SecureClientLogin.SecureClientLoginConfiguration( + false, "user@EXAMPLE.COM", "pwd"); + AppConfigurationEntry[] entries = conf.getAppConfigurationEntry("hadoop-keytab-kerberos"); + assertNotNull(entries); + assertEquals(2, entries.length); + assertEquals(KrbPasswordSaverLoginModule.class.getName(), entries[0].getLoginModuleName()); + assertEquals("user@EXAMPLE.COM", entries[0].getOptions().get(KrbPasswordSaverLoginModule.USERNAME_PARAM)); + assertEquals("pwd", entries[0].getOptions().get(KrbPasswordSaverLoginModule.PASSWORD_PARAM)); + assertTrue(entries[1].getLoginModuleName().contains("Krb5LoginModule")); + } + + @Test + public void test15_isKerberosCredentialExists_unreadableFile_returnsFalse() throws Exception { + File f = File.createTempFile("keytab", ".kt"); + f.deleteOnExit(); + try (FileWriter w = new FileWriter(f)) { + w.write("dummy"); + } + // make unreadable if possible + boolean permChanged = f.setReadable(false, false); + // If permission cannot be changed in this environment, skip assert to avoid + // flakiness + if (permChanged) { + boolean valid = SecureClientLogin.isKerberosCredentialExists("user@EXAMPLE.COM", f.getAbsolutePath()); + assertEquals(false, valid); + } + } + + @Test + public void test16_isKerberosCredentialExists_emptyPrincipal_returnsFalse() throws Exception { + File f = File.createTempFile("keytab", ".kt"); + f.deleteOnExit(); + try (FileWriter w = new FileWriter(f)) { + w.write("dummy"); + } + boolean valid = SecureClientLogin.isKerberosCredentialExists("", f.getAbsolutePath()); + assertEquals(false, valid); + } + + @Test + public void test17_loginUserFromKeytab_withInvalidNameRules_throwsIllegalArgumentException() { + assertThrows(IllegalArgumentException.class, + () -> SecureClientLogin.loginUserFromKeytab("user@EXAMPLE.COM", "/path/not/found", "INVALID_RULES_FORMAT")); + } + + @Test + public void test18_loginUserFromKeytab_twoArg_catchesLoginException() { + String originalRules = "DEFAULT"; + String allowExampleRule = "RULE:[1:$1@$0](.*@EXAMPLE.COM)s/@.*//\nDEFAULT"; + try { + KerberosName.setRules(allowExampleRule); + assertThrows(IOException.class, + () -> SecureClientLogin.loginUserFromKeytab("user@EXAMPLE.COM", "/path/not/found")); + } finally { + KerberosName.setRules(originalRules); + } + } + + @Test + public void test19_loginUserFromKeytab_threeArg_catchesLoginException() { + String originalRules = "DEFAULT"; + String allowExampleRule = "RULE:[1:$1@$0](.*@EXAMPLE.COM)s/@.*//\nDEFAULT"; + try { + assertThrows(IOException.class, () -> SecureClientLogin.loginUserFromKeytab("user@EXAMPLE.COM", + "/path/not/found", allowExampleRule)); + } finally { + KerberosName.setRules(originalRules); + } + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/admin/client/TestAbstractRangerAdminClient.java b/agents-common/src/test/java/org/apache/ranger/admin/client/TestAbstractRangerAdminClient.java new file mode 100644 index 0000000000..550983ee34 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/admin/client/TestAbstractRangerAdminClient.java @@ -0,0 +1,98 @@ +/* + * 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.ranger.admin.client; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.security.UserGroupInformation; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +/** +* @generated by Cursor +* @description +*/ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestAbstractRangerAdminClient { + public static class DummyClient extends AbstractRangerAdminClient { + @Override + public void init(String serviceName, String appId, String configPropertyPrefix, Configuration config) { + super.init(serviceName, appId, configPropertyPrefix, config); + } + } + + @Test + public void test01_initSetsGsonAndForceNonKerberos() { + DummyClient c = new DummyClient(); + Configuration cfg = new Configuration(false); + cfg.setBoolean("test.forceNonKerberos", true); + c.init("svc", "app", "test", cfg); + // isKerberosEnabled should return false when forceNonKerberos is true + try (MockedStatic ignored = Mockito.mockStatic(UserGroupInformation.class)) { + Assertions.assertFalse(c.isKerberosEnabled(null)); + } + } + + @Test + public void test02_isKerberosEnabled_respectsUGI() { + DummyClient c = new DummyClient(); + Configuration cfg = new Configuration(false); + cfg.setBoolean("p.forceNonKerberos", false); + c.init("svc", "app", "p", cfg); + + UserGroupInformation ugi = Mockito.mock(UserGroupInformation.class); + try (MockedStatic mocked = Mockito.mockStatic(UserGroupInformation.class)) { + mocked.when(UserGroupInformation::isSecurityEnabled).thenReturn(true); + Mockito.when(ugi.hasKerberosCredentials()).thenReturn(true); + Assertions.assertTrue(c.isKerberosEnabled(ugi)); + + Mockito.when(ugi.hasKerberosCredentials()).thenReturn(false); + Assertions.assertFalse(c.isKerberosEnabled(ugi)); + } + } + + @Test + public void test03_defaultNoOpMethodsReturnNullOrNoThrow() throws Exception { + DummyClient c = new DummyClient(); + Configuration cfg = new Configuration(false); + c.init("svc", "app", "p", cfg); + Assertions.assertNull(c.getServicePoliciesIfUpdated(1L, 2L)); + Assertions.assertNull(c.getRolesIfUpdated(1L, 2L)); + Assertions.assertNull(c.createRole(null)); + c.dropRole("u", "r"); + Assertions.assertNull(c.getAllRoles("u")); + Assertions.assertNull(c.getUserRoles("u")); + Assertions.assertNull(c.getRole("u", "r")); + c.grantRole(null); + c.revokeRole(null); + c.grantAccess(null); + c.revokeAccess(null); + Assertions.assertNull(c.getServiceTagsIfUpdated(1L, 2L)); + Assertions.assertNull(c.getTagTypes("x")); + Assertions.assertNull(c.getUserStoreIfUpdated(1L, 2L)); + Assertions.assertNull(c.getGdsInfoIfUpdated(1L, 2L)); + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/admin/client/TestRangerAdminRESTClient.java b/agents-common/src/test/java/org/apache/ranger/admin/client/TestRangerAdminRESTClient.java new file mode 100644 index 0000000000..ee4d4aff24 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/admin/client/TestRangerAdminRESTClient.java @@ -0,0 +1,1108 @@ +/* + * 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.ranger.admin.client; + +import com.sun.jersey.api.client.ClientResponse; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.security.AccessControlException; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.ranger.admin.client.datatype.RESTResponse; +import org.apache.ranger.audit.provider.MiscUtil; +import org.apache.ranger.plugin.model.RangerRole; +import org.apache.ranger.plugin.util.GrantRevokeRequest; +import org.apache.ranger.plugin.util.GrantRevokeRoleRequest; +import org.apache.ranger.plugin.util.RangerRESTClient; +import org.apache.ranger.plugin.util.RangerRoles; +import org.apache.ranger.plugin.util.RangerServiceNotFoundException; +import org.apache.ranger.plugin.util.ServiceGdsInfo; +import org.apache.ranger.plugin.util.ServicePolicies; +import org.apache.ranger.plugin.util.ServiceTags; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import javax.ws.rs.core.Cookie; +import javax.ws.rs.core.NewCookie; + +import java.lang.reflect.Field; +import java.security.PrivilegedExceptionAction; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * @generated by Cursor + * @description + */ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestRangerAdminRESTClient { + private static void setPrivateField(Object target, String name, Object value) throws Exception { + Field f = target.getClass().getDeclaredField(name); + f.setAccessible(true); + f.set(target, value); + } + + private static Object getPrivateField(Object target, String name) throws Exception { + Field f = target.getClass().getDeclaredField(name); + f.setAccessible(true); + return f.get(target); + } + + @Test + public void test01_getTagTypes_okAndCookieSet() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + cfg.setBoolean("p.policy.rest.client.cookie.enabled", true); + cfg.set("p.policy.rest.client.session.cookie.name", "RANGERSESSION"); + client.init("svc", "app", "p", cfg); + + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse resp = Mockito.mock(ClientResponse.class); + Mockito.when(resp.getStatus()).thenReturn(200); + Mockito.when(resp.getEntity(String.class)).thenReturn("[\"t1\",\"t2\"]"); + Mockito.when(resp.getCookies()).thenReturn(Arrays.asList(new NewCookie("RANGERSESSION", "abc"))); + + ArgumentCaptor url = ArgumentCaptor.forClass(String.class); + ArgumentCaptor params = ArgumentCaptor.forClass(Map.class); + ArgumentCaptor cookie = ArgumentCaptor.forClass(Cookie.class); + Mockito.when(rest.get(url.capture(), params.capture(), cookie.capture())).thenReturn(resp); + + List tags = client.getTagTypes("t"); + Assertions.assertEquals(Arrays.asList("t1", "t2"), tags); + + // Invoke again to verify a cookie is now being sent + ClientResponse resp2 = Mockito.mock(ClientResponse.class); + Mockito.when(resp2.getStatus()).thenReturn(500); + Mockito.when(resp2.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("err"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.any())).thenReturn(resp2); + Assertions.assertThrows(Exception.class, () -> client.getTagTypes("t")); + } + + @Test + public void test02_getTagTypes_errorThrows() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse resp = Mockito.mock(ClientResponse.class); + Mockito.when(resp.getStatus()).thenReturn(500); + Mockito.when(resp.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("server-error"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(resp); + + Assertions.assertThrows(Exception.class, () -> client.getTagTypes("t")); + } + + @Test + public void test03_getServicePoliciesIfUpdated_notModifiedReturnsNull() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse resp = Mockito.mock(ClientResponse.class); + Mockito.when(resp.getStatus()).thenReturn(304); + Mockito.when(resp.getCookies()).thenReturn(Arrays.asList(new NewCookie("R", "v"))); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(resp); + + Assertions.assertNull(client.getServicePoliciesIfUpdated(1L, 2L)); + } + + @Test + public void test04_getServicePoliciesIfUpdated_notFoundThrowsServiceNotFound() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse resp = Mockito.mock(ClientResponse.class); + Mockito.when(resp.getStatus()).thenReturn(404); + String body = "\"RANGER_ERROR_SERVICE_NOT_FOUND: ServiceName=svc\""; + Mockito.when(resp.hasEntity()).thenReturn(true); + Mockito.when(resp.getEntity(String.class)).thenReturn(body); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(resp); + + Assertions.assertThrows(RangerServiceNotFoundException.class, () -> client.getServicePoliciesIfUpdated(1L, 2L)); + } + + @Test + public void test05_createRole_unauthorizedAndNullResponse() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + RangerRole role = new RangerRole(); + role.setName("r1"); + + ClientResponse unauthorized = Mockito.mock(ClientResponse.class); + Mockito.when(unauthorized.getStatus()).thenReturn(401); + Mockito.when(unauthorized.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("unauth"); + } + }.toJson()); + Mockito.when(rest.post(Mockito.anyString(), Mockito.anyMap(), Mockito.any(), Mockito.isNull())) + .thenReturn(unauthorized); + Assertions.assertThrows(AccessControlException.class, () -> client.createRole(role)); + + Mockito.when(rest.post(Mockito.anyString(), Mockito.anyMap(), Mockito.any(), Mockito.isNull())) + .thenReturn(null); + Assertions.assertThrows(Exception.class, () -> client.createRole(role)); + } + + @Test + public void test06_dropRole_okAndError() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse ok204 = Mockito.mock(ClientResponse.class); + Mockito.when(ok204.getStatus()).thenReturn(204); + Mockito.when(rest.delete(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(ok204); + client.dropRole("u", "r"); + + Mockito.when(rest.delete(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(null); + Assertions.assertThrows(Exception.class, () -> client.dropRole("u", "r")); + } + + @Test + public void test07_getAllRoles_okAndUnauthorized() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(ok.getEntity(String.class)).thenReturn("[\"a\"]"); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(ok); + Assertions.assertEquals(Arrays.asList("a"), client.getAllRoles("u")); + + ClientResponse unauth = Mockito.mock(ClientResponse.class); + Mockito.when(unauth.getStatus()).thenReturn(401); + Mockito.when(unauth.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("unauth"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(unauth); + Assertions.assertThrows(AccessControlException.class, () -> client.getAllRoles("u")); + } + + @Test + public void test08_getServiceTagsIfUpdated_branches() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(null); + Assertions.assertNull(client.getServiceTagsIfUpdated(1L, 2L)); + + ClientResponse notFound = Mockito.mock(ClientResponse.class); + Mockito.when(notFound.getStatus()).thenReturn(404); + Mockito.when(notFound.hasEntity()).thenReturn(true); + Mockito.when(notFound.getEntity(String.class)) + .thenReturn("\"RANGER_ERROR_SERVICE_NOT_FOUND: ServiceName=svc\""); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(notFound); + Assertions.assertThrows(RangerServiceNotFoundException.class, () -> client.getServiceTagsIfUpdated(1L, 2L)); + } + + @Test + public void test09_getUserStoreIfUpdated_and_getGdsInfoIfUpdated_unexpectedStatusResetsCookie() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + cfg.setBoolean("p.policy.rest.client.cookie.enabled", true); + cfg.set("p.policy.rest.client.session.cookie.name", "RANGERSESSION"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(ok.getEntity(String.class)).thenReturn("{}\n"); + Mockito.when(ok.getCookies()).thenReturn(Arrays.asList(new NewCookie("RANGERSESSION", "abc"))); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(ok); + client.getUserStoreIfUpdated(1L, 2L); + Assertions.assertNotNull(getPrivateField(client, "sessionId")); + + ClientResponse unexpected = Mockito.mock(ClientResponse.class); + Mockito.when(unexpected.getStatus()).thenReturn(418); // unexpected status + Mockito.when(unexpected.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("teapot"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.any())).thenReturn(unexpected); + client.getGdsInfoIfUpdated(1L, 2L); + Assertions.assertNull(getPrivateField(client, "sessionId")); + } + + @Test + public void test10_secureModeBranches_usePrivilegedAction() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + UserGroupInformation ugi = Mockito.mock(UserGroupInformation.class); + try (MockedStatic misc = Mockito.mockStatic(MiscUtil.class); + MockedStatic ugiStatic = Mockito.mockStatic(UserGroupInformation.class)) { + misc.when(MiscUtil::getUGILoginUser).thenReturn(ugi); + ugiStatic.when(UserGroupInformation::isSecurityEnabled).thenReturn(true); + Mockito.when(ugi.hasKerberosCredentials()).thenReturn(true); + + Assertions.assertNull(client.getServicePoliciesIfUpdated(1L, 2L)); + } + } + + @Test + public void test11_getRolesIfUpdated_branches_notModifiedAndNull() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(null); + Assertions.assertNull(client.getRolesIfUpdated(1L, 2L)); + + ClientResponse notModified = Mockito.mock(ClientResponse.class); + Mockito.when(notModified.getStatus()).thenReturn(304); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(notModified); + Assertions.assertNull(client.getRolesIfUpdated(1L, 2L)); + } + + @Test + public void test12_getRolesIfUpdated_ok() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(ok.getEntity(String.class)) + .thenReturn("{\n \"serviceName\": \"svc\",\n \"roleVersion\": 5\n}\n"); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(ok); + RangerRoles roles = client.getRolesIfUpdated(1L, 2L); + Assertions.assertNotNull(roles); + } + + @Test + public void test13_getRolesIfUpdated_notFoundThrowsServiceNotFound() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse notFound = Mockito.mock(ClientResponse.class); + Mockito.when(notFound.getStatus()).thenReturn(404); + Mockito.when(notFound.hasEntity()).thenReturn(true); + Mockito.when(notFound.getEntity(String.class)) + .thenReturn("\"RANGER_ERROR_SERVICE_NOT_FOUND: ServiceName=svc\""); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(notFound); + Assertions.assertThrows(RangerServiceNotFoundException.class, () -> client.getRolesIfUpdated(1L, 2L)); + } + + @Test + public void test14_getRolesIfUpdated_unexpectedStatusReturnsNull() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse unexpected = Mockito.mock(ClientResponse.class); + Mockito.when(unexpected.getStatus()).thenReturn(500); + Mockito.when(unexpected.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("err"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(unexpected); + Assertions.assertNull(client.getRolesIfUpdated(1L, 2L)); + } + + @Test + public void test15_getUserRoles_okUnauthorizedAndNull() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(ok.getEntity(String.class)).thenReturn("[\"r1\",\"r2\"]"); + Mockito.when(rest.get(Mockito.anyString(), Mockito.isNull(), Mockito.isNull())).thenReturn(ok); + Assertions.assertEquals(Arrays.asList("r1", "r2"), client.getUserRoles("u")); + + ClientResponse unauth = Mockito.mock(ClientResponse.class); + Mockito.when(unauth.getStatus()).thenReturn(401); + Mockito.when(unauth.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("unauth"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.isNull(), Mockito.isNull())).thenReturn(unauth); + Assertions.assertThrows(AccessControlException.class, () -> client.getUserRoles("u")); + + Mockito.when(rest.get(Mockito.anyString(), Mockito.isNull(), Mockito.isNull())).thenReturn(null); + Assertions.assertThrows(Exception.class, () -> client.getUserRoles("u")); + } + + @Test + public void test16_getRole_okUnauthorizedAndNull() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(ok.getEntity(String.class)).thenReturn("{\n \"name\": \"role1\"\n}\n"); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(ok); + RangerRole role = client.getRole("u", "role1"); + Assertions.assertNotNull(role); + + ClientResponse unauth = Mockito.mock(ClientResponse.class); + Mockito.when(unauth.getStatus()).thenReturn(401); + Mockito.when(unauth.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("unauth"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(unauth); + Assertions.assertThrows(AccessControlException.class, () -> client.getRole("u", "role1")); + + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(null); + Assertions.assertThrows(Exception.class, () -> client.getRole("u", "role1")); + } + + @Test + public void test17_grantRole_branches() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + GrantRevokeRoleRequest req = new GrantRevokeRoleRequest(); + + ClientResponse unauth = Mockito.mock(ClientResponse.class); + Mockito.when(unauth.getStatus()).thenReturn(401); + Mockito.when(unauth.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("unauth"); + } + }.toJson()); + Mockito.when(rest.put(Mockito.anyString(), Mockito.any(), Mockito.isNull(Cookie.class))) + .thenReturn(unauth); + Assertions.assertThrows(AccessControlException.class, () -> client.grantRole(req)); + + Mockito.when(rest.put(Mockito.anyString(), Mockito.any(), Mockito.isNull(Cookie.class))) + .thenReturn(null); + Assertions.assertThrows(Exception.class, () -> client.grantRole(req)); + + ClientResponse err = Mockito.mock(ClientResponse.class); + Mockito.when(err.getStatus()).thenReturn(500); + Mockito.when(err.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("err"); + } + }.toJson()); + Mockito.when(rest.put(Mockito.anyString(), Mockito.any(), Mockito.isNull(Cookie.class))) + .thenReturn(err); + Assertions.assertThrows(Exception.class, () -> client.grantRole(req)); + + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(rest.put(Mockito.anyString(), Mockito.any(), Mockito.isNull(Cookie.class))).thenReturn(ok); + client.grantRole(req); + } + + @Test + public void test18_revokeRole_branches() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + GrantRevokeRoleRequest req = new GrantRevokeRoleRequest(); + + ClientResponse unauth = Mockito.mock(ClientResponse.class); + Mockito.when(unauth.getStatus()).thenReturn(401); + Mockito.when(unauth.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("unauth"); + } + }.toJson()); + Mockito.when(rest.put(Mockito.anyString(), Mockito.any(), Mockito.isNull(Cookie.class))) + .thenReturn(unauth); + Assertions.assertThrows(AccessControlException.class, () -> client.revokeRole(req)); + + Mockito.when(rest.put(Mockito.anyString(), Mockito.any(), Mockito.isNull(Cookie.class))) + .thenReturn(null); + Assertions.assertThrows(Exception.class, () -> client.revokeRole(req)); + + ClientResponse err = Mockito.mock(ClientResponse.class); + Mockito.when(err.getStatus()).thenReturn(500); + Mockito.when(err.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("err"); + } + }.toJson()); + Mockito.when(rest.put(Mockito.anyString(), Mockito.any(), Mockito.isNull(Cookie.class))) + .thenReturn(err); + Assertions.assertThrows(Exception.class, () -> client.revokeRole(req)); + + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(rest.put(Mockito.anyString(), Mockito.any(), Mockito.isNull(Cookie.class))).thenReturn(ok); + client.revokeRole(req); + } + + @Test + public void test19_grantAccess_branches() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + GrantRevokeRequest req = new GrantRevokeRequest(); + + ClientResponse unauth = Mockito.mock(ClientResponse.class); + Mockito.when(unauth.getStatus()).thenReturn(401); + Mockito.when(unauth.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("unauth"); + } + }.toJson()); + Mockito.when(rest.post(Mockito.anyString(), Mockito.anyMap(), Mockito.any(), Mockito.isNull())) + .thenReturn(unauth); + Assertions.assertThrows(AccessControlException.class, () -> client.grantAccess(req)); + + Mockito.when(rest.post(Mockito.anyString(), Mockito.anyMap(), Mockito.any(), Mockito.isNull())) + .thenReturn(null); + Assertions.assertThrows(Exception.class, () -> client.grantAccess(req)); + + ClientResponse err = Mockito.mock(ClientResponse.class); + Mockito.when(err.getStatus()).thenReturn(500); + Mockito.when(err.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("err"); + } + }.toJson()); + Mockito.when(rest.post(Mockito.anyString(), Mockito.anyMap(), Mockito.any(), Mockito.isNull())).thenReturn(err); + Assertions.assertThrows(Exception.class, () -> client.grantAccess(req)); + + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(rest.post(Mockito.anyString(), Mockito.anyMap(), Mockito.any(), Mockito.isNull())).thenReturn(ok); + client.grantAccess(req); + } + + @Test + public void test20_revokeAccess_branches() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + GrantRevokeRequest req = new GrantRevokeRequest(); + + ClientResponse unauth = Mockito.mock(ClientResponse.class); + Mockito.when(unauth.getStatus()).thenReturn(401); + Mockito.when(unauth.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("unauth"); + } + }.toJson()); + Mockito.when(rest.post(Mockito.anyString(), Mockito.anyMap(), Mockito.any(), Mockito.isNull())) + .thenReturn(unauth); + Assertions.assertThrows(AccessControlException.class, () -> client.revokeAccess(req)); + + Mockito.when(rest.post(Mockito.anyString(), Mockito.anyMap(), Mockito.any(), Mockito.isNull())) + .thenReturn(null); + Assertions.assertThrows(Exception.class, () -> client.revokeAccess(req)); + + ClientResponse err = Mockito.mock(ClientResponse.class); + Mockito.when(err.getStatus()).thenReturn(500); + Mockito.when(err.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("err"); + } + }.toJson()); + Mockito.when(rest.post(Mockito.anyString(), Mockito.anyMap(), Mockito.any(), Mockito.isNull())).thenReturn(err); + Assertions.assertThrows(Exception.class, () -> client.revokeAccess(req)); + + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(rest.post(Mockito.anyString(), Mockito.anyMap(), Mockito.any(), Mockito.isNull())).thenReturn(ok); + client.revokeAccess(req); + } + + @Test + public void test21_getServicePoliciesIfUpdated_ok() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(ok.getEntity(String.class)) + .thenReturn("{\n \"serviceName\": \"svc\",\n \"policyVersion\": 3\n}\n"); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(ok); + ServicePolicies policies = client.getServicePoliciesIfUpdated(1L, 2L); + Assertions.assertNotNull(policies); + } + + @Test + public void test22_getServicePoliciesIfUpdated_unexpectedStatusReturnsNull() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse unexpected = Mockito.mock(ClientResponse.class); + Mockito.when(unexpected.getStatus()).thenReturn(500); + Mockito.when(unexpected.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("err"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(unexpected); + Assertions.assertNull(client.getServicePoliciesIfUpdated(1L, 2L)); + } + + // ==================== Additional tests to cover missing branches + // ==================== + + @Test + public void test23_createRole_ok() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + RangerRole roleReq = new RangerRole(); + roleReq.setName("r1"); + + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(ok.getEntity(String.class)).thenReturn("{\"name\":\"r1\"}"); + Mockito.when(rest.post(Mockito.anyString(), Mockito.anyMap(), Mockito.any(), Mockito.isNull())).thenReturn(ok); + + RangerRole role = client.createRole(roleReq); + Assertions.assertNotNull(role); + } + + @Test + public void test24_dropRole_unauthorizedAndError() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse unauth = Mockito.mock(ClientResponse.class); + Mockito.when(unauth.getStatus()).thenReturn(401); + Mockito.when(unauth.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("unauth"); + } + }.toJson()); + Mockito.when(rest.delete(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(unauth); + Assertions.assertThrows(AccessControlException.class, () -> client.dropRole("u", "r")); + + ClientResponse err = Mockito.mock(ClientResponse.class); + Mockito.when(err.getStatus()).thenReturn(500); + Mockito.when(err.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("err"); + } + }.toJson()); + Mockito.when(rest.delete(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(err); + Assertions.assertThrows(Exception.class, () -> client.dropRole("u", "r")); + } + + @Test + public void test25_getAllRoles_nullResponseThrows() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(null); + Assertions.assertThrows(Exception.class, () -> client.getAllRoles("u")); + } + + @Test + public void test26_getServiceTagsIfUpdated_notModifiedReturnsNull() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse notModified = Mockito.mock(ClientResponse.class); + Mockito.when(notModified.getStatus()).thenReturn(304); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(notModified); + Assertions.assertNull(client.getServiceTagsIfUpdated(1L, 2L)); + } + + @Test + public void test27_getServiceTagsIfUpdated_okReturnsObject() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(ok.getEntity(String.class)).thenReturn("{}\n"); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(ok); + ServiceTags tags = client.getServiceTagsIfUpdated(1L, 2L); + Assertions.assertNotNull(tags); + } + + @Test + public void test28_getServiceTagsIfUpdated_unexpectedStatusReturnsNull() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse unexpected = Mockito.mock(ClientResponse.class); + Mockito.when(unexpected.getStatus()).thenReturn(500); + Mockito.when(unexpected.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("err"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(unexpected); + Assertions.assertNull(client.getServiceTagsIfUpdated(1L, 2L)); + } + + @Test + public void test29_getUserStoreIfUpdated_notModifiedNotFoundAndUnexpected() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse notModified = Mockito.mock(ClientResponse.class); + Mockito.when(notModified.getStatus()).thenReturn(304); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(notModified); + Assertions.assertNull(client.getUserStoreIfUpdated(1L, 2L)); + + ClientResponse notFound = Mockito.mock(ClientResponse.class); + Mockito.when(notFound.getStatus()).thenReturn(404); + Mockito.when(notFound.hasEntity()).thenReturn(true); + Mockito.when(notFound.getEntity(String.class)) + .thenReturn("\"RANGER_ERROR_SERVICE_NOT_FOUND: ServiceName=svc\""); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(notFound); + Assertions.assertThrows(RangerServiceNotFoundException.class, () -> client.getUserStoreIfUpdated(1L, 2L)); + + ClientResponse unexpected = Mockito.mock(ClientResponse.class); + Mockito.when(unexpected.getStatus()).thenReturn(500); + Mockito.when(unexpected.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("err"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(unexpected); + Assertions.assertNull(client.getUserStoreIfUpdated(1L, 2L)); + } + + @Test + public void test30_getGdsInfoIfUpdated_nullNotModifiedOkNotFound() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(null); + Assertions.assertNull(client.getGdsInfoIfUpdated(1L, 2L)); + + ClientResponse notModified = Mockito.mock(ClientResponse.class); + Mockito.when(notModified.getStatus()).thenReturn(304); + Mockito.when(notModified.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("not-modified"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(notModified); + Assertions.assertNull(client.getGdsInfoIfUpdated(1L, 2L)); + + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(ok.getEntity(String.class)).thenReturn("{}\n"); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(ok); + ServiceGdsInfo gds = client.getGdsInfoIfUpdated(1L, 2L); + Assertions.assertNotNull(gds); + + ClientResponse notFound = Mockito.mock(ClientResponse.class); + Mockito.when(notFound.getStatus()).thenReturn(404); + Mockito.when(notFound.hasEntity()).thenReturn(true); + Mockito.when(notFound.getEntity(String.class)) + .thenReturn("\"RANGER_ERROR_SERVICE_NOT_FOUND: ServiceName=svc\""); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(notFound); + Assertions.assertThrows(RangerServiceNotFoundException.class, () -> client.getGdsInfoIfUpdated(1L, 2L)); + } + + @Test + public void test31_getServicePoliciesIfUpdated_noContentReturnsNull() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse noContent = Mockito.mock(ClientResponse.class); + Mockito.when(noContent.getStatus()).thenReturn(204); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(noContent); + + Assertions.assertNull(client.getServicePoliciesIfUpdated(1L, 2L)); + } + + @Test + public void test32_getAllRoles_errorThrowsNonUnauthorized() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse err = Mockito.mock(ClientResponse.class); + Mockito.when(err.getStatus()).thenReturn(500); + Mockito.when(err.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("err"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(err); + + Assertions.assertThrows(Exception.class, () -> client.getAllRoles("u")); + } + + @Test + public void test33_getUserRoles_errorThrowsNonUnauthorized() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse err = Mockito.mock(ClientResponse.class); + Mockito.when(err.getStatus()).thenReturn(500); + Mockito.when(err.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("err"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.isNull(), Mockito.isNull())).thenReturn(err); + + Assertions.assertThrows(Exception.class, () -> client.getUserRoles("u")); + } + + @Test + public void test34_getRole_errorThrowsNonUnauthorized() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + ClientResponse err = Mockito.mock(ClientResponse.class); + Mockito.when(err.getStatus()).thenReturn(500); + Mockito.when(err.getEntity(String.class)).thenReturn(new RESTResponse() { + { + setMsgDesc("err"); + } + }.toJson()); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.isNull())).thenReturn(err); + + Assertions.assertThrows(Exception.class, () -> client.getRole("u", "r")); + } + + @Test + public void test35_cookieNullResponseResetsSessionId() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + cfg.setBoolean("p.policy.rest.client.cookie.enabled", true); + cfg.set("p.policy.rest.client.session.cookie.name", "RANGERSESSION"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + // First call sets the cookie + ClientResponse ok = Mockito.mock(ClientResponse.class); + Mockito.when(ok.getStatus()).thenReturn(200); + Mockito.when(ok.getEntity(String.class)).thenReturn("[\"t\"]"); + Mockito.when(ok.getCookies()).thenReturn(Arrays.asList(new NewCookie("RANGERSESSION", "abc"))); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.any())).thenReturn(ok); + client.getTagTypes("t"); + Assertions.assertNotNull(getPrivateField(client, "sessionId")); + + // Next call returns null response; sessionId should be reset to null + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.any())).thenReturn(null); + client.getServicePoliciesIfUpdated(1L, 2L); + Assertions.assertNull(getPrivateField(client, "sessionId")); + } + + @Test + public void test36_getRolesIfUpdated_secureMode_usesSecureUrl() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + UserGroupInformation ugi = Mockito.mock(UserGroupInformation.class); + try (MockedStatic misc = Mockito.mockStatic(MiscUtil.class); + MockedStatic ugiStatic = Mockito.mockStatic(UserGroupInformation.class)) { + misc.when(MiscUtil::getUGILoginUser).thenReturn(ugi); + ugiStatic.when(UserGroupInformation::isSecurityEnabled).thenReturn(true); + Mockito.when(ugi.hasKerberosCredentials()).thenReturn(true); + misc.when(() -> MiscUtil.executePrivilegedAction(Mockito.>any())) + .thenAnswer(inv -> { + PrivilegedExceptionAction action = inv.getArgument(0); + return action.run(); + }); + + ClientResponse notModified = Mockito.mock(ClientResponse.class); + Mockito.when(notModified.getStatus()).thenReturn(304); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.any())).thenReturn(notModified); + + Assertions.assertNull(client.getRolesIfUpdated(1L, 2L)); + + ArgumentCaptor url = ArgumentCaptor.forClass(String.class); + Mockito.verify(rest).get(url.capture(), Mockito.anyMap(), Mockito.any()); + Assertions.assertEquals("/service/roles/secure/download/svc", url.getValue()); + } + } + + @Test + public void test37_getServiceTagsIfUpdated_secureMode_usesSecureUrl() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + UserGroupInformation ugi = Mockito.mock(UserGroupInformation.class); + try (MockedStatic misc = Mockito.mockStatic(MiscUtil.class); + MockedStatic ugiStatic = Mockito.mockStatic(UserGroupInformation.class)) { + misc.when(MiscUtil::getUGILoginUser).thenReturn(ugi); + ugiStatic.when(UserGroupInformation::isSecurityEnabled).thenReturn(true); + Mockito.when(ugi.hasKerberosCredentials()).thenReturn(true); + misc.when(() -> MiscUtil.executePrivilegedAction(Mockito.>any())) + .thenAnswer(inv -> { + PrivilegedExceptionAction action = inv.getArgument(0); + return action.run(); + }); + + ClientResponse notModified = Mockito.mock(ClientResponse.class); + Mockito.when(notModified.getStatus()).thenReturn(304); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.any())).thenReturn(notModified); + + Assertions.assertNull(client.getServiceTagsIfUpdated(1L, 2L)); + + ArgumentCaptor url = ArgumentCaptor.forClass(String.class); + Mockito.verify(rest).get(url.capture(), Mockito.anyMap(), Mockito.any()); + Assertions.assertEquals("/service/tags/secure/download/svc", url.getValue()); + } + } + + @Test + public void test38_getUserStoreIfUpdated_secureMode_usesSecureUrl() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + UserGroupInformation ugi = Mockito.mock(UserGroupInformation.class); + try (MockedStatic misc = Mockito.mockStatic(MiscUtil.class); + MockedStatic ugiStatic = Mockito.mockStatic(UserGroupInformation.class)) { + misc.when(MiscUtil::getUGILoginUser).thenReturn(ugi); + ugiStatic.when(UserGroupInformation::isSecurityEnabled).thenReturn(true); + Mockito.when(ugi.hasKerberosCredentials()).thenReturn(true); + misc.when(() -> MiscUtil.executePrivilegedAction(Mockito.>any())) + .thenAnswer(inv -> { + PrivilegedExceptionAction action = inv.getArgument(0); + return action.run(); + }); + + ClientResponse notModified = Mockito.mock(ClientResponse.class); + Mockito.when(notModified.getStatus()).thenReturn(304); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.any())).thenReturn(notModified); + + Assertions.assertNull(client.getUserStoreIfUpdated(1L, 2L)); + + ArgumentCaptor url = ArgumentCaptor.forClass(String.class); + Mockito.verify(rest).get(url.capture(), Mockito.anyMap(), Mockito.any()); + Assertions.assertEquals("/service/xusers/secure/download/svc", url.getValue()); + } + } + + @Test + public void test39_getGdsInfoIfUpdated_secureMode_usesSecureUrl() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + UserGroupInformation ugi = Mockito.mock(UserGroupInformation.class); + try (MockedStatic misc = Mockito.mockStatic(MiscUtil.class); + MockedStatic ugiStatic = Mockito.mockStatic(UserGroupInformation.class)) { + misc.when(MiscUtil::getUGILoginUser).thenReturn(ugi); + ugiStatic.when(UserGroupInformation::isSecurityEnabled).thenReturn(true); + Mockito.when(ugi.hasKerberosCredentials()).thenReturn(true); + misc.when(() -> MiscUtil.executePrivilegedAction(Mockito.>any())) + .thenAnswer(inv -> { + PrivilegedExceptionAction action = inv.getArgument(0); + return action.run(); + }); + + ClientResponse notModified = Mockito.mock(ClientResponse.class); + Mockito.when(notModified.getStatus()).thenReturn(304); + Mockito.when(rest.get(Mockito.anyString(), Mockito.anyMap(), Mockito.any())).thenReturn(notModified); + + Assertions.assertNull(client.getGdsInfoIfUpdated(1L, 2L)); + + ArgumentCaptor url = ArgumentCaptor.forClass(String.class); + Mockito.verify(rest).get(url.capture(), Mockito.anyMap(), Mockito.any()); + Assertions.assertEquals("/service/gds/secure/download/svc", url.getValue()); + } + } + + @Test + public void test40_forceNonKerberos_disablesSecureMode_forRolesEndpoint() throws Exception { + RangerAdminRESTClient client = new RangerAdminRESTClient(); + Configuration cfg = new Configuration(false); + cfg.set("p.policy.rest.url", "http://localhost:6080"); + cfg.setBoolean("p.forceNonKerberos", true); + client.init("svc", "app", "p", cfg); + RangerRESTClient rest = Mockito.mock(RangerRESTClient.class); + setPrivateField(client, "restClient", rest); + + UserGroupInformation ugi = Mockito.mock(UserGroupInformation.class); + try (MockedStatic misc = Mockito.mockStatic(MiscUtil.class); + MockedStatic ugiStatic = Mockito.mockStatic(UserGroupInformation.class)) { + misc.when(MiscUtil::getUGILoginUser).thenReturn(ugi); + ugiStatic.when(UserGroupInformation::isSecurityEnabled).thenReturn(true); + + ArgumentCaptor url = ArgumentCaptor.forClass(String.class); + ClientResponse notModified = Mockito.mock(ClientResponse.class); + Mockito.when(notModified.getStatus()).thenReturn(304); + Mockito.when(rest.get(url.capture(), Mockito.anyMap(), Mockito.any())).thenReturn(notModified); + + Assertions.assertNull(client.getRolesIfUpdated(1L, 2L)); + Assertions.assertEquals("/service/roles/download/svc", url.getValue()); + } + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/admin/client/datatype/TestGrantRevokeData.java b/agents-common/src/test/java/org/apache/ranger/admin/client/datatype/TestGrantRevokeData.java new file mode 100644 index 0000000000..93dd801697 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/admin/client/datatype/TestGrantRevokeData.java @@ -0,0 +1,155 @@ +/* + * 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.ranger.admin.client.datatype; + +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** +* @generated by Cursor +* @description +*/ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestGrantRevokeData { + @Test + public void test01_setHiveData_setsDefaultsAndAddsPermMap() { + GrantRevokeData data = new GrantRevokeData(); + GrantRevokeData.PermMap pm = new GrantRevokeData.PermMap(); + pm.addUser("u1"); + pm.addGroup("g1"); + pm.addPerm("select"); + + data.setHiveData("grantor", "repo", null, null, null, pm); + + assertEquals("grantor", data.getGrantor()); + assertEquals("repo", data.getRepositoryName()); + assertEquals("hive", data.getRepositoryType()); + assertEquals("*", data.getDatabases()); + assertEquals("*", data.getTables()); + assertEquals("*", data.getColumns()); + assertEquals(1, data.getPermMapList().size()); + } + + @Test + public void test02_setHBaseData_setsDefaultsAndAddsPermMap() { + GrantRevokeData data = new GrantRevokeData(); + GrantRevokeData.PermMap pm = new GrantRevokeData.PermMap("u1", "g1", "RW"); + + data.setHBaseData("grantor", "repo", null, null, null, pm); + + assertEquals("grantor", data.getGrantor()); + assertEquals("repo", data.getRepositoryName()); + assertEquals("hbase", data.getRepositoryType()); + assertEquals("*", data.getTables()); + assertEquals("*", data.getColumns()); + assertEquals("*", data.getColumnFamilies()); + assertEquals(1, data.getPermMapList().size()); + } + + @Test + public void test03_permMap_copyConstructor_and_toJson() { + List users = new ArrayList<>(Arrays.asList("u1", "u2")); + List groups = new ArrayList<>(Arrays.asList("g1")); + List perms = new ArrayList<>(Arrays.asList("read")); + + GrantRevokeData.PermMap pm = new GrantRevokeData.PermMap(users, groups, perms); + assertEquals(2, pm.getUserList().size()); + assertEquals(1, pm.getGroupList().size()); + assertEquals(1, pm.getPermList().size()); + + String json = pm.toJson(); + assertNotNull(json); + } + + @Test + public void test04_toJson_containsRepositoryType() { + GrantRevokeData data = new GrantRevokeData(); + GrantRevokeData.PermMap pm = new GrantRevokeData.PermMap("u", "g", "p"); + data.setHiveData("grantor", "repo", "db", "tbl", "col", pm); + + String json = data.toJson(); + assertNotNull(json); + assertTrue(json.contains("\"repositoryType\":\"hive\"")); + } + + @Test + public void test05_permMap_addMethods_ignoreNullOrEmpty() throws Exception { + GrantRevokeData.PermMap pm = new GrantRevokeData.PermMap(); + pm.addUser(""); + pm.addUser(null); + pm.addGroup(""); + pm.addGroup(null); + pm.addPerm(""); + pm.addPerm(null); + assertTrue(pm.getUserList().isEmpty()); + assertTrue(pm.getGroupList().isEmpty()); + assertTrue(pm.getPermList().isEmpty()); + } + + @Test + public void test06_permMap_threeArgConstructor_populatesLists_and_toString() { + GrantRevokeData.PermMap pm = new GrantRevokeData.PermMap("uX", "gX", "pX"); + assertEquals(1, pm.getUserList().size()); + assertEquals("uX", pm.getUserList().get(0)); + assertEquals(1, pm.getGroupList().size()); + assertEquals("gX", pm.getGroupList().get(0)); + assertEquals(1, pm.getPermList().size()); + assertEquals("pX", pm.getPermList().get(0)); + assertNotNull(pm.toString()); + } + + @Test + public void test07_permMap_copyConstructor_ignoresNullAndEmpty() { + List users = new ArrayList<>(Arrays.asList("", null, "u1")); + List groups = new ArrayList<>(Arrays.asList(null, "", "g1")); + List perms = new ArrayList<>(Arrays.asList("", null, "p1")); + GrantRevokeData.PermMap pm = new GrantRevokeData.PermMap(users, groups, perms); + assertEquals(1, pm.getUserList().size()); + assertEquals("u1", pm.getUserList().get(0)); + assertEquals(1, pm.getGroupList().size()); + assertEquals("g1", pm.getGroupList().get(0)); + assertEquals(1, pm.getPermList().size()); + assertEquals("p1", pm.getPermList().get(0)); + } + + @Test + public void test08_setPermMapList_replacesList() { + GrantRevokeData data = new GrantRevokeData(); + GrantRevokeData.PermMap pm1 = new GrantRevokeData.PermMap("u1", "g1", "p1"); + GrantRevokeData.PermMap pm2 = new GrantRevokeData.PermMap("u2", "g2", "p2"); + List newList = new ArrayList<>(); + newList.add(pm1); + newList.add(pm2); + data.setPermMapList(newList); + assertEquals(2, data.getPermMapList().size()); + assertEquals("u2", data.getPermMapList().get(1).getUserList().get(0)); + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/admin/client/datatype/TestRESTResponse.java b/agents-common/src/test/java/org/apache/ranger/admin/client/datatype/TestRESTResponse.java new file mode 100644 index 0000000000..65ab06b873 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/admin/client/datatype/TestRESTResponse.java @@ -0,0 +1,150 @@ +/* + * 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.ranger.admin.client.datatype; + +import com.sun.jersey.api.client.ClientResponse; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @generated by Cursor + * @description + */ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestRESTResponse { + @Test + public void test01_toJson_and_fromJson_roundTrip() { + RESTResponse resp = new RESTResponse(); + resp.setHttpStatusCode(200); + resp.setStatusCode(RESTResponse.STATUS_SUCCESS); + resp.setMsgDesc("ok"); + resp.setMessageList(Collections.emptyList()); + + String json = resp.toJson(); + assertNotNull(json); + + RESTResponse parsed = RESTResponse.fromJson(json); + assertNotNull(parsed); + assertEquals(200, parsed.getHttpStatusCode()); + assertEquals(RESTResponse.STATUS_SUCCESS, parsed.getStatusCode()); + assertEquals("ok", parsed.getMsgDesc()); + } + + @Test + public void test02_fromJson_invalid_returnsNull() { + RESTResponse parsed = RESTResponse.fromJson("not-json"); + assertNull(parsed); + } + + @Test + public void test03_getMessage_usesMsgDescElseHttpStatus() { + RESTResponse r1 = new RESTResponse(); + r1.setHttpStatusCode(404); + r1.setMsgDesc("not found"); + assertEquals("not found", r1.getMessage()); + + RESTResponse r2 = new RESTResponse(); + r2.setHttpStatusCode(500); + assertEquals("HTTP 500", r2.getMessage()); + } + + @Test + public void test04_fromClientResponse_parsesBodyAndSetsStatus() { + ClientResponse clientResponse = mock(ClientResponse.class); + when(clientResponse.getStatus()).thenReturn(201); + when(clientResponse.getEntity(String.class)).thenReturn("{\"statusCode\":0,\"msgDesc\":\"done\"}"); + + RESTResponse resp = RESTResponse.fromClientResponse(clientResponse); + assertNotNull(resp); + assertEquals(201, resp.getHttpStatusCode()); + assertEquals(0, resp.getStatusCode()); + assertEquals("done", resp.getMsgDesc()); + } + + @Test + public void test05_fromClientResponse_nullResponse_createsDefault() { + RESTResponse resp = RESTResponse.fromClientResponse(null); + assertNotNull(resp); + assertEquals(0, resp.getHttpStatusCode()); + } + + @Test + public void test06_message_toJson_fromJson_roundTrip() { + RESTResponse.Message msg = new RESTResponse.Message(); + msg.setName("n"); + msg.setRbKey("k"); + msg.setMessage("m"); + msg.setObjectId(1L); + msg.setFieldName("f"); + + String json = msg.toJson(); + assertNotNull(json); + + RESTResponse parsed = RESTResponse.Message.fromJson("{\"messageList\":[{" + + "\"name\":\"n\",\"rbKey\":\"k\",\"message\":\"m\",\"objectId\":1,\"fieldName\":\"f\"}]} "); + assertNotNull(parsed); + } + + @Test + public void test07_toString_delegatesToToJson() { + RESTResponse resp = new RESTResponse(); + resp.setHttpStatusCode(202); + String s = resp.toString(); + assertNotNull(s); + assertEquals(resp.toJson(), s); + } + + @Test + public void test08_message_getters_and_toString() { + RESTResponse.Message msg = new RESTResponse.Message(); + msg.setName("nm"); + msg.setRbKey("rb"); + msg.setMessage("ms"); + msg.setObjectId(5L); + msg.setFieldName("fld"); + assertEquals("nm", msg.getName()); + assertEquals("rb", msg.getRbKey()); + assertEquals("ms", msg.getMessage()); + assertEquals(5L, msg.getObjectId().longValue()); + assertEquals("fld", msg.getFieldName()); + assertNotNull(msg.toString()); + } + + @Test + public void test09_fromClientResponse_emptyBody_setsOnlyStatus() { + ClientResponse clientResponse = mock(ClientResponse.class); + when(clientResponse.getStatus()).thenReturn(204); + when(clientResponse.getEntity(String.class)).thenReturn(""); + RESTResponse resp = RESTResponse.fromClientResponse(clientResponse); + assertNotNull(resp); + assertEquals(204, resp.getHttpStatusCode()); + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerAdminConfig.java b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerAdminConfig.java new file mode 100644 index 0000000000..54c7a56976 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerAdminConfig.java @@ -0,0 +1,51 @@ +/* + * 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.ranger.authorization.hadoop.config; + +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +/** +* @generated by Cursor +* @description +*/ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestRangerAdminConfig { + @Test + public void test01_getInstance_returnsSingleton() { + RangerAdminConfig c1 = RangerAdminConfig.getInstance(); + RangerAdminConfig c2 = RangerAdminConfig.getInstance(); + assertNotNull(c1); + assertSame(c1, c2); + } + + @Test + public void test02_isFipsEnabled_defaultsFalseWithoutConfig() { + RangerAdminConfig cfg = RangerAdminConfig.getInstance(); + assertFalse(cfg.isFipsEnabled()); + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerAuditConfig.java b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerAuditConfig.java new file mode 100644 index 0000000000..1932959553 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerAuditConfig.java @@ -0,0 +1,55 @@ +/* + * 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.ranger.authorization.hadoop.config; + +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertFalse; + +/** +* @generated by Cursor +* @description +*/ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestRangerAuditConfig { + @Test + public void test01_defaultConstructor_callsServiceNameStandalone() { + RangerAuditConfig conf = new RangerAuditConfig(); + // No test resources exist; expect false + assertFalse(conf.isInitSuccess()); + } + + @Test + public void test02_paramConstructor_withNonExistingService_returnsFalse() { + RangerAuditConfig conf = new RangerAuditConfig("nonexistent-service-xyz"); + assertFalse(conf.isInitSuccess()); + } + + @Test + public void test03_paramConstructor_withLikelyMissingConfig_returnsFalse() { + RangerAuditConfig conf = new RangerAuditConfig("hdfs"); + // in this workspace we don't have ranger-hdfs-audit.xml on classpath + assertFalse(conf.isInitSuccess()); + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerChainedPluginConfig.java b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerChainedPluginConfig.java new file mode 100644 index 0000000000..606ab3a020 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerChainedPluginConfig.java @@ -0,0 +1,69 @@ +/* + * 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.ranger.authorization.hadoop.config; + +import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** +* @generated by Cursor +* @description +*/ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestRangerChainedPluginConfig { + @Test + public void test01_copiesPropertiesWithNewPrefix_andExcludesNonChained() { + RangerPluginConfig base = new RangerPluginConfig("hdfs", "baseSvc", "app", null, null, null); + String basePrefix = base.getPropertyPrefix(); + + base.set(basePrefix + ".prop1", "v1"); + base.set(basePrefix + ".chained.services", "svcA,svcB"); + base.set("xasecure.policymgr.clientssl.keystore", "ks"); + + RangerChainedPluginConfig chained = new RangerChainedPluginConfig("hive", "hiveSvc", "app2", base); + + String chainedPrefix = chained.getPropertyPrefix(); + // copied + assertEquals("v1", chained.get(chainedPrefix + ".prop1")); + // chained property is intentionally NOT copied in copyProperties, and only copied if already present with the new prefix in source; expect null here + assertNull(chained.get(chainedPrefix + ".chained.services")); + // legacy ssl copied + assertEquals("ks", chained.get("xasecure.policymgr.clientssl.keystore")); + // service.name overridden to new service + assertEquals("hiveSvc", chained.get(chainedPrefix + ".service.name")); + } + + @Test + public void test02_toString_containsClassNameAndProperties() { + RangerPluginConfig base = new RangerPluginConfig("hdfs", "baseSvc", "app", null, null, (RangerPolicyEngineOptions) null); + RangerChainedPluginConfig chained = new RangerChainedPluginConfig("hive", "hiveSvc", "app2", base); + String s = chained.toString(); + assertTrue(s.contains("RangerChainedPluginConfig")); + assertTrue(s.contains("propertyName:")); + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerConfigConstants.java b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerConfigConstants.java new file mode 100644 index 0000000000..b6698dd062 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerConfigConstants.java @@ -0,0 +1,45 @@ +/* + * 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.ranger.authorization.hadoop.config; + +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.lang.reflect.Constructor; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @generated by Cursor + * @description + */ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestRangerConfigConstants { + @Test + public void test01_privateConstructor_isInaccessibleButInvokableViaReflection() throws Exception { + Constructor c = RangerConfigConstants.class.getDeclaredConstructor(); + c.setAccessible(true); + Object o = c.newInstance(); + assertTrue(o instanceof RangerConfigConstants); + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerConfiguration.java b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerConfiguration.java new file mode 100644 index 0000000000..0ad9efd7dc --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerConfiguration.java @@ -0,0 +1,97 @@ +/* + * 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.ranger.authorization.hadoop.config; + +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** +* @generated by Cursor +* @description +*/ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestRangerConfiguration { + public static class ThrowingAddResourceConfig extends RangerConfiguration { + @Override + public void addResource(URL url) { + throw new RuntimeException("forced failure"); + } + } + + @Test + public void test01_addResourceIfReadable_nonExisting_returnsFalse() { + RangerConfiguration conf = new RangerConfiguration(); + + boolean added = conf.addResourceIfReadable("file-does-not-exist-12345.xml"); + + assertFalse(added); + } + + @Test + public void test02_addResourceIfReadable_existingFile_returnsTrue_andLoadsProperty() throws Exception { + RangerConfiguration conf = new RangerConfiguration(); + + Path tmp = Files.createTempFile("ranger-config-", ".xml"); + String xml = "\n" + + " \n" + + " test.key\n" + + " testValue\n" + + " \n" + + "\n"; + Files.write(tmp, xml.getBytes(StandardCharsets.UTF_8)); + + boolean added = conf.addResourceIfReadable(tmp.toFile().getAbsolutePath()); + + assertTrue(added); + assertEquals("testValue", conf.get("test.key")); + } + + @Test + public void test03_addResourceIfReadable_whenAddResourceThrows_returnsFalse() throws Exception { + ThrowingAddResourceConfig conf = new ThrowingAddResourceConfig(); + + Path tmp = Files.createTempFile("ranger-config-throw-", ".xml"); + String xml = ""; + Files.write(tmp, xml.getBytes(StandardCharsets.UTF_8)); + + boolean added = conf.addResourceIfReadable(tmp.toFile().getAbsolutePath()); + + assertFalse(added); + } + + @Test + public void test04_getProperties_returnsNotNull() { + RangerConfiguration conf = new RangerConfiguration(); + assertNotNull(conf.getProperties()); + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerLegacyConfigBuilder.java b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerLegacyConfigBuilder.java new file mode 100644 index 0000000000..831a514cfa --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerLegacyConfigBuilder.java @@ -0,0 +1,174 @@ +/* + * 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.ranger.authorization.hadoop.config; + +import org.apache.hadoop.conf.Configuration; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.URL; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** +* @generated by Cursor +* @description +*/ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestRangerLegacyConfigBuilder { + @Test + public void test01_getPropertyName_replacesPlaceholder() { + String prop = RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.RANGER_SERVICE_NAME, "hdfs"); + assertEquals("ranger.plugin.hdfs.service.name", prop); + } + + @Test + public void test02_getPolicyMgrURL_extractsBase() { + String url = "http://host:6080/service/public/v2/api/service/name"; + String base = RangerLegacyConfigBuilder.getPolicyMgrURL(url); + assertEquals("http://host:6080", base); + } + + @Test + public void test03_getServiceNameFromURL_extractsName() { + String url = "http://host:6080/service/public/v2/api/service/myservice"; + assertEquals("myservice", RangerLegacyConfigBuilder.getServiceNameFromURL(url)); + } + + @Test + public void test04_getCacheFileURL_parentDir() { + assertEquals("/var/cache/ranger", RangerLegacyConfigBuilder.getCacheFileURL("/var/cache/ranger/policies.json")); + } + + @Test + public void test05_buildRangerSecurityConf_knoxGetsDefaultImpl() { + Configuration conf = RangerLegacyConfigBuilder.buildRangerSecurityConf("knox"); + String key = RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.RANGER_PLUGIN_POLICY_SOURCE_IMPL, "knox"); + assertEquals("org.apache.ranger.admin.client.RangerAdminJersey2RESTClient", conf.get(key)); + } + + @Test + public void test06_buildRangerSecurityConf_nonKnoxEmptyImpl() { + Configuration conf = RangerLegacyConfigBuilder.buildRangerSecurityConf("hdfs"); + String key = RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.RANGER_PLUGIN_POLICY_SOURCE_IMPL, "hdfs"); + assertEquals("", conf.get(key)); + } + + @Test + public void test07_getConfigChangeMap_containsExpectedKeys() { + assertTrue(RangerLegacyConfigBuilder.getConfigChangeMap("hdfs").size() >= 4); + } + + @Test + public void test08_getFileURL_unknownResource_null() { + URL url = RangerLegacyConfigBuilder.getFileURL("this-file-definitely-does-not-exist-xyz.txt"); + assertNull(url); + } + + @Test + public void test09_fetchLegacyValue_behaviors() throws Exception { + // set static serviceType used by fetchLegacyValue + Field f = RangerLegacyConfigBuilder.class.getDeclaredField("serviceType"); + f.setAccessible(true); + f.set(null, "hdfs"); + String serviceNameKey = RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.RANGER_SERVICE_NAME, "hdfs"); + String restUrlKey = RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.RANGER_PLUGIN_POLICY_REST_URL, "hdfs"); + String cacheDirKey = RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.RANGER_PLUGIN_POLICY_CACHE_DIR, "hdfs"); + + assertEquals("svc", RangerLegacyConfigBuilder.fetchLegacyValue("http://host:6080/service/public/rest/svc", serviceNameKey)); + assertEquals("http://host:6080", RangerLegacyConfigBuilder.fetchLegacyValue("http://host:6080/service/public/rest/svc", restUrlKey)); + assertEquals("/var/cache/ranger", RangerLegacyConfigBuilder.fetchLegacyValue("/var/cache/ranger/policies.json", cacheDirKey)); + } + + @Test + public void test10_getSecurityConfig_returnsNullWhenLegacyNotFound() { + Configuration cfg = RangerLegacyConfigBuilder.getSecurityConfig("nonexistent-svc"); + assertNull(cfg); + } + + @Test + public void test11_getAuditConfig_returnsNullIfNoSiteFiles() throws Throwable { + URL url = RangerLegacyConfigBuilder.getAuditConfig("hdfs"); + // in unit test env, hive/hbase/hdfs site files are not present; should return null + assertNull(url); + } + + @Test + public void test12_getConfigChangeMap_specificMappingsForHdfsAndHbase() { + // HDFS adds XASECURE_ADD_HADDOP_AUTHORZATION -> RANGER_PLUGIN_ADD_HADDOOP_AUTHORIZATION + assertTrue(RangerLegacyConfigBuilder.getConfigChangeMap("hdfs").containsKey(RangerConfigConstants.XASECURE_ADD_HADDOP_AUTHORZATION)); + assertEquals(RangerConfigConstants.RANGER_PLUGIN_ADD_HADDOOP_AUTHORIZATION, + RangerLegacyConfigBuilder.getConfigChangeMap("hdfs").get(RangerConfigConstants.XASECURE_ADD_HADDOP_AUTHORZATION)); + + // HBase adds update grant mapping + String hbaseLegacy = RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.XASECURE_UPDATE_XAPOLICIES_ON_GRANT, "hbase"); + String hbaseRanger = RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.XASECURE_UPDATE_XAPOLICIES_ON_GRANT, "hbase"); + assertEquals(hbaseRanger, RangerLegacyConfigBuilder.getConfigChangeMap("hbase").get(hbaseLegacy)); + } + + @Test + public void test13_fetchLegacyValue_unmatchedKey_returnsNull() { + String unmatchedKey = "some.random.key"; + assertNull(RangerLegacyConfigBuilder.fetchLegacyValue("value", unmatchedKey)); + } + + @Test + public void test14_mapLegacyConfigToRanger_appliesTransforms_viaReflection() throws Exception { + // Ensure static serviceType used by mapLegacyConfigToRanger is set + Field f = RangerLegacyConfigBuilder.class.getDeclaredField("serviceType"); + f.setAccessible(true); + f.set(null, "hdfs"); + + Configuration legacy = new Configuration(); + String legacyUrlKey = RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.XASECURE_POLICYMGR_URL, "hdfs"); + String legacyCacheKey = RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.XASECURE_POLICYMGR_URL_LASTSTOREDFILE, "hdfs"); + String legacyReload = RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.XASECURE_POLICYMGR_GRL_RELOADINTERVALINMILLIS, "hdfs"); + legacy.set(legacyUrlKey, "http://host:6080/service/public/rest/svc"); + legacy.set(legacyCacheKey, "/var/cache/ranger/policies.json"); + legacy.set(legacyReload, "5000"); + legacy.set(RangerConfigConstants.XASECURE_ADD_HADDOP_AUTHORZATION, "true"); + + Configuration rangerIn = new Configuration(); + + Method m = RangerLegacyConfigBuilder.class.getDeclaredMethod("mapLegacyConfigToRanger", Configuration.class, Configuration.class); + m.setAccessible(true); + Configuration out = (Configuration) m.invoke(null, rangerIn, legacy); + + assertNotNull(out); + assertEquals("svc", out.get(RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.RANGER_SERVICE_NAME, "hdfs"))); + assertEquals("http://host:6080", out.get(RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.RANGER_PLUGIN_POLICY_REST_URL, "hdfs"))); + assertEquals("/var/cache/ranger", out.get(RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.RANGER_PLUGIN_POLICY_CACHE_DIR, "hdfs"))); + assertEquals("5000", out.get(RangerLegacyConfigBuilder.getPropertyName(RangerConfigConstants.RANGER_PLUGIN_POLICY_POLLINVETERVALMS, "hdfs"))); + assertEquals("true", out.get(RangerConfigConstants.RANGER_PLUGIN_ADD_HADDOOP_AUTHORIZATION)); + } + + @Test + public void test15_getFileLocation_unknownReturnsNull() { + assertNull(RangerLegacyConfigBuilder.getFileLocation("definitely-not-present-xyz.xml")); + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerPluginConfig.java b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerPluginConfig.java new file mode 100644 index 0000000000..296f6ff846 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/authorization/hadoop/config/TestRangerPluginConfig.java @@ -0,0 +1,157 @@ +/* + * 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.ranger.authorization.hadoop.config; + +import org.apache.ranger.plugin.policyengine.RangerPolicyEngineOptions; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.File; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** +* @generated by Cursor +* @description +*/ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestRangerPluginConfig { + @Test + public void test01_constructor_setsDefaults_andPolicyOptionsConfigured() { + RangerPluginConfig cfg = new RangerPluginConfig("hdfs", null, null, null, null, (List) null, null); + + assertEquals("hdfs", cfg.getServiceType()); + assertEquals("hdfs", cfg.getAppId()); + assertEquals("ranger.plugin.hdfs", cfg.getPropertyPrefix()); + assertNotNull(cfg.getPolicyEngineOptions()); + } + + @Test + public void test02_constructor_serviceNameFromConfig_whenNullInCtor() throws Exception { + // create a temp config file that sets service name property + Path tmp = Files.createTempFile("ranger-plugin-", ".xml"); + String key = "ranger.plugin.hdfs.service.name"; + String xml = "\n" + + " \n" + + " " + key + "\n" + + " svcA\n" + + " \n" + + "\n"; + Files.write(tmp, xml.getBytes(StandardCharsets.UTF_8)); + + List files = new ArrayList<>(); + files.add(tmp.toFile()); + + RangerPluginConfig cfg = new RangerPluginConfig("hdfs", null, null, null, null, files, null); + + assertNull(cfg.getServiceName()); + assertEquals("svcA", cfg.get(key)); + } + + @Test + public void test03_constructor_clusterName_clusterType_resolution() { + RangerPluginConfig cfg = new RangerPluginConfig("hdfs", "svc", null, null, null, (List) null, null); + + assertEquals("", cfg.getClusterName()); + assertEquals("", cfg.getClusterType()); + } + + @Test + public void test04_xForwardedAndTrustedProxy_parsing_andWarnings() { + // Provide a config file enabling forwarded IP and a list of proxies + Path tmp; + try { + tmp = Files.createTempFile("ranger-plugin-ip-", ".xml"); + String prefix = "ranger.plugin.hdfs"; + String xml = "\n" + + " " + prefix + ".use.x-forwarded-for.ipaddresstrue\n" + + " " + prefix + ".trusted.proxy.ipaddresses10.0.0.1, 10.0.0.2\n" + + "\n"; + Files.write(tmp, xml.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + throw new RuntimeException(e); + } + List files = new ArrayList<>(); + files.add(tmp.toFile()); + + RangerPluginConfig cfg = new RangerPluginConfig("hdfs", "svc", null, null, null, files, null); + + assertTrue(cfg.isUseForwardedIPAddress()); + assertArrayEquals(new String[] {"10.0.0.1", "10.0.0.2"}, cfg.getTrustedProxyAddresses()); + } + + @Test + public void test05_policyEngineOptions_providedIsUsed() { + RangerPolicyEngineOptions opts = new RangerPolicyEngineOptions(); + RangerPluginConfig cfg = new RangerPluginConfig("hdfs", "svc", "app", "cln", "clt", Collections.emptyList(), opts); + assertSame(opts, cfg.getPolicyEngineOptions()); + } + + @Test + public void test06_auditAndSuperUsersGroupsRoles_apis() { + RangerPluginConfig cfg = new RangerPluginConfig("hdfs", "svc", null, null, null, (List) null, null); + + Set users = new HashSet<>(Arrays.asList("u1", "u2")); + Set groups = new HashSet<>(Arrays.asList("g1", "g2")); + Set roles = new HashSet<>(Arrays.asList("r1")); + cfg.setAuditExcludedUsersGroupsRoles(users, groups, roles); + + assertTrue(cfg.isAuditExcludedUser("u1")); + assertTrue(cfg.hasAuditExcludedGroup(new HashSet<>(Arrays.asList("g2")))); + assertTrue(cfg.hasAuditExcludedRole(new HashSet<>(Arrays.asList("r1", "r2")))); + + cfg.setSuperUsersGroups(new HashSet<>(Arrays.asList("su1")), new HashSet<>(Arrays.asList("sg1"))); + assertTrue(cfg.isSuperUser("su1")); + assertTrue(cfg.hasSuperGroup(new HashSet<>(Arrays.asList("sg1", "sgX")))); + + cfg.setServiceAdmins(new HashSet<>(Arrays.asList("admin1"))); + assertTrue(cfg.isServiceAdmin("admin1")); + + cfg.addSuperUsers(new ArrayList<>(Arrays.asList("su2"))); + assertTrue(cfg.isSuperUser("su2")); + } + + @Test + public void test07_getSSLConfigResource_returnsNullForMissingFile() throws Exception { + RangerPluginConfig cfg = new RangerPluginConfig("hdfs", "svc", null, null, null, (List) null, null); + Method m = RangerPluginConfig.class.getDeclaredMethod("getSSLConfigResource", String.class); + m.setAccessible(true); + Object ret = m.invoke(cfg, "file-that-does-not-exist-xyz.txt"); + assertNull(ret); + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/authorization/utils/TestJsonUtils.java b/agents-common/src/test/java/org/apache/ranger/authorization/utils/TestJsonUtils.java new file mode 100644 index 0000000000..13abf98040 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/authorization/utils/TestJsonUtils.java @@ -0,0 +1,222 @@ +/* + * 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.ranger.authorization.utils; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.ranger.plugin.model.AuditFilter; +import org.apache.ranger.plugin.model.RangerGds.RangerGdsMaskInfo; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemDataMaskInfo; +import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; +import org.apache.ranger.plugin.model.RangerPrincipal; +import org.apache.ranger.plugin.model.RangerPrincipal.PrincipalType; +import org.apache.ranger.plugin.model.RangerTag; +import org.apache.ranger.plugin.model.RangerValidityRecurrence; +import org.apache.ranger.plugin.model.RangerValidityRecurrence.RecurrenceSchedule; +import org.apache.ranger.plugin.model.RangerValidityRecurrence.ValidityInterval; +import org.apache.ranger.plugin.model.RangerValiditySchedule; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** +* @generated by Cursor +* @description +*/ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestJsonUtils { + @Test + public void test01_getMapperConfiguration() { + ObjectMapper mapper = JsonUtils.getMapper(); + Assertions.assertNotNull(mapper); + // Verify custom date format set via configuration + Assertions.assertNotNull(mapper.getDateFormat()); + } + + @Test + public void test02_mapListSetObjectToJson_successAndEmpty() { + Map map = new HashMap<>(); + map.put("k", "v"); + String mapJson = JsonUtils.mapToJson(map); + Assertions.assertEquals("{\"k\":\"v\"}", mapJson); + + List list = Arrays.asList("a", "b"); + String listJson = JsonUtils.listToJson(list); + Assertions.assertEquals("[\"a\",\"b\"]", listJson); + + Set set = new HashSet<>(Arrays.asList("x", "y")); + String setJson = JsonUtils.setToJson(set); + Assertions.assertTrue(setJson.contains("x")); + Assertions.assertTrue(setJson.contains("y")); + + String objJson = JsonUtils.objectToJson(new RangerPrincipal(PrincipalType.USER, "alice")); + Assertions.assertTrue(objJson.contains("alice")); + + Assertions.assertNull(JsonUtils.mapToJson(null)); + Assertions.assertNull(JsonUtils.listToJson(new ArrayList<>())); + Assertions.assertNull(JsonUtils.setToJson(new HashSet<>())); + Assertions.assertNull(JsonUtils.objectToJson(null)); + } + + @Test + public void test03_jsonToObject_withReaderAndWriter_andClass() { + RangerPrincipal in = new RangerPrincipal(PrincipalType.ROLE, "analyst"); + String json = JsonUtils.objectToJson(in); + Writer w = new StringWriter(); + JsonUtils.objectToWriter(w, in); + String serialized = w.toString(); + Assertions.assertTrue(serialized.contains("analyst")); + + Reader r = new StringReader(json); + RangerPrincipal out = JsonUtils.jsonToObject(r, RangerPrincipal.class); + Assertions.assertEquals(in, out); + + // null safety + Assertions.assertNull(JsonUtils.jsonToObject((Reader) null, RangerPrincipal.class)); + JsonUtils.objectToWriter(null, in); // should not throw + } + + @Test + public void test04_jsonToObject_withTypeReference_andBranching() throws Exception { + Map m = new HashMap<>(); + m.put("a", 1); + String json = JsonUtils.objectToJson(m); + Map out = JsonUtils.jsonToObject(json, new TypeReference>() { + }); + Assertions.assertEquals(1, out.get("a").intValue()); + + Assertions.assertNull(JsonUtils.jsonToObject((String) null, new TypeReference>() { + })); + } + + @Test + public void test05_jsonToPrimitivesCollectionsHelpers() { + Assertions.assertNull(JsonUtils.jsonToMapStringString(null)); + Assertions.assertNull(JsonUtils.jsonToSetString(null)); + Assertions.assertNull(JsonUtils.jsonToListString(null)); + + String mapJson = "{\"k\":\"v\"}"; + Map map = JsonUtils.jsonToMapStringString(mapJson); + Assertions.assertEquals("v", map.get("k")); + + String setJson = "[\"u\",\"v\"]"; + Set set = JsonUtils.jsonToSetString(setJson); + Assertions.assertTrue(set.contains("u")); + Assertions.assertTrue(set.contains("v")); + + String listJson = "[\"p\",\"q\"]"; + List list = JsonUtils.jsonToListString(listJson); + Assertions.assertEquals(Arrays.asList("p", "q"), list); + } + + @Test + public void test06_jsonToValidityAndAuditRelatedHelpers_success() { + RangerValiditySchedule sched = new RangerValiditySchedule(); + sched.setTimeZone("UTC"); + sched.setStartTime("2020/01/01 00:00:00"); + sched.setEndTime("2025/01/01 00:00:00"); + RangerValidityRecurrence rec = new RangerValidityRecurrence(); + RecurrenceSchedule rs = new RecurrenceSchedule("0", "*", "*", "*", "*", "*"); + rec.setSchedule(rs); + rec.setInterval(new ValidityInterval(0, 1, 0)); + sched.setRecurrences(Arrays.asList(rec)); + String schedJson = JsonUtils.objectToJson(Arrays.asList(sched)); + List backSched = JsonUtils.jsonToRangerValiditySchedule(schedJson); + Assertions.assertEquals(1, backSched.size()); + + AuditFilter af = new AuditFilter(); + af.setAccessTypes(Arrays.asList("read")); + Map res = new HashMap<>(); + res.put("database", new RangerPolicyResource("db1")); + af.setResources(res); + String afJson = JsonUtils.objectToJson(Arrays.asList(af)); + List backAF = JsonUtils.jsonToAuditFilterList(afJson); + Assertions.assertEquals(1, backAF.size()); + + RangerValidityRecurrence rr = new RangerValidityRecurrence(rs, new ValidityInterval(0, 0, 30)); + String rrJson = JsonUtils.objectToJson(Arrays.asList(rr)); + List backRR = JsonUtils.jsonToRangerValidityRecurringSchedule(rrJson); + Assertions.assertEquals(1, backRR.size()); + + RangerPrincipal p = new RangerPrincipal(PrincipalType.USER, "bob"); + String pJson = JsonUtils.objectToJson(Arrays.asList(p)); + List backP = JsonUtils.jsonToRangerPrincipalList(pJson); + Assertions.assertEquals(1, backP.size()); + + RangerTag tag = new RangerTag("guid-1", "PII", new HashMap() { + { + put("level", "high"); + } + }, RangerTag.OWNER_SERVICERESOURCE); + String tagJson = JsonUtils.objectToJson(Arrays.asList(tag)); + List backTag = JsonUtils.jsonToRangerTagList(tagJson); + Assertions.assertEquals(1, backTag.size()); + } + + @Test + public void test07_jsonToGdsMaskInfoAndPolicyResource_success() { + RangerGdsMaskInfo mi = new RangerGdsMaskInfo(); + mi.setValues(Arrays.asList("col1")); + mi.setMaskInfo(new RangerPolicyItemDataMaskInfo("MASK", null, null)); + String miJson = JsonUtils.objectToJson(Arrays.asList(mi)); + List backMi = JsonUtils.jsonToListGdsMaskInfo(miJson); + Assertions.assertEquals(1, backMi.size()); + + Map m = new HashMap<>(); + m.put("table", new RangerPolicyResource("t1")); + String mJson = JsonUtils.objectToJson(m); + Map backM = JsonUtils.jsonToMapPolicyResource(mJson); + Assertions.assertTrue(backM.containsKey("table")); + Assertions.assertEquals("t1", backM.get("table").getValues().get(0)); + } + + @Test + public void test08_errorPaths_returnNullAndLogging() { + // invalid JSON strings should not throw and should return null + Assertions.assertNull(JsonUtils.jsonToMapStringString("{invalid}")); + Assertions.assertNull(JsonUtils.jsonToSetString("{invalid}")); + Assertions.assertNull(JsonUtils.jsonToListString("{invalid}")); + Assertions.assertNull(JsonUtils.jsonToRangerValiditySchedule("{invalid}")); + Assertions.assertNull(JsonUtils.jsonToAuditFilterList("{invalid}")); + Assertions.assertNull(JsonUtils.jsonToRangerValidityRecurringSchedule("{invalid}")); + Assertions.assertNull(JsonUtils.jsonToRangerPrincipalList("{invalid}")); + Assertions.assertNull(JsonUtils.jsonToRangerTagList("{invalid}")); + Assertions.assertNull(JsonUtils.jsonToListGdsMaskInfo("{invalid}")); + Assertions.assertNull(JsonUtils.jsonToMapPolicyResource("{invalid}")); + + Assertions.assertNull(JsonUtils.jsonToObject("{invalid}", RangerPrincipal.class)); + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/authorization/utils/TestStringUtil.java b/agents-common/src/test/java/org/apache/ranger/authorization/utils/TestStringUtil.java index dd21e9dc26..a6f09e554b 100644 --- a/agents-common/src/test/java/org/apache/ranger/authorization/utils/TestStringUtil.java +++ b/agents-common/src/test/java/org/apache/ranger/authorization/utils/TestStringUtil.java @@ -24,22 +24,33 @@ import org.apache.ranger.plugin.model.RangerSecurityZone; import org.apache.ranger.plugin.model.RangerSecurityZone.RangerSecurityZoneService; import org.apache.ranger.plugin.util.RangerSecurityZoneHelper; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +/** +* @generated by Cursor +* @description +*/ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) public class TestStringUtil { - public static Map mapFromStrings(String...args) { + public static Map mapFromStrings(String... args) { Map ret = new HashMap<>(); if (args != null) { @@ -54,12 +65,12 @@ public static Map mapFromStrings(String...args) { return ret; } - public static HashMap> mapFromStringStringList(Object...args) { + public static HashMap> mapFromStringStringList(Object... args) { HashMap> ret = new HashMap<>(); if (args != null) { for (int i = 0; i < args.length; i += 2) { - String key = (String) args[i]; + String key = (String) args[i]; List val = (args.length > (i + 1)) ? ((List) args[i + 1]) : null; ret.put(key, val); @@ -72,101 +83,101 @@ public static HashMap> mapFromStringStringList(Object...arg @Test public void testDedupString() { Map strTbl = new HashMap<>(); - String s1 = getString("database"); - String s2 = getString("database"); + String s1 = getString("database"); + String s2 = getString("database"); // s1 and s2 point to different instances of String - Assert.assertNotSame("s1 != s2", s1, s2); + Assertions.assertNotSame(s1, s2); // strTbl doesn't have s1; dedupString(s1) should return s1 - Assert.assertSame("s1 == dedupString(s1)", s1, StringUtil.dedupString(s1, strTbl)); + Assertions.assertSame(s1, StringUtil.dedupString(s1, strTbl)); // strTbl now has s1; s2 has same value as s1, hence dedupString() should return s1 - Assert.assertSame("s1 == dedupString(s2)", s1, StringUtil.dedupString(s2, strTbl)); + Assertions.assertSame(s1, StringUtil.dedupString(s2, strTbl)); } @Test public void testDedupStringsList() { Map strTbl = new HashMap<>(); - List l1 = null; + List l1 = null; - Assert.assertSame("null list - dedupStringsList() should return the same list", l1, StringUtil.dedupStringsList(l1, strTbl)); + Assertions.assertSame(l1, StringUtil.dedupStringsList(l1, strTbl)); l1 = Collections.emptyList(); - Assert.assertSame("empty list - dedupStringsList() should return the same list", l1, StringUtil.dedupStringsList(l1, strTbl)); + Assertions.assertSame(l1, StringUtil.dedupStringsList(l1, strTbl)); l1 = new ArrayList<>(); - Assert.assertSame("empty list - dedupStringsList() should return the same list", l1, StringUtil.dedupStringsList(l1, strTbl)); + Assertions.assertSame(l1, StringUtil.dedupStringsList(l1, strTbl)); l1 = new ArrayList<>(Collections.singletonList("*")); - Assert.assertNotSame("non-empty list - dedupStringsList() should return a new list", l1, StringUtil.dedupStringsList(l1, strTbl)); + Assertions.assertNotSame(l1, StringUtil.dedupStringsList(l1, strTbl)); l1 = new ArrayList<>(Arrays.asList(getString("*"), getString("db1"))); - Assert.assertNotSame("non-empty list - dedupStringsList() should return a new list", l1, StringUtil.dedupStringsList(l1, strTbl)); + Assertions.assertNotSame(l1, StringUtil.dedupStringsList(l1, strTbl)); List l2 = new ArrayList<>(Arrays.asList(getString("*"), getString("db1"))); for (int i = 0; i < l1.size(); i++) { - Assert.assertNotSame("Before dedupStringsList(): l1[" + i + "] == l2[" + i + "]", l1.get(i), l2.get(i)); + Assertions.assertNotSame(l1.get(i), l2.get(i)); } l1 = StringUtil.dedupStringsList(l1, strTbl); l2 = StringUtil.dedupStringsList(l2, strTbl); for (int i = 0; i < l1.size(); i++) { - Assert.assertSame("After dedupStringsList(): l1[" + i + "] == l2[" + i + "]", l1.get(i), l2.get(i)); + Assertions.assertSame(l1.get(i), l2.get(i)); } } @Test public void testDedupStringsSet() { Map strTbl = new HashMap<>(); - Set s1 = null; + Set s1 = null; - Assert.assertSame("null set - dedupStringsList() should return the same set", s1, StringUtil.dedupStringsSet(s1, strTbl)); + Assertions.assertSame(s1, StringUtil.dedupStringsSet(s1, strTbl)); s1 = Collections.emptySet(); - Assert.assertSame("empty set - dedupStringsSet() should return the same set", s1, StringUtil.dedupStringsSet(s1, strTbl)); + Assertions.assertSame(s1, StringUtil.dedupStringsSet(s1, strTbl)); s1 = new HashSet<>(); - Assert.assertSame("empty set - dedupStringsSet() should return the same set", s1, StringUtil.dedupStringsSet(s1, strTbl)); + Assertions.assertSame(s1, StringUtil.dedupStringsSet(s1, strTbl)); s1 = new HashSet<>(Collections.singletonList(getString("*"))); - Assert.assertNotSame("non-empty set - dedupStringsSet() should return a new set", s1, StringUtil.dedupStringsSet(s1, strTbl)); + Assertions.assertNotSame(s1, StringUtil.dedupStringsSet(s1, strTbl)); s1 = new HashSet<>(Arrays.asList(getString("*"), getString("db1"))); - Assert.assertNotSame("non-empty set - dedupStringsSet() should return a new set", s1, StringUtil.dedupStringsSet(s1, strTbl)); + Assertions.assertNotSame(s1, StringUtil.dedupStringsSet(s1, strTbl)); Set s2 = new HashSet<>(Arrays.asList(getString("*"), getString("db1"))); for (String elem : s1) { - Assert.assertFalse("Before dedupStringsSet(): s1[" + elem + "] == s2[" + elem + "]", containsInstance(s2, elem)); + Assertions.assertFalse(containsInstance(s2, elem)); } s1 = StringUtil.dedupStringsSet(s1, strTbl); s2 = StringUtil.dedupStringsSet(s2, strTbl); for (String elem : s1) { - Assert.assertTrue("After dedupStringsSet(): s1[" + elem + "] == s2[" + elem + "]", containsInstance(s2, elem)); + Assertions.assertTrue(containsInstance(s2, elem)); } } @Test public void testDedupStringsMap() { Map strTbl = new HashMap<>(); - Map m1 = null; + Map m1 = null; - Assert.assertSame("null map - dedupStringsMap() should return the same map", m1, StringUtil.dedupStringsMap(m1, strTbl)); + Assertions.assertSame(m1, StringUtil.dedupStringsMap(m1, strTbl)); m1 = Collections.emptyMap(); - Assert.assertSame("empty map - dedupStringsMap() should return the same map", m1, StringUtil.dedupStringsMap(m1, strTbl)); + Assertions.assertSame(m1, StringUtil.dedupStringsMap(m1, strTbl)); m1 = new HashMap<>(); - Assert.assertSame("empty map - dedupStringsMap() should return the same map", m1, StringUtil.dedupStringsMap(m1, strTbl)); + Assertions.assertSame(m1, StringUtil.dedupStringsMap(m1, strTbl)); m1 = new HashMap<>(); m1.put(getString("database"), getString("*")); - Assert.assertNotSame("non-empty map - dedupStringsMap() should return a new map", m1, StringUtil.dedupStringsMap(m1, strTbl)); + Assertions.assertNotSame(m1, StringUtil.dedupStringsMap(m1, strTbl)); Map m2 = new HashMap<>(); m2.put(getString("database"), getString("*")); @@ -174,8 +185,8 @@ public void testDedupStringsMap() { for (Map.Entry entry : m1.entrySet()) { String key = entry.getKey(); - Assert.assertFalse("Before dedupStringsMap(): m2 has same key as m1", containsInstance(m2.keySet(), key)); - Assert.assertNotSame("Before dedupStringsMap(): m1[" + key + "] == l2[" + key + "]", m1.get(key), m2.get(key)); + Assertions.assertFalse(containsInstance(m2.keySet(), key)); + Assertions.assertNotSame(m1.get(key), m2.get(key)); } m1 = StringUtil.dedupStringsMap(m1, strTbl); @@ -184,42 +195,42 @@ public void testDedupStringsMap() { for (Map.Entry entry : m1.entrySet()) { String key = entry.getKey(); - Assert.assertTrue("After dedupStringsMap(): m2 has same key as m1", containsInstance(m2.keySet(), key)); - Assert.assertSame("After dedupStringsMap(): m1[" + key + "] == l2[" + key + "]", m1.get(key), m2.get(key)); + Assertions.assertTrue(containsInstance(m2.keySet(), key)); + Assertions.assertSame(m1.get(key), m2.get(key)); } } @Test public void testDedupMapOfPolicyResource() { - Map strTbl = new HashMap<>(); - Map m1 = null; + Map strTbl = new HashMap<>(); + Map m1 = null; - Assert.assertSame("null map - dedupStringsMapOfPolicyResource() should return the same map", m1, StringUtil.dedupStringsMapOfPolicyResource(m1, strTbl)); + Assertions.assertSame(m1, StringUtil.dedupStringsMapOfPolicyResource(m1, strTbl)); m1 = Collections.emptyMap(); - Assert.assertSame("empty map - dedupStringsMapOfPolicyResource() should return the same map", m1, StringUtil.dedupStringsMapOfPolicyResource(m1, strTbl)); + Assertions.assertSame(m1, StringUtil.dedupStringsMapOfPolicyResource(m1, strTbl)); m1 = new HashMap<>(); - Assert.assertSame("empty map - dedupStringsMapOfPolicyResource() should return the same map", m1, StringUtil.dedupStringsMapOfPolicyResource(m1, strTbl)); + Assertions.assertSame(m1, StringUtil.dedupStringsMapOfPolicyResource(m1, strTbl)); m1 = new HashMap<>(); m1.put(getString("database"), new RangerPolicyResource(getString("db1"))); m1.put(getString("table"), new RangerPolicyResource(getString("*"))); - Assert.assertNotSame("non-empty map - dedupStringsMapOfPolicyResource() should return a new map", m1, StringUtil.dedupStringsMapOfPolicyResource(m1, strTbl)); + Assertions.assertNotSame(m1, StringUtil.dedupStringsMapOfPolicyResource(m1, strTbl)); Map m2 = new HashMap<>(); m2.put(getString("database"), new RangerPolicyResource(getString("db1"))); m2.put(getString("table"), new RangerPolicyResource(getString("*"))); for (Map.Entry entry : m1.entrySet()) { - String key = entry.getKey(); + String key = entry.getKey(); RangerPolicyResource value1 = entry.getValue(); RangerPolicyResource value2 = m2.get(key); - Assert.assertFalse("Before dedupStringsMapOfPolicyResource(): m2 has same key as m1", containsInstance(m2.keySet(), key)); + Assertions.assertFalse(containsInstance(m2.keySet(), key)); for (String value : value1.getValues()) { - Assert.assertFalse("Before dedupStringsMapOfPolicyResource(): m2.values not same values as m1.values for " + value, containsInstance(value2.getValues(), value)); + Assertions.assertFalse(containsInstance(value2.getValues(), value)); } } @@ -227,14 +238,14 @@ public void testDedupMapOfPolicyResource() { m2 = StringUtil.dedupStringsMapOfPolicyResource(m2, strTbl); for (Map.Entry entry : m1.entrySet()) { - String key = entry.getKey(); + String key = entry.getKey(); RangerPolicyResource value1 = entry.getValue(); RangerPolicyResource value2 = m2.get(key); - Assert.assertTrue("After dedupStringsMapOfPolicyResource(): m2 has same key as m1", containsInstance(m2.keySet(), key)); + Assertions.assertTrue(containsInstance(m2.keySet(), key)); for (String value : value1.getValues()) { - Assert.assertTrue("After dedupStringsMapOfPolicyResource(): m2.values has same values as m1.values for " + value, containsInstance(value2.getValues(), value)); + Assertions.assertTrue(containsInstance(value2.getValues(), value)); } } } @@ -244,16 +255,191 @@ public void testJsonCompression() throws IOException { int[] sizeFactors = new int[] {1, 10, 50, 100, 250, 300, 400, 500}; for (int sizeFactor : sizeFactors) { - RangerSecurityZone zone = generateLargeSecurityZone(sizeFactor); - String json = JsonUtils.objectToJson(zone); - String compressed = StringUtil.compressString(json); - String deCompressed = StringUtil.decompressString(compressed); + RangerSecurityZone zone = generateLargeSecurityZone(sizeFactor); + String json = JsonUtils.objectToJson(zone); + String compressed = StringUtil.compressString(json); + String deCompressed = StringUtil.decompressString(compressed); + + System.out.printf("%d: resourceCount=%d: len(json)=%,d, len(compressed)=%,d, savings=(%,d == %.03f%%)%n", + sizeFactor, getResourceCount(zone), json.length(), compressed.length(), + (json.length() - compressed.length()), + ((json.length() - compressed.length()) / (float) json.length()) * 100); + + Assertions.assertTrue(compressed.length() < deCompressed.length()); + + Assertions.assertEquals(json, deCompressed); + } + } + + @Test + public void test01_EqualsAndEqualsIgnoreCase_String() { + Assertions.assertTrue(StringUtil.equals((String) null, (String) null)); + Assertions.assertFalse(StringUtil.equals((String) null, "a")); + Assertions.assertFalse(StringUtil.equals("a", (String) null)); + Assertions.assertTrue(StringUtil.equals("a", "a")); + + Assertions.assertTrue(StringUtil.equalsIgnoreCase((String) null, (String) null)); + Assertions.assertFalse(StringUtil.equalsIgnoreCase((String) null, "A")); + Assertions.assertFalse(StringUtil.equalsIgnoreCase("A", (String) null)); + Assertions.assertTrue(StringUtil.equalsIgnoreCase("a", "A")); + } + + @Test + public void test02_EqualsAndEqualsIgnoreCase_Collections() { + List l1 = null; + List l2 = null; + Assertions.assertTrue(StringUtil.equals(l1, l2)); + Assertions.assertTrue(StringUtil.equalsIgnoreCase(l1, l2)); + + l1 = new ArrayList<>(); + l2 = new ArrayList<>(); + Assertions.assertTrue(StringUtil.equals(l1, l2)); + Assertions.assertTrue(StringUtil.equalsIgnoreCase(l1, l2)); + + l1 = new ArrayList<>(Arrays.asList("a", "b")); + l2 = new ArrayList<>(Arrays.asList("B", "A")); + Assertions.assertFalse(StringUtil.equals(l1, l2)); + Assertions.assertTrue(StringUtil.equalsIgnoreCase(l1, l2)); + } + + @Test + public void test03_MatchesAndContains() { + Assertions.assertTrue(StringUtil.matches(null, null)); + Assertions.assertTrue(StringUtil.matches("", "")); + Assertions.assertTrue(StringUtil.matches(".*", "")); + Assertions.assertTrue(StringUtil.matches("a.*b", "acb")); + Assertions.assertTrue(StringUtil.matches("a.*b", "acxb")); + + Assertions.assertTrue(StringUtil.contains("abc", "b")); + Assertions.assertFalse(StringUtil.contains("abc", (String) null)); + Assertions.assertFalse(StringUtil.contains((String) null, "a")); + + Assertions.assertTrue(StringUtil.containsIgnoreCase("AbC", "b")); + Assertions.assertFalse(StringUtil.containsIgnoreCase("abc", (String) null)); + Assertions.assertFalse(StringUtil.containsIgnoreCase((String) null, "a")); + + String[] arr = new String[] {"x", "Y"}; + Assertions.assertTrue(StringUtil.contains(arr, "x")); + Assertions.assertFalse(StringUtil.contains(arr, "z")); + Assertions.assertTrue(StringUtil.containsIgnoreCase(arr, "y")); + } - System.out.printf("%d: resourceCount=%d: len(json)=%,d, len(compressed)=%,d, savings=(%,d == %.03f%%)%n", sizeFactor, getResourceCount(zone), json.length(), compressed.length(), (json.length() - compressed.length()), ((json.length() - compressed.length()) / (float) json.length()) * 100); + @Test + public void test04_ToStringVariants() { + List list = new ArrayList<>(); + Assertions.assertEquals("", StringUtil.toString(list)); + list.add("a"); + list.add("b"); + Assertions.assertEquals("a, b", StringUtil.toString(list)); + + String[] arr = new String[] {}; + Assertions.assertEquals("", StringUtil.toString(arr)); + arr = new String[] {"a", "b", "c"}; + Assertions.assertEquals("a, b, c", StringUtil.toString(arr)); + } + + @Test + public void test05_IsEmptyToLowerGetBytes() { + Assertions.assertTrue(StringUtil.isEmpty((String) null)); + Assertions.assertTrue(StringUtil.isEmpty(" ")); + Assertions.assertFalse(StringUtil.isEmpty("a")); + + List list = new ArrayList<>(); + Assertions.assertTrue(StringUtil.isEmpty((Collection) list)); + list.add("x"); + Assertions.assertFalse(StringUtil.isEmpty(list)); - Assert.assertTrue(compressed.length() < deCompressed.length()); + Assertions.assertNull(StringUtil.toLower(null)); + Assertions.assertEquals("abc", StringUtil.toLower("AbC")); + + Assertions.assertNull(StringUtil.getBytes(null)); + Assertions.assertArrayEquals("abc".getBytes(), StringUtil.getBytes("abc")); + } + + @Test + public void test06_UTCDateHelpers() { + Assertions.assertNotNull(StringUtil.getUTCDate()); + Assertions.assertNotNull(StringUtil.getUTCDateForLocalDate(new Date())); + } - Assert.assertEquals(json, deCompressed); + @Test + public void test07_ToStringObjectMap_Set_List_URLs() { + Map src = new HashMap<>(); + src.put("a", "1"); + Map out = StringUtil.toStringObjectMap(src); + Assertions.assertNotNull(out); + Assertions.assertEquals("1", out.get("a")); + + Assertions.assertTrue(StringUtil.toSet(null).isEmpty()); + Set set = StringUtil.toSet(" a, ,b , c "); + Assertions.assertTrue(set.contains("a")); + Assertions.assertTrue(set.contains("b")); + Assertions.assertTrue(set.contains("c")); + + Assertions.assertTrue(StringUtil.toList(null).isEmpty()); + List list = StringUtil.toList(" a, ,b , c "); + Assertions.assertEquals(Arrays.asList("a", "b", "c"), list); + + List urls = StringUtil.getURLs(" http://x/ , https://y/z "); + Assertions.assertEquals(" http://x/ ", urls.get(0)); + Assertions.assertEquals(" https://y/z ", urls.get(1)); + } + + @Test + public void test08_DedupMapSetListVariantsAndCollection() { + Map strTbl = new HashMap<>(); + + Map> mom = new HashMap<>(); + Map inner = new HashMap<>(); + inner.put(getString("k1"), getString("v1")); + mom.put(getString("outer"), inner); + Map> mom2 = StringUtil.dedupStringsMapOfMap(mom, strTbl); + Assertions.assertNotSame(mom, mom2); + + Map> mos = new HashMap<>(); + Set iv = new HashSet<>(Arrays.asList(getString("a"), getString("b"))); + mos.put(getString("outer"), iv); + Map> mos2 = StringUtil.dedupStringsMapOfSet(mos, strTbl); + Assertions.assertNotSame(mos, mos2); + + Map> mol = new HashMap<>(); + List il = new ArrayList<>(Arrays.asList(getString("a"), getString("b"))); + mol.put(getString("outer"), il); + Map> mol2 = StringUtil.dedupStringsMapOfList(mol, strTbl); + Assertions.assertNotSame(mol, mol2); + + HashMap> hm = new HashMap<>(); + hm.put(getString("outer"), new ArrayList<>(Arrays.asList(getString("a")))); + HashMap> hm2 = StringUtil.dedupStringsHashMapOfList(hm, strTbl); + Assertions.assertNotSame(hm, hm2); + + Map moo = new HashMap<>(); + moo.put(getString("x"), getString("y")); + Map moo2 = StringUtil.dedupStringsMapOfObject(moo, strTbl); + Assertions.assertNotSame(moo, moo2); + + Collection coll = new ArrayList<>(Arrays.asList(getString("x"), getString("y"))); + Collection coll2 = StringUtil.dedupStringsCollection(coll, strTbl); + Assertions.assertNotSame(coll, coll2); + } + + @Test + public void test09_GzipHelpersAndEmptyCompress() throws IOException { + String empty = ""; + Assertions.assertEquals(empty, StringUtil.compressString(empty)); + Assertions.assertEquals(empty, StringUtil.decompressString(empty)); + + String original = "hello world"; + byte[] compressed = StringUtil.gzipCompress(original); + String decompressed = StringUtil.gzipDecompress(compressed); + Assertions.assertEquals(original, decompressed); + + byte[] bad = new byte[] {1, 2, 3}; + try { + StringUtil.gzipDecompress(bad); + Assertions.fail("Expected IOException"); + } catch (IOException expected) { + // expected } } @@ -278,10 +464,10 @@ private String getString(String str) { } private RangerSecurityZone generateLargeSecurityZone(int sizeFactor) { - RangerSecurityZone zone = new RangerSecurityZone(); - int svcCount = sizeFactor; - int resourceCount = sizeFactor; - int resNameLen = (sizeFactor / 10) + 1; + RangerSecurityZone zone = new RangerSecurityZone(); + int svcCount = sizeFactor; + int resourceCount = sizeFactor; + int resNameLen = (sizeFactor / 10) + 1; zone.setName("test-zone"); zone.setDescription("this is a test zone"); @@ -333,6 +519,7 @@ private List generateStrings(String prefix, int maxLen, int count) { } private String generateResourceName(String prefix, int maxLen) { - return prefix.length() < maxLen ? (prefix + RandomStringUtils.random(maxLen - prefix.length(), true, true)) : prefix; + return prefix.length() < maxLen ? (prefix + RandomStringUtils.random(maxLen - prefix.length(), true, true)) + : prefix; } } diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/audit/TestRangerDefaultAuditHandler.java b/agents-common/src/test/java/org/apache/ranger/plugin/audit/TestRangerDefaultAuditHandler.java new file mode 100644 index 0000000000..acdad81e02 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/plugin/audit/TestRangerDefaultAuditHandler.java @@ -0,0 +1,390 @@ +/* + * 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.ranger.plugin.audit; + +import org.apache.hadoop.conf.Configuration; +import org.apache.ranger.audit.model.AuthzAuditEvent; +import org.apache.ranger.audit.provider.AuditHandler; +import org.apache.ranger.authorization.hadoop.constants.RangerHadoopConstants; +import org.apache.ranger.plugin.contextenricher.RangerTagForEval; +import org.apache.ranger.plugin.model.RangerServiceDef; +import org.apache.ranger.plugin.model.RangerServiceDef.RangerResourceDef; +import org.apache.ranger.plugin.model.RangerTag; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.gds.GdsAccessResult; +import org.apache.ranger.plugin.policyresourcematcher.RangerPolicyResourceMatcher; +import org.apache.ranger.plugin.service.RangerBasePlugin; +import org.apache.ranger.plugin.util.RangerAccessRequestUtil; +import org.apache.ranger.plugin.util.RangerRESTUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @generated by Cursor + * @description + */ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestRangerDefaultAuditHandler { + @Test + public void test01_getAuthzEvents_nullsAndAuditFlag() { + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(); + + AuthzAuditEvent ev = handler.getAuthzEvents((RangerAccessResult) null); + Assertions.assertNull(ev); + + RangerAccessResult resWithNullReq = new RangerAccessResult(0, "svc", null, null); + resWithNullReq.setIsAudited(true); + Assertions.assertNull(handler.getAuthzEvents(resWithNullReq)); + + RangerAccessRequestImpl req = new RangerAccessRequestImpl(); + RangerAccessResult resNotAudited = new RangerAccessResult(0, "svc", null, req); + resNotAudited.setIsAudited(false); + Assertions.assertNull(handler.getAuthzEvents(resNotAudited)); + } + + @Test + public void test02_getAuthzEvents_populatesFieldsAndDefaults() { + RangerRESTUtils.hostname = "my-host"; + + RangerServiceDef svcDef = new RangerServiceDef(); + svcDef.setId(5L); + List resourceDefs = new ArrayList<>(); + RangerResourceDef r1 = new RangerResourceDef(); + r1.setName("db"); + RangerResourceDef r2 = new RangerResourceDef(); + r2.setName("table"); + RangerResourceDef r3 = new RangerResourceDef(); + r3.setName("column"); + resourceDefs.add(r1); + resourceDefs.add(r2); + resourceDefs.add(r3); + svcDef.setResources(resourceDefs); + + Map elements = new HashMap<>(); + elements.put("db", "sales"); + elements.put("table", "orders"); + elements.put("column", "id"); + RangerAccessResourceImpl resource = new RangerAccessResourceImpl(elements); + resource.setServiceDef(svcDef); + + RangerAccessRequestImpl req = new RangerAccessRequestImpl(); + req.setResource(resource); + req.setUser("alice"); + req.setAccessType("read"); + req.setAction("SELECT"); + req.setAccessTime(new Date(1720000000000L)); + req.setClientIPAddress("192.168.1.10"); + req.setRemoteIPAddress("10.0.0.1"); + List fwd = new ArrayList<>(Arrays.asList("172.16.0.2", "172.16.0.3")); + req.setForwardedAddresses(fwd); + req.setClientType("jdbc"); + req.setSessionId("sess-1"); + req.setRequestData("req-json"); + req.setClusterName("clusterA"); + + // Add a tag for getTags() + Map tagAttrs = new HashMap<>(); + tagAttrs.put("key", "value"); + RangerTag tag = new RangerTag("PII", tagAttrs); + RangerTagForEval tagForEval = new RangerTagForEval(tag, RangerPolicyResourceMatcher.MatchType.SELF); + Set tagSet = new HashSet<>(); + tagSet.add(tagForEval); + RangerAccessRequestUtil.setRequestTagsInContext(req.getContext(), tagSet); + + // Add GDS datasets/projects + GdsAccessResult gds = new GdsAccessResult(); + gds.addDataset("dataset1"); + gds.addProject("project1"); + RangerAccessRequestUtil.setGdsResultInContext(req, gds); + + RangerAccessResult result = new RangerAccessResult(0, "svcA", svcDef, req); + result.setIsAudited(true); + result.setIsAllowed(true); + result.setPolicyId(123L); + result.setZoneName("zone-1"); + result.setPolicyVersion(7L); + + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(new Configuration()); + AuthzAuditEvent event = handler.getAuthzEvents(result); + + Assertions.assertNotNull(event); + Assertions.assertEquals("svcA", event.getRepositoryName()); + Assertions.assertEquals(5, event.getRepositoryType()); + Assertions.assertEquals("column", event.getResourceType()); + Assertions.assertEquals("sales/orders/id", event.getResourcePath()); + Assertions.assertEquals("alice", event.getUser()); + Assertions.assertEquals("read", event.getAction()); + Assertions.assertEquals("SELECT", event.getAccessType()); + Assertions.assertEquals(1, event.getAccessResult()); + Assertions.assertEquals(123L, event.getPolicyId()); + Assertions.assertEquals("192.168.1.10", event.getClientIP()); + Assertions.assertEquals("jdbc", event.getClientType()); + Assertions.assertEquals("sess-1", event.getSessionId()); + Assertions.assertEquals(RangerHadoopConstants.DEFAULT_RANGER_MODULE_ACL_NAME, event.getAclEnforcer()); + Assertions.assertNotNull(event.getTags()); + Assertions.assertFalse(event.getTags().isEmpty()); + Assertions.assertEquals(new HashSet<>(Arrays.asList("dataset1")), event.getDatasets()); + Assertions.assertEquals(new HashSet<>(Arrays.asList("project1")), event.getProjects()); + Assertions.assertNotNull(event.getAdditionalInfo()); + Assertions.assertTrue(event.getAdditionalInfo().contains("10.0.0.1")); + Assertions.assertTrue(event.getAdditionalInfo().contains("forwarded-ip-addresses")); + Assertions.assertEquals("clusterA", event.getClusterName()); + Assertions.assertEquals("zone-1", event.getZoneName()); + Assertions.assertEquals(Long.valueOf(7L), event.getPolicyVersion()); + Assertions.assertEquals("my-host", event.getAgentHostname()); + Assertions.assertNotNull(event.getEventId()); + Assertions.assertEquals(event.getEventId(), result.getAuditLogId()); + Assertions.assertEquals("RangerAudit", event.getLogType()); + } + + @Test + public void test03_getAuthzEvents_collectionSkipsNulls() { + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(); + + RangerAccessRequestImpl req1 = new RangerAccessRequestImpl(); + RangerAccessResult r1 = new RangerAccessResult(0, "svc", null, req1); + r1.setIsAudited(false); // will be skipped + + RangerAccessResult r2 = new RangerAccessResult(0, "svc", null, null); // request null, skipped + r2.setIsAudited(true); + + RangerAccessRequestImpl req3 = new RangerAccessRequestImpl(); + RangerAccessResult r3 = new RangerAccessResult(0, "svc", null, req3); + r3.setIsAudited(true); + r3.setIsAllowed(true); + + List list = new ArrayList<>(); + list.add(r1); + list.add(r2); + list.add(r3); + + Collection events = handler.getAuthzEvents(list); + Assertions.assertNotNull(events); + Assertions.assertEquals(1, events.size()); + } + + @Test + public void test04_logAuthzAudit_branches_providerSuccessAndFailure() { + AuthzAuditEvent event = new AuthzAuditEvent(); + event.setRepositoryName("svc-x"); + + try (MockedStatic mocked = Mockito.mockStatic(RangerBasePlugin.class)) { + AuditHandler ok = Mockito.mock(AuditHandler.class); + Mockito.when(ok.log(Mockito.any(AuthzAuditEvent.class))).thenReturn(true); + mocked.when(() -> RangerBasePlugin.getAuditProvider("svc-x")).thenReturn(ok); + + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(); + handler.logAuthzAudit(event); + Mockito.verify(ok, Mockito.times(1)).log(Mockito.any(AuthzAuditEvent.class)); + } + + AuthzAuditEvent event2 = new AuthzAuditEvent(); + event2.setRepositoryName("svc-y"); + try (MockedStatic mocked = Mockito.mockStatic(RangerBasePlugin.class)) { + AuditHandler fail = Mockito.mock(AuditHandler.class); + Mockito.when(fail.log(Mockito.any(AuthzAuditEvent.class))).thenReturn(false); + mocked.when(() -> RangerBasePlugin.getAuditProvider("svc-y")).thenReturn(fail); + + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(); + handler.logAuthzAudit(event2); // should not throw + Mockito.verify(fail, Mockito.times(1)).log(Mockito.any(AuthzAuditEvent.class)); + } + + // null event branch + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(); + handler.logAuthzAudit(null); + } + + @Test + public void test05_logAuthzAudits_iteratesEach() { + AuthzAuditEvent e1 = new AuthzAuditEvent(); + e1.setRepositoryName("svc"); + AuthzAuditEvent e2 = new AuthzAuditEvent(); + e2.setRepositoryName("svc"); + + try (MockedStatic mocked = Mockito.mockStatic(RangerBasePlugin.class)) { + AuditHandler ok = Mockito.mock(AuditHandler.class); + Mockito.when(ok.log(Mockito.any(AuthzAuditEvent.class))).thenReturn(true); + mocked.when(() -> RangerBasePlugin.getAuditProvider("svc")).thenReturn(ok); + + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(); + List list = new ArrayList<>(); + list.add(e1); + list.add(e2); + handler.logAuthzAudits(list); + Mockito.verify(ok, Mockito.times(2)).log(Mockito.any(AuthzAuditEvent.class)); + } + + // null input + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(); + handler.logAuthzAudits(null); + } + + @Test + public void test06_createAuthzAuditEvent_returnsNew() { + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(); + AuthzAuditEvent e = handler.createAuthzAuditEvent(); + Assertions.assertNotNull(e); + } + + @Test + public void test07_getDatasetsAndProjects_fromContext() { + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(); + + RangerAccessRequestImpl req = new RangerAccessRequestImpl(); + GdsAccessResult gds = new GdsAccessResult(); + gds.addDataset("d1"); + gds.addProject("p1"); + RangerAccessRequestUtil.setGdsResultInContext(req, gds); + + Set datasets = handler.getDatasets(req); + Set projects = handler.getProjects(req); + Assertions.assertEquals(new HashSet<>(Arrays.asList("d1")), datasets); + Assertions.assertEquals(new HashSet<>(Arrays.asList("p1")), projects); + } + + @Test + public void test08_getAdditionalInfo_nullAndNonNull() { + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(); + RangerAccessRequestImpl req = new RangerAccessRequestImpl(); + req.setRemoteIPAddress(null); + req.setForwardedAddresses(new ArrayList<>()); + Assertions.assertNull(handler.getAdditionalInfo(req)); + + RangerAccessRequestImpl req2 = new RangerAccessRequestImpl(); + req2.setRemoteIPAddress("10.1.1.1"); + List fwd = new ArrayList<>(Arrays.asList("1.1.1.1")); + req2.setForwardedAddresses(fwd); + String info = handler.getAdditionalInfo(req2); + Assertions.assertNotNull(info); + Assertions.assertTrue(info.contains("10.1.1.1")); + } + + @Test + public void test09_getTags_nullAndNonNull() { + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(); + + RangerAccessRequestImpl req = new RangerAccessRequestImpl(); + Assertions.assertNull(invokeGetTags(handler, req)); + + Map tagAttrs = new HashMap<>(); + tagAttrs.put("a", "b"); + RangerTag tag = new RangerTag("T1", tagAttrs); + RangerTagForEval tagForEval = new RangerTagForEval(tag, RangerPolicyResourceMatcher.MatchType.SELF); + Set tagSet = new HashSet<>(); + tagSet.add(tagForEval); + RangerAccessRequestUtil.setRequestTagsInContext(req.getContext(), tagSet); + + Set tags = invokeGetTags(handler, req); + Assertions.assertNotNull(tags); + Assertions.assertEquals(1, tags.size()); + } + + @Test + public void test10_generateNextAuditEventId_resetsUuidOnCounterMax() throws Exception { + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(); + + Field uuidField = RangerDefaultAuditHandler.class.getDeclaredField("uuid"); + uuidField.setAccessible(true); + uuidField.set(handler, "fixed"); + + Field counterField = RangerDefaultAuditHandler.class.getDeclaredField("counter"); + counterField.setAccessible(true); + counterField.set(handler, new AtomicInteger(Integer.MAX_VALUE - 1)); + + AuthzAuditEvent e1 = new AuthzAuditEvent(); + e1.setRepositoryName("svc"); + AuthzAuditEvent e2 = new AuthzAuditEvent(); + e2.setRepositoryName("svc"); + + try (MockedStatic mocked = Mockito.mockStatic(RangerBasePlugin.class)) { + AuditHandler ok = Mockito.mock(AuditHandler.class); + Mockito.when(ok.log(Mockito.any(AuthzAuditEvent.class))).thenReturn(true); + mocked.when(() -> RangerBasePlugin.getAuditProvider("svc")).thenReturn(ok); + + handler.logAuthzAudit(e1); + handler.logAuthzAudit(e2); + } + + String id1 = e1.getEventId(); + String id2 = e2.getEventId(); + Assertions.assertNotNull(id1); + Assertions.assertNotNull(id2); + Assertions.assertTrue(id1.startsWith("fixed-")); + Assertions.assertFalse(id2.startsWith("fixed-")); + } + + @Test + public void test11_processResult_and_processResults() { + RangerAccessRequestImpl req = new RangerAccessRequestImpl(); + RangerAccessResult result = new RangerAccessResult(0, "svcP", null, req); + result.setIsAudited(true); + result.setIsAllowed(true); + + try (MockedStatic mocked = Mockito.mockStatic(RangerBasePlugin.class)) { + AuditHandler ok = Mockito.mock(AuditHandler.class); + Mockito.when(ok.log(Mockito.any(AuthzAuditEvent.class))).thenReturn(true); + mocked.when(() -> RangerBasePlugin.getAuditProvider("svcP")).thenReturn(ok); + + RangerDefaultAuditHandler handler = new RangerDefaultAuditHandler(); + handler.processResult(result); + + List list = new ArrayList<>(); + list.add(result); + handler.processResults(list); + + Mockito.verify(ok, Mockito.atLeast(2)).log(Mockito.any(AuthzAuditEvent.class)); + } + } + + private Set invokeGetTags(RangerDefaultAuditHandler handler, RangerAccessRequest request) { + try { + Method m = RangerDefaultAuditHandler.class.getDeclaredMethod("getTags", RangerAccessRequest.class); + m.setAccessible(true); + @SuppressWarnings("unchecked") + Set ret = (Set) m.invoke(handler, request); + return ret; + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/audit/TestRangerMultiResourceAuditHandler.java b/agents-common/src/test/java/org/apache/ranger/plugin/audit/TestRangerMultiResourceAuditHandler.java new file mode 100644 index 0000000000..a55ba16439 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/plugin/audit/TestRangerMultiResourceAuditHandler.java @@ -0,0 +1,143 @@ +/* + * 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.ranger.plugin.audit; + +import org.apache.ranger.audit.model.AuthzAuditEvent; +import org.apache.ranger.audit.provider.AuditHandler; +import org.apache.ranger.plugin.service.RangerBasePlugin; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * @generated by Cursor + * @description + */ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestRangerMultiResourceAuditHandler { + @Test + public void test01_collectsEventsViaOverrides() { + RangerMultiResourceAuditHandler handler = new RangerMultiResourceAuditHandler(); + + AuthzAuditEvent e1 = new AuthzAuditEvent(); + e1.setAccessResult((short) 1); + e1.setRepositoryName("svc"); + AuthzAuditEvent e2 = new AuthzAuditEvent(); + e2.setAccessResult((short) 0); + e2.setRepositoryName("svc"); + + handler.logAuthzAudit(e1); + List list = new ArrayList<>(); + list.add(e2); + handler.logAuthzAudits(list); + + // Now flush: since a denied exists, only denied should be forwarded + try (MockedStatic mocked = Mockito.mockStatic(RangerBasePlugin.class)) { + AuditHandler ok = Mockito.mock(AuditHandler.class); + Mockito.when(ok.log(Mockito.any(AuthzAuditEvent.class))).thenReturn(true); + mocked.when(() -> RangerBasePlugin.getAuditProvider("svc")).thenReturn(ok); + + handler.flushAudit(); + Mockito.verify(ok, Mockito.times(1)).log(Mockito.argThat(a -> a.getAccessResult() == 0)); + } + } + + @Test + public void test02_flushAudit_allAllowedWhenNoDenied() { + RangerMultiResourceAuditHandler handler = new RangerMultiResourceAuditHandler(); + + AuthzAuditEvent e1 = new AuthzAuditEvent(); + e1.setAccessResult((short) 1); + e1.setRepositoryName("svc"); + AuthzAuditEvent e2 = new AuthzAuditEvent(); + e2.setAccessResult((short) 1); + e2.setRepositoryName("svc"); + + List list = new ArrayList<>(); + list.add(e1); + list.add(e2); + handler.logAuthzAudits(list); + + try (MockedStatic mocked = Mockito.mockStatic(RangerBasePlugin.class)) { + AuditHandler ok = Mockito.mock(AuditHandler.class); + Mockito.when(ok.log(Mockito.any(AuthzAuditEvent.class))).thenReturn(true); + mocked.when(() -> RangerBasePlugin.getAuditProvider("svc")).thenReturn(ok); + + handler.flushAudit(); + Mockito.verify(ok, Mockito.times(2)).log(Mockito.any(AuthzAuditEvent.class)); + } + } + + @Test + public void test03_flushAudit_resetsBufferOnErrorToo() { + RangerMultiResourceAuditHandler handler = new RangerMultiResourceAuditHandler(); + + AuthzAuditEvent e1 = new AuthzAuditEvent(); + e1.setAccessResult((short) 1); + e1.setRepositoryName("svc"); + AuthzAuditEvent e2 = new AuthzAuditEvent(); + e2.setAccessResult((short) 0); + e2.setRepositoryName("svc"); + + List list = new ArrayList<>(); + list.add(e1); + list.add(e2); + handler.logAuthzAudits(list); + + try (MockedStatic mocked = Mockito.mockStatic(RangerBasePlugin.class)) { + AuditHandler failing = Mockito.mock(AuditHandler.class); + Mockito.when(failing.log(Mockito.any(AuthzAuditEvent.class))).thenThrow(new RuntimeException("boom")); + mocked.when(() -> RangerBasePlugin.getAuditProvider("svc")).thenReturn(failing); + + handler.flushAudit(); + } + + // After exception, subsequent flush with no events should not send anything + try (MockedStatic mocked = Mockito.mockStatic(RangerBasePlugin.class)) { + AuditHandler ok = Mockito.mock(AuditHandler.class); + mocked.when(() -> RangerBasePlugin.getAuditProvider("svc")).thenReturn(ok); + + handler.flushAudit(); + Mockito.verify(ok, Mockito.never()).log(Mockito.any(AuthzAuditEvent.class)); + } + } + + @Test + public void test04_logAuthzAudits_emptyCollectionNoop() { + RangerMultiResourceAuditHandler handler = new RangerMultiResourceAuditHandler(); + Collection empty = new ArrayList<>(); + handler.logAuthzAudits(empty); + try (MockedStatic mocked = Mockito.mockStatic(RangerBasePlugin.class)) { + AuditHandler ok = Mockito.mock(AuditHandler.class); + mocked.when(() -> RangerBasePlugin.getAuditProvider(Mockito.anyString())).thenReturn(ok); + + handler.flushAudit(); + Mockito.verify(ok, Mockito.never()).log(Mockito.any(AuthzAuditEvent.class)); + } + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/client/TestBaseClient.java b/agents-common/src/test/java/org/apache/ranger/plugin/client/TestBaseClient.java new file mode 100644 index 0000000000..6d27ef920b --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/plugin/client/TestBaseClient.java @@ -0,0 +1,329 @@ +/* + * 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.ranger.plugin.client; + +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import javax.security.auth.Subject; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * @generated by Cursor + * @description + */ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestBaseClient { + @Test + public void test01_generateResponseDataMap_populatesAllKeys() { + Map map = new HashMap<>(); + BaseClient.generateResponseDataMap(true, "msg", "desc", 5L, "field", map); + assertEquals(true, map.get("connectivityStatus")); + assertEquals("msg", map.get("message")); + assertEquals("desc", map.get("description")); + assertEquals(5L, map.get("objectId")); + assertEquals("field", map.get("fieldName")); + } + + @Test + public void test02_getMessage_collectsFromCauseChainWithoutDuplicates() { + Exception inner = new Exception("inner"); + Exception outer = new Exception("outer", inner); + String msg = BaseClient.getMessage(outer); + // order is preserved top-down + assertEquals("outer. \ninner. \n", msg); + } + + @Test + public void test03_login_withUsernameSimpleAuth_createsSubjectAndServiceName() { + Map props = new HashMap<>(); + props.put("username", "unit_user"); + props.put("authtype", "simple"); + props.put("hadoop.security.authentication", "simple"); + + class TestClient extends BaseClient { + TestClient(String svc, Map cp) { + super(svc, cp, "core-site.xml"); + } + + public Subject subject() { + return getLoginSubject(); + } + } + + TestClient client = new TestClient("svcName", props); + assertEquals("svcName", client.getSerivceName()); + assertNotNull(client.subject()); + } + + @Test + public void test04_login_usesLookupPrincipalWhenProvided() { + Map props = new HashMap<>(); + props.put("username", "unit_user"); + props.put("lookupprincipal", "user/_HOST@EXAMPLE.COM"); + props.put("lookupkeytab", "/tmp/missing.keytab"); + props.put("hadoop.security.authentication", "kerberos"); + + class TestClient extends BaseClient { + TestClient(String svc, Map cp) { + super(svc, cp, "core-site.xml"); + } + } + + try { + new TestClient("svc", props); + } catch (Exception ex) { + if (ex instanceof HadoopException) { + assertNotNull(((HadoopException) ex).getResponseData()); + } + } + } + + @Test + public void test05_getConfigHolder_isNotNull_withNullConnectionProperties() { + Map props = new HashMap<>(); + props.put("username", "unit_user"); + class TestClient extends BaseClient { + TestClient(String svc, Map cp) { + super(svc, cp, "xalogin.xml"); + } + + @Override + protected void login() { + /* no-op for test */ } + + public HadoopConfigHolder cfg() { + return getConfigHolder(); + } + } + + TestClient client = new TestClient("svcNull", props); + assertNotNull(client.cfg()); + } + + @Test + public void test06_createException_methods_viaReflection() throws Exception { + Map props = new HashMap<>(); + props.put("username", "unit_user"); + class TestClient extends BaseClient { + TestClient(String svc, Map cp) { + super(svc, cp, "xalogin.xml"); + } + + @Override + protected void login() { + /* no-op for reflection tests */ } + } + + TestClient client = new TestClient("svcEx", props); + + Method m1 = BaseClient.class.getDeclaredMethod("createException", Exception.class); + m1.setAccessible(true); + HadoopException he1 = (HadoopException) m1.invoke(client, new IOException("io")); + assertNotNull(he1.getResponseData()); + + Method m2 = BaseClient.class.getDeclaredMethod("createException", String.class, Exception.class); + m2.setAccessible(true); + HadoopException he2 = (HadoopException) m2.invoke(client, "msg", new IOException("io2")); + assertNotNull(he2.getResponseData()); + } + + @Test + public void test07_login_keytabPresentButSimpleAuth_usesSimpleLogin() { + Map props = new HashMap<>(); + props.put("username", "unit_user"); + props.put("keytabfile", "/tmp/any.keytab"); + props.put("authtype", "simple"); + props.put("hadoop.security.authentication", "simple"); + + class TestClient extends BaseClient { + TestClient(String svc, Map cp) { + super(svc, cp, "core-site.xml"); + } + + public Subject subject() { + return getLoginSubject(); + } + } + + TestClient client = new TestClient("svcKeytabSimple", props); + assertNotNull(client.subject()); + } + + @Test + public void test08_login_passwordDecryptFailureFallsBack_andKerberosPasswordPath() { + Map props = new HashMap<>(); + props.put("username", "unit_user"); + // deliberately set an invalid encrypted string to trigger decryption exception + // path + props.put("password", "not-base64-@#"); + props.put("authtype", "kerberos"); + props.put("hadoop.security.authentication", "kerberos"); + + class TestClient extends BaseClient { + TestClient(String svc, Map cp) { + super(svc, cp, "core-site.xml"); + } + } + + try { + new TestClient("svcPwdKrb", props); + } catch (Exception ex) { + // loginUserWithPassword will fail and be wrapped into HadoopException + assertNotNull(((HadoopException) ex).getResponseData()); + } + } + + @Test + public void test09_constructor_twoArg_callsInitAndLogin() { + Map props = new HashMap<>(); + props.put("username", "unit_user"); + props.put("authtype", "simple"); + props.put("hadoop.security.authentication", "simple"); + + class TestClient extends BaseClient { + TestClient(String svc, Map cp) { + super(svc, cp); + } + + public Subject subject() { + return getLoginSubject(); + } + } + + TestClient client = new TestClient("svc2Arg", props); + assertNotNull(client.subject()); + } + + @Test + public void test10_init_withNullConnectionProperties_usesGetInstanceWithoutProps() { + class TestClient extends BaseClient { + TestClient(String svc) { + super(svc, null, "xalogin.xml"); + } + + @Override + protected void login() { + /* avoid external login for this test */ } + + public HadoopConfigHolder cfg() { + return getConfigHolder(); + } + } + + TestClient client = new TestClient("svcNullProps"); + assertNotNull(client.cfg()); + } + + @Test + public void test11_login_missingUsername_throwsHadoopException() { + Map props = new HashMap<>(); + props.put("authtype", "simple"); + props.put("hadoop.security.authentication", "simple"); + + class TestClient extends BaseClient { + TestClient(String svc, Map cp) { + super(svc, cp, "core-site.xml"); + } + } + + try { + new TestClient("svcNoUser", props); + } catch (Exception ex) { + assertEquals(HadoopException.class, ex.getClass()); + // message created in createException(String, Exception) + } + } + + @Test + public void test12_login_lookupProvidedButSimpleAuth_usesUsernameLogin() { + Map props = new HashMap<>(); + props.put("username", "unit_user"); + props.put("lookupprincipal", "user/_HOST@EXAMPLE.COM"); + props.put("lookupkeytab", "/tmp/missing.keytab"); + props.put("authtype", "simple"); + props.put("hadoop.security.authentication", "simple"); + + class TestClient extends BaseClient { + TestClient(String svc, Map cp) { + super(svc, cp, "core-site.xml"); + } + + public Subject subject() { + return getLoginSubject(); + } + } + + TestClient client = new TestClient("svcLookupSimple", props); + assertNotNull(client.subject()); + } + + @Test + public void test13_login_keytabPresentKerberos_throwsWrappedException() { + Map props = new HashMap<>(); + props.put("username", "unit_user@EXAMPLE.COM"); + props.put("keytabfile", "/tmp/missing.keytab"); + props.put("authtype", "kerberos"); + props.put("hadoop.security.authentication", "kerberos"); + + class TestClient extends BaseClient { + TestClient(String svc, Map cp) { + super(svc, cp, "core-site.xml"); + } + } + + try { + new TestClient("svcKeytabKrb", props); + } catch (Exception ex) { + assertEquals(IllegalArgumentException.class, ex.getClass()); + } + } + + @Test + public void test14_login_noPasswordConfigured_kerberosPath_throwsWrappedException() { + Map props = new HashMap<>(); + props.put("username", "unit_user@EXAMPLE.COM"); + // no password and no keytab + props.put("authtype", "kerberos"); + props.put("hadoop.security.authentication", "kerberos"); + + class TestClient extends BaseClient { + TestClient(String svc, Map cp) { + super(svc, cp, "core-site.xml"); + } + } + + try { + new TestClient("svcNoPwdKrb", props); + } catch (Exception ex) { + assertEquals(IllegalArgumentException.class, ex.getClass()); + } + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/client/TestHadoopConfigHolder.java b/agents-common/src/test/java/org/apache/ranger/plugin/client/TestHadoopConfigHolder.java new file mode 100644 index 0000000000..ce1c25fc3e --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/plugin/client/TestHadoopConfigHolder.java @@ -0,0 +1,306 @@ +/* + * 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.ranger.plugin.client; + +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.File; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @generated by Cursor + * @description + */ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestHadoopConfigHolder { + @Test + public void test01_getInstance_withConnectionProperties_populatesLoginInfoAndKerberosFlag() { + String ds = "ds-" + System.nanoTime(); + Map props = new HashMap<>(); + props.put("username", "user1"); + props.put("password", "pwd1"); + props.put("lookupprincipal", "lp/host@EXAMPLE.COM"); + props.put("lookupkeytab", "/tmp/lp.keytab"); + props.put("namerules", "DEFAULT"); + props.put("authtype", "simple"); + props.put("hadoop.security.authentication", "kerberos"); + + HadoopConfigHolder holder = HadoopConfigHolder.getInstance(ds, props, "core-site.xml"); + + assertNotNull(holder); + assertEquals("user1", holder.getUserName()); + assertEquals("pwd1", holder.getPassword()); + assertEquals("lp/host@EXAMPLE.COM", holder.getLookupPrincipal()); + assertEquals("/tmp/lp.keytab", holder.getLookupKeytab()); + assertEquals("DEFAULT", holder.getNameRules()); + assertEquals("kerberos", holder.getHadoopSecurityAuthentication()); + assertTrue(holder.isKerberosAuthentication()); + assertTrue(holder.hasResourceExists("xalogin.xml")); + } + + @Test + public void test02_getInstance_replacesCachedWhenConnectionPropertiesChange() { + String ds = "ds-" + System.nanoTime(); + Map props1 = new HashMap<>(); + props1.put("username", "userA"); + HadoopConfigHolder h1 = HadoopConfigHolder.getInstance(ds, props1, "xalogin.xml"); + assertEquals("userA", h1.getUserName()); + + Map props2 = new HashMap<>(); + props2.put("username", "userB"); + HadoopConfigHolder h2 = HadoopConfigHolder.getInstance(ds, props2, "xalogin.xml"); + assertEquals("userB", h2.getUserName()); + } + + @Test + public void test03_isKerberosAuthentication_trueWhenUsernameContainsRealm() { + String ds = "ds-" + System.nanoTime(); + Map props = new HashMap<>(); + props.put("username", "user@EXAMPLE.COM"); + HadoopConfigHolder holder = HadoopConfigHolder.getInstance(ds, props, "core-site.xml"); + assertTrue(holder.isKerberosAuthentication()); + } + + @Test + public void test04_getters_forHiveAndAuthAndInternalKeys() { + String ds = "ds-" + System.nanoTime(); + Map props = new HashMap<>(); + props.put("enable.hive.metastore.lookup", "true"); + props.put("hive.site.file.path", "/etc/hive/hive-site.xml"); + props.put("authtype", "simple"); + HadoopConfigHolder holder = HadoopConfigHolder.getInstance(ds, props, "xalogin.xml"); + + // getHiveSiteFilePath returns null unless the value is present and non-empty + // in the xalogin.xml (RANGER_SECTION_NAME) section + assertEquals("/etc/hive/hive-site.xml", holder.getHiveSiteFilePath()); + assertTrue(holder.isEnableHiveMetastoreLookup()); + assertEquals("simple", holder.getAuthType()); + Set internalKeys = holder.getRangerInternalPropertyKeys(); + assertNotNull(internalKeys); + assertTrue(internalKeys.contains("username")); + } + + @Test + public void test05_getInstance_withoutProps_usesStaticInitAndReturnsSameInstance() { + String ds = "ds-" + System.nanoTime(); + HadoopConfigHolder h1 = HadoopConfigHolder.getInstance(ds); + HadoopConfigHolder h2 = HadoopConfigHolder.getInstance(ds); + assertNotNull(h1); + assertEquals(h1, h2); + } + + @Test + public void test06_init_guardBranch_executedViaReflection() throws Exception { + Field f = HadoopConfigHolder.class.getDeclaredField("initialized"); + f.setAccessible(true); + + Method init = HadoopConfigHolder.class.getDeclaredMethod("init"); + init.setAccessible(true); + + // First: force initialized=true then call init() to hit early return path + f.setBoolean(null, true); + init.invoke(null); + + // Second: force initialized=false then call init() to execute read path + f.setBoolean(null, false); + init.invoke(null); + + // Verify we can still obtain an instance afterward + String ds = "ds-" + System.nanoTime(); + HadoopConfigHolder holder = HadoopConfigHolder.getInstance(ds); + assertNotNull(holder); + } + + @Test + public void test07_isKerberosAuthentication_falseWithLookupCredsPresent() { + String ds = "ds-" + System.nanoTime(); + Map props = new HashMap<>(); + props.put("username", "user1"); + props.put("lookupprincipal", "user/_HOST@EXAMPLE.COM"); + props.put("lookupkeytab", "/tmp/lp.keytab"); + props.put("hadoop.security.authentication", "simple"); + + HadoopConfigHolder holder = HadoopConfigHolder.getInstance(ds, props, "core-site.xml"); + assertNotNull(holder); + assertEquals("simple", holder.getHadoopSecurityAuthentication()); + assertFalse(holder.isKerberosAuthentication()); + } + + @Test + public void test10_init_whenResourcesMissing_setsInitializedAndKeepsGlobalPropsUnchanged() throws Exception { + Field initializedField = HadoopConfigHolder.class.getDeclaredField("initialized"); + initializedField.setAccessible(true); + initializedField.setBoolean(null, false); + + Field glp = HadoopConfigHolder.class.getDeclaredField("globalLoginProp"); + glp.setAccessible(true); + Properties empty = new Properties(); + glp.set(null, empty); + + Method init = HadoopConfigHolder.class.getDeclaredMethod("init"); + init.setAccessible(true); + init.invoke(null); + + assertTrue(initializedField.getBoolean(null)); + Properties current = (Properties) glp.get(null); + assertTrue(current.isEmpty()); + } + + @Test + public void test11_init_whenOnlyGlobalLoginPropsPresent_populatesGlobalLoginAndUserName() throws Exception { + Field initializedField = HadoopConfigHolder.class.getDeclaredField("initialized"); + initializedField.setAccessible(true); + initializedField.setBoolean(null, false); + + // Ensure globalLoginProp starts empty + Field glp = HadoopConfigHolder.class.getDeclaredField("globalLoginProp"); + glp.setAccessible(true); + Properties empty = new Properties(); + glp.set(null, empty); + + // Prepare temp dir with only hadoop-login.properties + Path tempDir = Files.createTempDirectory("hcp-init-only-global-"); + Path loginProps = tempDir.resolve("hadoop-login.properties"); + Properties p = new Properties(); + p.setProperty("username", "from-global-only"); + try (OutputStream os = Files.newOutputStream(loginProps)) { + p.store(os, "test"); + } + + // Use an isolated classloader so that init() can discover resources from tempDir + URLClassLoader isolated = buildIsolatedLoader(tempDir); + Class isoClazz = Class.forName("org.apache.ranger.plugin.client.HadoopConfigHolder", true, isolated); + + Field isoInitializedField = isoClazz.getDeclaredField("initialized"); + isoInitializedField.setAccessible(true); + isoInitializedField.setBoolean(null, false); + + Field isoGlp = isoClazz.getDeclaredField("globalLoginProp"); + isoGlp.setAccessible(true); + isoGlp.set(null, new Properties()); + + Method init = isoClazz.getDeclaredMethod("init"); + init.setAccessible(true); + init.invoke(null); + + assertTrue(isoInitializedField.getBoolean(null)); + Properties current = (Properties) isoGlp.get(null); + assertEquals("from-global-only", current.getProperty("username")); + + String ds = "ds-" + System.nanoTime(); + Method getInstance = isoClazz.getDeclaredMethod("getInstance", String.class); + Object holder = getInstance.invoke(null, ds); + Method getUserName = isoClazz.getDeclaredMethod("getUserName"); + String actualUser = (String) getUserName.invoke(holder); + assertEquals("from-global-only", actualUser); + } + + @Test + public void test12_init_withDatasourceProperties_parsesKeysAndAddsConfigurations() throws Exception { + // Create datasource.properties with a mix of valid and invalid keys + Path tempDir = Files.createTempDirectory("hcp-init-ds-"); + Path dsProps = tempDir.resolve("datasource.properties"); + String content = String.join("\n", "ds1=ignored", // dotLocatedAt == -1 -> continue + "ds1.core-site=ignored2", // resourceFoundAt == -1 -> skip + "ds1.core-site.hadoop.security.authentication=kerberos", // valid + "ds1.xalogin.username=testuser"); // valid + + Files.write(dsProps, content.getBytes(StandardCharsets.ISO_8859_1)); + + URLClassLoader isolated = buildIsolatedLoader(tempDir); + Class isoClazz = Class.forName("org.apache.ranger.plugin.client.HadoopConfigHolder", true, isolated); + + Method init = isoClazz.getDeclaredMethod("init"); + init.setAccessible(true); + init.invoke(null); + + Field mapField = isoClazz.getDeclaredField("dataSource2ResourceListMap"); + mapField.setAccessible(true); + @SuppressWarnings("unchecked") + Map> dsMap = (Map>) mapField.get(null); + + @SuppressWarnings("unchecked") + Map resources = dsMap.get("ds1"); + assertNotNull(resources); + assertTrue(resources.containsKey("core-site.xml")); + assertTrue(resources.containsKey("xalogin.xml")); + assertEquals("kerberos", resources.get("core-site.xml").getProperty("hadoop.security.authentication")); + assertEquals("testuser", resources.get("xalogin.xml").getProperty("username")); + } + + @Test + public void test13_init_withEmptyDatasourceProperties_returnsEarlyAndSkipsGlobalLogin() throws Exception { + // Provide empty datasource.properties with no global login props, in an + // isolated loader + Path tempDir = Files.createTempDirectory("hcp-init-empty-ds-"); + Files.write(tempDir.resolve("datasource.properties"), new byte[0]); + // do not create hadoop-login.properties in this tempDir + + URLClassLoader isolated = buildIsolatedLoader(tempDir); + Class isoClazz = Class.forName("org.apache.ranger.plugin.client.HadoopConfigHolder", true, isolated); + + Method init = isoClazz.getDeclaredMethod("init"); + init.setAccessible(true); + init.invoke(null); + + Field glp = isoClazz.getDeclaredField("globalLoginProp"); + glp.setAccessible(true); + Properties current = (Properties) glp.get(null); + assertTrue(current.isEmpty()); // early return prevented reading global login + } + + private static URLClassLoader buildIsolatedLoader(Path firstResourceDir) throws Exception { + List urls = new ArrayList<>(); + urls.add(firstResourceDir.toUri().toURL()); + String cp = System.getProperty("java.class.path"); + if (cp != null && !cp.isEmpty()) { + String[] parts = cp.split(File.pathSeparator); + for (String part : parts) { + File f = new File(part); + if (f.exists()) { + urls.add(f.toURI().toURL()); + } + } + } + return new URLClassLoader(urls.toArray(new URL[0]), null); + } +} diff --git a/agents-common/src/test/java/org/apache/ranger/plugin/client/TestHadoopException.java b/agents-common/src/test/java/org/apache/ranger/plugin/client/TestHadoopException.java new file mode 100644 index 0000000000..4aa0437006 --- /dev/null +++ b/agents-common/src/test/java/org/apache/ranger/plugin/client/TestHadoopException.java @@ -0,0 +1,57 @@ +/* + * 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.ranger.plugin.client; + +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** +* @generated by Cursor +* @description +*/ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestHadoopException { + @Test + public void test01_generateResponseDataMap_populatesFields() { + HadoopException ex = new HadoopException("msg"); + ex.generateResponseDataMap(false, "m1", "d1", 10L, "f1"); + assertNotNull(ex.getResponseData()); + assertEquals(false, ex.getResponseData().get("connectivityStatus")); + assertEquals("m1", ex.getResponseData().get("message")); + assertEquals("d1", ex.getResponseData().get("description")); + assertEquals(10L, ex.getResponseData().get("objectId")); + assertEquals("f1", ex.getResponseData().get("fieldName")); + } + + @Test + public void test02_getMessage_collectsFromCauses() { + Exception inner = new Exception("inner"); + Exception outer = new Exception("outer", inner); + HadoopException ex = new HadoopException("wrap", outer); + String s = ex.getMessage(outer); + assertEquals("outer. \ninner. \n", s); + } +}