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

dhavalshah9131 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/master by this push:
     new 5dd493412 RANGER-5221 : Adding test cases for class 
RangerKeyStoreProvider (#599)
5dd493412 is described below

commit 5dd4934122b2a053aeae08db663427754d3d2a5f
Author: dhavalshah9131 <dhavalshah9...@gmail.com>
AuthorDate: Fri Jun 27 18:44:34 2025 +0530

    RANGER-5221 : Adding test cases for class RangerKeyStoreProvider (#599)
---
 .../key/kms/server/RangerKeyStoreProviderTest.java | 849 ++++++++++++++++++++-
 1 file changed, 842 insertions(+), 7 deletions(-)

diff --git 
a/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerKeyStoreProviderTest.java
 
b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerKeyStoreProviderTest.java
index 96168fb0c..8f68e2498 100644
--- 
a/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerKeyStoreProviderTest.java
+++ 
b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/RangerKeyStoreProviderTest.java
@@ -18,12 +18,16 @@
 package org.apache.hadoop.crypto.key.kms.server;
 
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.crypto.key.KeyProvider;
 import org.apache.hadoop.crypto.key.KeyProvider.KeyVersion;
 import org.apache.hadoop.crypto.key.KeyProvider.Options;
+import org.apache.hadoop.crypto.key.RangerKMSMKI;
+import org.apache.hadoop.crypto.key.RangerKeyStore;
 import org.apache.hadoop.crypto.key.RangerKeyStoreProvider;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import javax.crypto.Cipher;
@@ -31,9 +35,37 @@
 import javax.crypto.spec.SecretKeySpec;
 
 import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 /**
  * A test for the RangerKeyStoreProvider, which is an implementation of the 
Hadoop KeyProvider interface, which stores keys in a database.
@@ -57,6 +89,25 @@ public static void stopServers() throws Exception {
         }
     }
 
+    @BeforeEach
+    public void cleanUpKeyBeforeEachTest() throws Throwable {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
+        }
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration conf = new Configuration();
+        RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+        try {
+            keyProvider.deleteKey("newkey1");
+            keyProvider.flush();
+        } catch (IOException e) {
+            // Ignore if the key doesn't exist yet
+        }
+    }
+
     @Test
     public void testCreateDeleteKey() throws Throwable {
         if (!UNRESTRICTED_POLICIES_INSTALLED) {
@@ -66,7 +117,7 @@ public void testCreateDeleteKey() throws Throwable {
         Path configDir = Paths.get("src/test/resources/kms");
         System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
 
-        Configuration          conf        = new Configuration();
+        Configuration conf = new Configuration();
         RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
 
         // Create a key
@@ -84,14 +135,68 @@ public void testCreateDeleteKey() throws Throwable {
 
         keyProvider.flush();
         Assertions.assertEquals(0, keyProvider.getKeys().size());
+    }
 
-        // Try to delete a key that isn't there
-        try {
-            keyProvider.deleteKey("newkey2");
-            Assertions.fail("Failure expected on trying to delete an unknown 
key");
-        } catch (IOException ex) {
-            // expected
+    @Test
+    public void testDeleteKey_EngineDeleteEntryThrowsForBaseKey() throws 
Throwable {
+        Configuration          conf     = new Configuration();
+        RangerKeyStoreProvider provider = spy(new 
RangerKeyStoreProvider(conf));
+        RangerKeyStore         dbStore  = mock(RangerKeyStore.class);
+
+        // Inject mocked dbStore
+        Field dbStoreField = 
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+        dbStoreField.setAccessible(true);
+        dbStoreField.set(provider, dbStore);
+
+        // Mock Metadata
+        KeyProvider.Metadata metadata = mock(KeyProvider.Metadata.class);
+        when(metadata.getAlgorithm()).thenReturn("AES");
+        when(metadata.getBitLength()).thenReturn(128);
+        when(metadata.getDescription()).thenReturn("test description");
+        when(metadata.getVersions()).thenReturn(0); // No versions (only base 
key)
+        when(metadata.getAttributes()).thenReturn(new HashMap<>());
+
+        // Return mocked metadata
+        doReturn(metadata).when(provider).getMetadata("testKey");
+
+        // Simulate that base key alias exists
+        doReturn(true).when(dbStore).engineContainsAlias("testKey");
+
+        // Throw exception when trying to delete base key alias
+        doThrow(new KeyStoreException("Delete 
failed")).when(dbStore).engineDeleteEntry("testKey");
+
+        // Act & Assert
+        IOException ex = assertThrows(IOException.class, () -> 
provider.deleteKey("testKey"));
+        assertTrue(ex.getMessage().contains("Problem removing testKey from"));
+    }
+
+    @Test
+    public void testCreateKey() throws Throwable {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
         }
+
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf        = new Configuration();
+        RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+        // Create a key
+        Options options = new Options(conf);
+        options.setBitLength(256);
+        options.setCipher("AES");
+        KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+        Assertions.assertEquals("newkey1", keyVersion.getName());
+        Assertions.assertEquals(256 / 8, keyVersion.getMaterial().length);
+        Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+        keyProvider.flush();
+
+        // Validate the key exists
+        List<String> keys = keyProvider.getKeys();
+        Assertions.assertEquals(1, keys.size());
+        Assertions.assertEquals("newkey1", keys.get(0));
     }
 
     @Test
@@ -129,6 +234,736 @@ public void testRolloverKey() throws Throwable {
 
         keyProvider.flush();
         Assertions.assertEquals(0, keyProvider.getKeys().size());
+        try {
+            keyProvider.deleteKey("newkey1");
+            keyProvider.flush();
+        } catch (IOException e) {
+            // Ignore if key doesn't exist
+        }
+    }
+
+    @Test
+    public void testGetKeyVersion() throws Throwable {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
+        }
+
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf        = new Configuration();
+        RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+        // Create a key version
+        Options options = new Options(conf);
+        options.setBitLength(192);
+        options.setCipher("AES");
+        KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+
+        Assertions.assertEquals("newkey1", keyVersion.getName());
+        Assertions.assertEquals(192 / 8, keyVersion.getMaterial().length);
+        Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+        keyProvider.flush();
+
+        // Validate the key exists
+        Assertions.assertEquals(1, keyProvider.getKeys().size());
+
+        // Get key versions
+        List<KeyVersion> keyVersions = keyProvider.getKeyVersions("newkey1");
+        Assertions.assertEquals(1, keyVersions.size());
+
+        KeyVersion kv = keyVersions.get(0);
+        Assertions.assertEquals("newkey1", kv.getName());
+        Assertions.assertEquals(192 / 8, kv.getMaterial().length);
+        assertTrue(kv.getVersionName().startsWith("newkey1@"));
+
+        keyProvider.flush();
+        Assertions.assertNotEquals(0, keyProvider.getKeys().size());
+
+        // Try to get key versions of a non-existent key
+        try {
+            List<KeyVersion> invalidVersions = 
keyProvider.getKeyVersions("newkey2");
+            if (!invalidVersions.isEmpty()) {
+                Assertions.fail("Unexpected key version found: " + 
invalidVersions.get(0).getName());
+            }
+        } catch (IOException ex) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testGetKeys() throws Throwable {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
+        }
+
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf        = new Configuration();
+        RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+        // Create a key version
+        Options options = new Options(conf);
+        options.setBitLength(192);
+        options.setCipher("AES");
+        KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+
+        Assertions.assertEquals("newkey1", keyVersion.getName());
+        Assertions.assertEquals(192 / 8, keyVersion.getMaterial().length);
+        Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+        keyProvider.flush();
+
+        List<String> getkeys = keyProvider.getKeys();
+        Assertions.assertEquals(1, getkeys.size());
+        Assertions.assertEquals("newkey1", getkeys.get(0));
+
+        keyProvider.flush();
+        Assertions.assertNotEquals(0, keyProvider.getKeys().size());
+    }
+
+    @Test
+    public void testGetKeyVersionWithInvalidKey() throws Throwable {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
+        }
+
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf        = new Configuration();
+        RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+        // Try to get key versions of a non-existent key
+        try {
+            List<KeyVersion> invalidVersions = 
keyProvider.getKeyVersions("nonExistentKey");
+            assertTrue(invalidVersions.isEmpty(), "Expected no key versions 
for non-existent key");
+        } catch (IOException ex) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testGetKeyVersionWithInvalidVersion() throws Throwable {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
+        }
+
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf        = new Configuration();
+        RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+        // Create a key version
+        Options options = new Options(conf);
+        options.setBitLength(192);
+        options.setCipher("AES");
+        KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+
+        Assertions.assertEquals("newkey1", keyVersion.getName());
+        Assertions.assertEquals(192 / 8, keyVersion.getMaterial().length);
+        Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+        keyProvider.flush();
+
+        // Try to get an invalid version
+        try {
+            KeyVersion invalidVersion = 
keyProvider.getKeyVersion("newkey1@invalid");
+            Assertions.assertNull(invalidVersion, "Expected null for invalid 
version");
+        } catch (IOException ex) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testGetKeyVersions() throws Throwable {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
+        }
+
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf        = new Configuration();
+        RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+        // Create a key version
+        Options options = new Options(conf);
+        options.setBitLength(192);
+        options.setCipher("AES");
+        KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+
+        Assertions.assertEquals("newkey1", keyVersion.getName());
+        Assertions.assertEquals(192 / 8, keyVersion.getMaterial().length);
+        Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+        keyProvider.flush();
+
+        // Get key versions
+        List<KeyVersion> keyVersions = keyProvider.getKeyVersions("newkey1");
+        Assertions.assertEquals(1, keyVersions.size());
+
+        KeyVersion kv = keyVersions.get(0);
+        Assertions.assertEquals("newkey1", kv.getName());
+        Assertions.assertEquals(192 / 8, kv.getMaterial().length);
+        assertTrue(kv.getVersionName().startsWith("newkey1@"));
+    }
+
+    @Test
+    public void testGetMetadata() throws Throwable {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
+        }
+
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf        = new Configuration();
+        RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+        // Create a key version
+        Options options = new Options(conf);
+        options.setBitLength(192);
+        options.setCipher("AES");
+        KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+        Assertions.assertEquals("newkey1", keyVersion.getName());
+        Assertions.assertEquals(192 / 8, keyVersion.getMaterial().length);
+        Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+        keyProvider.flush();
+
+        // Get metadata
+        String metadata = String.valueOf(keyProvider.getMetadata("newkey1"));
+        assertNotNull(metadata, "Metadata should not be null");
+        assertTrue(metadata.contains("192"), "Metadata should contain key bit 
length");
+        assertTrue(metadata.contains("AES"), "Metadata should contain key 
cipher");
+    }
+
+    @Test
+    public void testGetKeyVersionWithInvalidKeyName() throws Throwable {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
+        }
+
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf        = new Configuration();
+        RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+        // Try to get key versions of a non-existent key
+        try {
+            KeyVersion invalidVersion = 
keyProvider.getKeyVersion("nonExistentKey@0");
+            Assertions.assertNull(invalidVersion, "Expected null for 
non-existent key version");
+        } catch (IOException ex) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testFlush() throws Throwable {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
+        }
+
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf        = new Configuration();
+        RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+        // Create a key version
+        Options options = new Options(conf);
+        options.setBitLength(192);
+        options.setCipher("AES");
+        KeyVersion keyVersion = keyProvider.createKey("newkey1", options);
+
+        Assertions.assertEquals("newkey1", keyVersion.getName());
+        Assertions.assertEquals(192 / 8, keyVersion.getMaterial().length);
+        Assertions.assertEquals("newkey1@0", keyVersion.getVersionName());
+
+        // Flush the provider
+        keyProvider.flush();
+
+        // Validate that the key is still present after flush
+        List<KeyVersion> keyVersions = keyProvider.getKeyVersions("newkey1");
+        Assertions.assertEquals(1, keyVersions.size());
+    }
+
+    @Test
+    public void testGetConfiguration() {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
+        }
+
+        String originalConfDir = 
System.getProperty(KMSConfiguration.KMS_CONFIG_DIR);
+
+        try {
+            System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
"relative/path");
+
+            Configuration conf = new Configuration();
+
+            RuntimeException ex = assertThrows(RuntimeException.class, () -> {
+                new RangerKeyStoreProvider(conf); // Should internally call 
getConfiguration()
+            });
+
+            assertTrue(ex.getMessage().contains("must be an absolute path"));
+        } finally {
+            if (originalConfDir != null) {
+                System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
originalConfDir);
+            } else {
+                System.clearProperty(KMSConfiguration.KMS_CONFIG_DIR);
+            }
+        }
+    }
+
+    @Test
+    public void testGetKeyVersionWithInvalidVersionName() throws Throwable {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
+        }
+
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf        = new Configuration();
+        RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+        // Try to get key version with an invalid version name
+        try {
+            KeyVersion invalidVersion = 
keyProvider.getKeyVersion("newkey1@invalid");
+            Assertions.assertNull(invalidVersion, "Expected null for invalid 
version name");
+        } catch (IOException ex) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testGetDBKSConf() throws Throwable {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
+        }
+
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf        = new Configuration();
+        RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+        // Get the DB configuration
+        Configuration dbConf = RangerKeyStoreProvider.getDBKSConf();
+        assertNotNull(dbConf, "DB configuration should not be null");
+    }
+
+    @Test
+    public void testRollNewVersion_ThrowsWhenKeyNotFound() throws Throwable {
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+        Configuration          conf     = new Configuration();
+        RangerKeyStoreProvider provider = new RangerKeyStoreProvider(conf);
+
+        byte[] dummyMaterial = new byte[16]; // 128-bit material
+
+        IOException exception = assertThrows(IOException.class, () ->
+                provider.rollNewVersion("nonExistingKey", dummyMaterial));
+
+        assertTrue(exception.getMessage().contains("Key nonExistingKey not 
found"));
+    }
+
+    @Test
+    public void testRollNewVersion_ThrowsWhenKeyLengthMismatch() throws 
Throwable {
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf     = new Configuration();
+        RangerKeyStoreProvider provider = new RangerKeyStoreProvider(conf);
+
+        Options options = new Options(conf);
+        options.setBitLength(128);
+        options.setCipher("AES");
+        provider.createKey("testKeyMismatch", options);
+        provider.flush();
+
+        // Use 192-bit material
+        byte[] wrongMaterial = new byte[24];
+
+        IOException exception = assertThrows(IOException.class, () ->
+                provider.rollNewVersion("testKeyMismatch", wrongMaterial));
+
+        assertTrue(exception.getMessage().contains("Wrong key length"));
+    }
+
+    @Test
+    public void testDeleteKey_MetadataIsNull() throws Throwable {
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf         = new Configuration();
+        RangerKeyStoreProvider realProvider = new RangerKeyStoreProvider(conf);
+
+        // Spy on the real provider to override getMetadata
+        RangerKeyStoreProvider provider = spy(realProvider);
+
+        // Simulate missing metadata
+        doReturn(null).when(provider).getMetadata("testKey");
+
+        // Act & Assert
+        IOException ex = assertThrows(IOException.class, () -> 
provider.deleteKey("testKey"));
+
+        // This now matches the real message thrown by deleteKey()
+        assertTrue(ex.getMessage().contains("Key testKey does not exist"));
+    }
+
+    @Test
+    public void testGetKeyVersion_DecryptKeyThrowsRuntimeException() throws 
Throwable {
+        Configuration          conf     = new Configuration();
+        RangerKeyStore         dbStore  = mock(RangerKeyStore.class);
+        RangerKeyStoreProvider provider = spy(new 
RangerKeyStoreProvider(conf));
+
+        // Inject dbStore
+        Field dbStoreField = 
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+        dbStoreField.setAccessible(true);
+        dbStoreField.set(provider, dbStore);
+
+        // Enable keyVault mode
+        Field keyVaultField = 
RangerKeyStoreProvider.class.getDeclaredField("keyVaultEnabled");
+        keyVaultField.setAccessible(true);
+        keyVaultField.set(provider, true);
+
+        // Setup mocks: alias exists, but decryption fails
+        doReturn(true).when(dbStore).engineContainsAlias("testKey");
+        doThrow(new RuntimeException("decryption 
failure")).when(dbStore).engineGetDecryptedZoneKeyByte("testKey");
+
+        RuntimeException ex = assertThrows(RuntimeException.class, () -> 
provider.getKeyVersion("testKey"));
+        assertTrue(ex.getMessage().contains("Error while getting decrypted 
key."));
+        assertTrue(ex.getMessage().contains("decryption failure"));
+    }
+
+    @Test
+    public void testGetKeyVersion_NoSuchAlgorithmException() throws Throwable {
+        Configuration          conf     = new Configuration();
+        RangerKeyStore         dbStore  = mock(RangerKeyStore.class);
+        RangerKeyStoreProvider provider = spy(new 
RangerKeyStoreProvider(conf));
+
+        // Inject dbStore
+        Field dbStoreField = 
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+        dbStoreField.setAccessible(true);
+        dbStoreField.set(provider, dbStore);
+
+        // Setup: alias exists, key fetch throws NoSuchAlgorithmException
+        doReturn(true).when(dbStore).engineContainsAlias("testKey");
+        doThrow(new 
NoSuchAlgorithmException()).when(dbStore).engineGetKey(eq("testKey"), any());
+
+        IOException ex = assertThrows(IOException.class, () -> 
provider.getKeyVersion("testKey"));
+
+        assertTrue(ex.getMessage().contains("Can't get algorithm for key"));
+
+        // Setup: alias exists, key fetch throws UnrecoverableKeyException
+        doReturn(true).when(dbStore).engineContainsAlias("testKey");
+        doThrow(new 
UnrecoverableKeyException()).when(dbStore).engineGetKey(eq("testKey"), any());
+
+        IOException ex1 = assertThrows(IOException.class, () -> 
provider.getKeyVersion("testKey"));
+
+        assertTrue(ex1.getMessage().contains("Can't recover key "));
+    }
+
+    @Test
+    public void testGetMetadata_GenericException() throws Throwable {
+        Configuration          conf     = new Configuration();
+        RangerKeyStoreProvider provider = spy(new 
RangerKeyStoreProvider(conf));
+        RangerKeyStore         dbStore  = mock(RangerKeyStore.class);
+
+        // Inject mocked dbStore
+        Field dbStoreField = 
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+        dbStoreField.setAccessible(true);
+        dbStoreField.set(provider, dbStore);
+
+        // Simulate exception during dbStore.engineContainsAlias for 
RuntimeException
+        when(dbStore.engineContainsAlias("testKey")).thenThrow(new 
RuntimeException("DB failure"));
+
+        IOException ex = assertThrows(IOException.class, () -> 
provider.getMetadata("testKey"));
+
+        assertTrue(ex.getMessage().contains("Please try again"));
+        assertTrue(ex.getCause().getMessage().contains("DB failure"));
+    }
+
+    @Test
+    public void testGetConfiguration1() throws Throwable {
+        if (!UNRESTRICTED_POLICIES_INSTALLED) {
+            return;
+        }
+
+        Path configDir = Paths.get("src/test/resources/kms");
+        System.setProperty(KMSConfiguration.KMS_CONFIG_DIR, 
configDir.toFile().getAbsolutePath());
+
+        Configuration          conf        = new Configuration();
+        RangerKeyStoreProvider keyProvider = new RangerKeyStoreProvider(conf);
+
+        // Get the configuration
+        Configuration keyProviderConf = keyProvider.getConf();
+        assertNotNull(keyProviderConf, "Configuration should not be null");
+    }
+
+    @Test
+    public void testSaveKey_ThrowsIOException() throws Throwable {
+        Configuration          conf     = new Configuration();
+        RangerKeyStoreProvider provider = spy(new 
RangerKeyStoreProvider(conf));
+        RangerKeyStore         dbStore  = mock(RangerKeyStore.class);
+
+        // Inject mocked dbStore
+        Field dbStoreField = 
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+        dbStoreField.setAccessible(true);
+        dbStoreField.set(provider, dbStore);
+
+        // Set keyVaultEnabled = false
+        Field keyVaultField = 
RangerKeyStoreProvider.class.getDeclaredField("keyVaultEnabled");
+        keyVaultField.setAccessible(true);
+        keyVaultField.set(provider, false);
+
+        // Mock Metadata with required getters
+        KeyProvider.Metadata metadata = mock(KeyProvider.Metadata.class);
+        when(metadata.getAlgorithm()).thenReturn("AES");
+        when(metadata.getBitLength()).thenReturn(128);
+        when(metadata.getDescription()).thenReturn("test description");
+        when(metadata.getVersions()).thenReturn(1);
+        when(metadata.getAttributes()).thenReturn(new HashMap<>());
+
+        // Mock exception on addKeyEntry
+        doThrow(new RuntimeException("decryption 
failure")).when(dbStore).addKeyEntry(
+                eq("testKey"),
+                any(),
+                any(),
+                eq("AES"),
+                eq(128),
+                eq("test description"),
+                eq(1),
+                any());
+
+        Method saveKeyMethod = 
RangerKeyStoreProvider.class.getDeclaredMethod("saveKey", String.class, 
KeyProvider.Metadata.class);
+        saveKeyMethod.setAccessible(true);
+
+        try {
+            saveKeyMethod.invoke(provider, "testKey", metadata);
+            fail("Expected IOException to be thrown");
+        } catch (InvocationTargetException e) {
+            Throwable cause = e.getCause();
+            assertInstanceOf(IOException.class, cause, "Cause should be 
IOException");
+            assertInstanceOf(RuntimeException.class, cause.getCause(), 
"IOException cause should be RuntimeException");
+            assertTrue(cause.getCause().getMessage().contains("decryption 
failure"));
+        }
+    }
+
+    @Test
+    public void testGetKeyVersion_KeyVaultTrue_SuccessPath() throws Throwable {
+        Configuration          conf     = new Configuration();
+        RangerKeyStoreProvider provider = spy(new 
RangerKeyStoreProvider(conf));
+        RangerKeyStore         dbStore  = mock(RangerKeyStore.class);
+
+        // Inject dbStore
+        Field dbStoreField = 
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+        dbStoreField.setAccessible(true);
+        dbStoreField.set(provider, dbStore);
+
+        // Set keyVaultEnabled = true
+        Field keyVaultField = 
RangerKeyStoreProvider.class.getDeclaredField("keyVaultEnabled");
+        keyVaultField.setAccessible(true);
+        keyVaultField.set(provider, true);
+
+        String versionedKey = "testKey@0";
+
+        // Simulate engineContainsAlias returns false first, then true
+        
when(dbStore.engineContainsAlias(versionedKey)).thenReturn(false).thenReturn(true);
+
+        // Simulate engineLoad
+        doNothing().when(dbStore).engineLoad(isNull(), any());
+
+        // Simulate decrypted key return
+        byte[] decryptedKey = new byte[] {0x01, 0x02, 0x03};
+        
when(dbStore.engineGetDecryptedZoneKeyByte(versionedKey)).thenReturn(decryptedKey);
+
+        // Act
+        KeyVersion result = provider.getKeyVersion(versionedKey);
+
+        // Assert
+        assertNotNull(result);
+        assertEquals(versionedKey, result.getVersionName());
+        assertEquals("testKey", result.getName());
+        assertArrayEquals(decryptedKey, result.getMaterial());
+    }
+
+    @Test
+    public void testGenerateAndGetMasterKey_generateMasterKeyThrows() throws 
Throwable {
+        Configuration          conf              = new Configuration();
+        RangerKeyStoreProvider provider          = spy(new 
RangerKeyStoreProvider(conf));
+        RangerKMSMKI           masterKeyProvider = mock(RangerKMSMKI.class);
+
+        // simulate generateMasterKey throwing an exception
+        doThrow(new RuntimeException("Simulated failure in 
generateMasterKey")).when(masterKeyProvider).generateMasterKey("abc123");
+
+        Method method = 
RangerKeyStoreProvider.class.getDeclaredMethod("generateAndGetMasterKey", 
RangerKMSMKI.class, String.class);
+        method.setAccessible(true);
+
+        RuntimeException ex = assertThrows(RuntimeException.class, () -> {
+            try {
+                method.invoke(provider, masterKeyProvider, "abc123");
+            } catch (InvocationTargetException e) {
+                throw e.getCause();
+            }
+        });
+
+        assertTrue(ex.getMessage().contains("Error while generating Ranger 
Master key"));
+    }
+
+    @Test
+    void testFlush_EngineStoreThrowsIOException() throws Throwable {
+        Configuration  conf    = new Configuration();
+        RangerKeyStore dbStore = mock(RangerKeyStore.class);
+        doThrow(new IOException("Flush 
failed")).when(dbStore).engineStore(any(), any());
+
+        RangerKeyStoreProvider provider = spy(new 
RangerKeyStoreProvider(conf));
+
+        // Inject mocks and changed = true
+        Field dbStoreField = 
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+        dbStoreField.setAccessible(true);
+        dbStoreField.set(provider, dbStore);
+
+        Field changedField = 
RangerKeyStoreProvider.class.getDeclaredField("changed");
+        changedField.setAccessible(true);
+        changedField.set(provider, true);
+
+        IOException ex = assertThrows(IOException.class, provider::flush);
+        assertTrue(ex.getMessage().contains("Flush failed"));
+
+        verify(dbStore, times(1)).engineStore(any(), any());
+    }
+
+    @Test
+    void testFlush_EngineStoreThrowsNoSuchAlgorithmException() throws 
Throwable {
+        Configuration  conf    = new Configuration();
+        RangerKeyStore dbStore = mock(RangerKeyStore.class);
+        doThrow(new 
NoSuchAlgorithmException()).when(dbStore).engineStore(any(), any());
+
+        RangerKeyStoreProvider provider = spy(new 
RangerKeyStoreProvider(conf));
+
+        Field dbStoreField = 
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+        dbStoreField.setAccessible(true);
+        dbStoreField.set(provider, dbStore);
+
+        Field changedField = 
RangerKeyStoreProvider.class.getDeclaredField("changed");
+        changedField.setAccessible(true);
+        changedField.set(provider, true);
+
+        IOException ex = assertThrows(IOException.class, provider::flush);
+        assertTrue(ex.getMessage().contains("No such algorithm storing key"));
+
+        verify(dbStore, times(1)).engineStore(any(), any());
+    }
+
+    @Test
+    void testFlush_EngineStoreThrowsCertificateException() throws Throwable {
+        Configuration  conf    = new Configuration();
+        RangerKeyStore dbStore = mock(RangerKeyStore.class);
+        doThrow(new CertificateException()).when(dbStore).engineStore(any(), 
any());
+
+        RangerKeyStoreProvider provider = spy(new 
RangerKeyStoreProvider(conf));
+
+        Field dbStoreField = 
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+        dbStoreField.setAccessible(true);
+        dbStoreField.set(provider, dbStore);
+
+        Field changedField = 
RangerKeyStoreProvider.class.getDeclaredField("changed");
+        changedField.setAccessible(true);
+        changedField.set(provider, true);
+
+        IOException ex = assertThrows(IOException.class, provider::flush);
+        assertTrue(ex.getMessage().contains("Certificate exception storing 
key"));
+
+        verify(dbStore, times(1)).engineStore(any(), any());
+    }
+
+    @Test
+    void testDeleteKey_ShouldThrowIOException() throws Throwable {
+        Configuration          conf     = new Configuration();
+        RangerKeyStore         dbStore  = mock(RangerKeyStore.class);
+        RangerKeyStoreProvider provider = spy(new 
RangerKeyStoreProvider(conf));
+
+        // Inject mocked dbStore
+        Field dbStoreField = 
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+        dbStoreField.setAccessible(true);
+        dbStoreField.set(provider, dbStore);
+
+        // Mock Metadata object with versions = 1
+        KeyProvider.Metadata metadata = mock(KeyProvider.Metadata.class);
+        when(metadata.getVersions()).thenReturn(1);
+
+        // Stub getMetadata to return mocked metadata
+        doReturn(metadata).when(provider).getMetadata("testKey");
+
+        // Stub dbStore responses for key existence
+        doReturn(true).when(dbStore).engineContainsAlias("testKey@0");
+        doReturn(true).when(dbStore).engineContainsAlias("testKey");
+
+        // Simulate KeyStoreException on deleting the version key
+        doThrow(new KeyStoreException("forced 
exception")).when(dbStore).engineDeleteEntry("testKey@0");
+
+        // Expect IOException because KeyStoreException is caught and wrapped
+        IOException ex = assertThrows(IOException.class, () -> 
provider.deleteKey("testKey"));
+        assertTrue(ex.getMessage().contains("Problem removing"));
+
+        // Verify interactions with dbStore mocks
+        verify(dbStore).engineContainsAlias("testKey@0");
+        verify(dbStore).engineDeleteEntry("testKey@0");
+    }
+
+    @Test
+    void testCreateKey_ShouldThrowIOException_WhenKeyAlreadyExists() throws 
Throwable {
+        Configuration          conf     = new Configuration();
+        RangerKeyStore         dbStore  = mock(RangerKeyStore.class);
+        RangerKeyStoreProvider provider = spy(new 
RangerKeyStoreProvider(conf));
+
+        // Inject mocked dbStore
+        Field dbStoreField = 
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+        dbStoreField.setAccessible(true);
+        dbStoreField.set(provider, dbStore);
+
+        String keyName  = "existingKey";
+        byte[] material = new byte[16]; // 128 bits
+        KeyProvider.Options options = new KeyProvider.Options(conf)
+                .setCipher("AES")
+                .setBitLength(128);
+
+        // Simulate that key already exists
+        when(dbStore.engineContainsAlias(keyName)).thenReturn(true);
+
+        IOException ex = assertThrows(IOException.class, () -> 
provider.createKey(keyName, material, options));
+        assertTrue(ex.getMessage().contains("Key " + keyName + " already 
exists"));
+    }
+
+    @Test
+    void testCreateKey_ShouldThrowIOException_WhenKeyLengthIncorrect() throws 
Throwable {
+        Configuration          conf     = new Configuration();
+        RangerKeyStore         dbStore  = mock(RangerKeyStore.class);
+        RangerKeyStoreProvider provider = spy(new 
RangerKeyStoreProvider(conf));
+
+        // Inject mocked dbStore
+        Field dbStoreField = 
RangerKeyStoreProvider.class.getDeclaredField("dbStore");
+        dbStoreField.setAccessible(true);
+        dbStoreField.set(provider, dbStore);
+
+        String keyName  = "newKey";
+        byte[] material = new byte[10]; // 80 bits
+        KeyProvider.Options options = new KeyProvider.Options(conf)
+                .setCipher("AES")
+                .setBitLength(128); // But expects 128 bits
+
+        // Simulate key does not exist
+        when(dbStore.engineContainsAlias(keyName)).thenReturn(false);
+
+        IOException ex = assertThrows(IOException.class, () -> 
provider.createKey(keyName, material, options));
+        assertTrue(ex.getMessage().contains("Wrong key length. Required 128, 
but got 80"));
     }
 
     static {


Reply via email to