From c2adac9b97575f18ad811383e55ff8d615e1a4f8 Mon Sep 17 00:00:00 2001 From: bhaavesh1567 Date: Mon, 20 Apr 2026 18:54:59 +0530 Subject: [PATCH] RANGER-5562:Add Unit Test Cases for agents-installer Module --- agents-installer/pom.xml | 20 + .../utils/install/TestXmlConfigChanger.java | 501 ++++++++++++++++++ 2 files changed, 521 insertions(+) create mode 100644 agents-installer/src/test/java/org/apache/ranger/utils/install/TestXmlConfigChanger.java diff --git a/agents-installer/pom.xml b/agents-installer/pom.xml index 325d631821..66842b062d 100644 --- a/agents-installer/pom.xml +++ b/agents-installer/pom.xml @@ -41,5 +41,25 @@ commons-compress ${commons.compress.version} + + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + org.mockito + mockito-junit-jupiter + ${mockito.version} + test + diff --git a/agents-installer/src/test/java/org/apache/ranger/utils/install/TestXmlConfigChanger.java b/agents-installer/src/test/java/org/apache/ranger/utils/install/TestXmlConfigChanger.java new file mode 100644 index 0000000000..8af1d23c51 --- /dev/null +++ b/agents-installer/src/test/java/org/apache/ranger/utils/install/TestXmlConfigChanger.java @@ -0,0 +1,501 @@ +/* + * 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.utils.install; + +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.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * @generated by Cursor + * @description : Unit Test cases for XmlConfigChanger + */ +@ExtendWith(MockitoExtension.class) +@TestMethodOrder(MethodOrderer.MethodName.class) +public class TestXmlConfigChanger { + @Test + void testMain_negative_missingOptionsEndsWithRuntimeException() { + Assertions.assertThrows(RuntimeException.class, () -> XmlConfigChanger.main(new String[0])); + } + + @Test + void testMain_positive_completesWithoutExitWhenFilesValid() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-main"); + tmp.toFile().deleteOnExit(); + + File inputXml = tmp.resolve("input.xml").toFile(); + File outputXml = tmp.resolve("output.xml").toFile(); + File configTxt = tmp.resolve("config.txt").toFile(); + + writeUtf8(inputXml.toPath(), sampleConfigurationXml()); + writeUtf8(configTxt.toPath(), "sample.key replaced mod\n"); + + String[] args = new String[] { + "-i", inputXml.getAbsolutePath(), + "-o", outputXml.getAbsolutePath(), + "-c", configTxt.getAbsolutePath() + }; + + Assertions.assertDoesNotThrow(() -> XmlConfigChanger.main(args)); + + Assertions.assertTrue(outputXml.exists()); + Assertions.assertTrue(readUtf8(outputXml.toPath()).contains("replaced")); + } + + @Test + void testParseConfig_negative_configNotReadableThrows() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-parse-cfg"); + tmp.toFile().deleteOnExit(); + + File inputXml = tmp.resolve("input.xml").toFile(); + File outputXml = tmp.resolve("output.xml").toFile(); + File missingCfg = tmp.resolve("nope.txt").toFile(); + + writeUtf8(inputXml.toPath(), sampleConfigurationXml()); + + XmlConfigChanger changer = new XmlConfigChanger(); + String[] args = new String[] { + "-i", inputXml.getAbsolutePath(), + "-o", outputXml.getAbsolutePath(), + "-c", missingCfg.getAbsolutePath() + }; + + Assertions.assertThrows(RuntimeException.class, () -> changer.parseConfig(args)); + } + + @Test + void testParseConfig_negative_installPropNotReadableThrows() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-parse-p"); + tmp.toFile().deleteOnExit(); + + File inputXml = tmp.resolve("input.xml").toFile(); + File outputXml = tmp.resolve("output.xml").toFile(); + File configTxt = tmp.resolve("config.txt").toFile(); + File missingProp = tmp.resolve("missing.properties").toFile(); + + writeUtf8(inputXml.toPath(), sampleConfigurationXml()); + writeUtf8(configTxt.toPath(), "a b add\n"); + + XmlConfigChanger changer = new XmlConfigChanger(); + String[] args = new String[] { + "-i", inputXml.getAbsolutePath(), + "-o", outputXml.getAbsolutePath(), + "-c", configTxt.getAbsolutePath(), + "-p", missingProp.getAbsolutePath() + }; + + Assertions.assertThrows(RuntimeException.class, () -> changer.parseConfig(args)); + } + + @Test + void testParseConfig_negative_outputAlreadyExistsThrows() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-parse-out"); + tmp.toFile().deleteOnExit(); + + File inputXml = tmp.resolve("input.xml").toFile(); + File outputXml = tmp.resolve("output.xml").toFile(); + File configTxt = tmp.resolve("config.txt").toFile(); + + writeUtf8(inputXml.toPath(), sampleConfigurationXml()); + writeUtf8(configTxt.toPath(), "a b add\n"); + writeUtf8(outputXml.toPath(), "exists\n"); + + XmlConfigChanger changer = new XmlConfigChanger(); + String[] args = new String[] { + "-i", inputXml.getAbsolutePath(), + "-o", outputXml.getAbsolutePath(), + "-c", configTxt.getAbsolutePath() + }; + + Assertions.assertThrows(RuntimeException.class, () -> changer.parseConfig(args)); + } + + @Test + void testParseConfig_negative_unreadableInputThrows() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-parse-neg"); + tmp.toFile().deleteOnExit(); + + File missingIn = tmp.resolve("noin.xml").toFile(); + File outXml = tmp.resolve("out.xml").toFile(); + File cfg = tmp.resolve("cfg.txt").toFile(); + + writeUtf8(cfg.toPath(), "a b add\n"); + + XmlConfigChanger changer = new XmlConfigChanger(); + String[] args = new String[] { + "-i", missingIn.getAbsolutePath(), + "-o", outXml.getAbsolutePath(), + "-c", cfg.getAbsolutePath() + }; + + Assertions.assertThrows(RuntimeException.class, () -> changer.parseConfig(args)); + } + + @Test + void testParseConfig_positive_acceptsReadableFiles() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-parse-pos"); + tmp.toFile().deleteOnExit(); + + File inputXml = tmp.resolve("input.xml").toFile(); + File outputXml = tmp.resolve("output.xml").toFile(); + File configTxt = tmp.resolve("config.txt").toFile(); + + writeUtf8(inputXml.toPath(), sampleConfigurationXml()); + writeUtf8(configTxt.toPath(), "sample.key v add\n"); + + XmlConfigChanger changer = new XmlConfigChanger(); + String[] args = new String[] { + "-i", inputXml.getAbsolutePath(), + "-o", outputXml.getAbsolutePath(), + "-c", configTxt.getAbsolutePath() + }; + + Assertions.assertDoesNotThrow(() -> changer.parseConfig(args)); + } + + @Test + void testParseConfig_positive_acceptsReadableInstallProp() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-parse-prop"); + tmp.toFile().deleteOnExit(); + + File inputXml = tmp.resolve("input.xml").toFile(); + File outputXml = tmp.resolve("output.xml").toFile(); + File configTxt = tmp.resolve("config.txt").toFile(); + File installProp = tmp.resolve("install.properties").toFile(); + + writeUtf8(inputXml.toPath(), sampleConfigurationXml()); + writeUtf8(configTxt.toPath(), "a b add\n"); + writeUtf8(installProp.toPath(), "k=v\n"); + + XmlConfigChanger changer = new XmlConfigChanger(); + String[] args = new String[] { + "-i", inputXml.getAbsolutePath(), + "-o", outputXml.getAbsolutePath(), + "-c", configTxt.getAbsolutePath(), + "-p", installProp.getAbsolutePath() + }; + + Assertions.assertDoesNotThrow(() -> changer.parseConfig(args)); + } + + @Test + void testRun_negative_replacePropMissingTokenThrows() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-run-miss"); + tmp.toFile().deleteOnExit(); + + File inputXml = tmp.resolve("input.xml").toFile(); + File outputXml = tmp.resolve("output.xml").toFile(); + File configTxt = tmp.resolve("config.txt").toFile(); + File installProp = tmp.resolve("install.properties").toFile(); + + writeUtf8(inputXml.toPath(), sampleConfigurationXml()); + writeUtf8(configTxt.toPath(), "sample.key %NOT_HERE% mod\n"); + writeUtf8(installProp.toPath(), "other=something\n"); + + XmlConfigChanger changer = new XmlConfigChanger(); + changer.parseConfig(new String[] { + "-i", inputXml.getAbsolutePath(), + "-o", outputXml.getAbsolutePath(), + "-c", configTxt.getAbsolutePath(), + "-p", installProp.getAbsolutePath() + }); + + Assertions.assertThrows(RuntimeException.class, changer::run); + } + + @Test + void testRun_negative_replacePropUnclosedTokenThrows() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-run-open"); + tmp.toFile().deleteOnExit(); + + File inputXml = tmp.resolve("input.xml").toFile(); + File outputXml = tmp.resolve("output.xml").toFile(); + File configTxt = tmp.resolve("config.txt").toFile(); + + writeUtf8(inputXml.toPath(), sampleConfigurationXml()); + writeUtf8(configTxt.toPath(), "sample.key %OPEN mod\n"); + + XmlConfigChanger changer = new XmlConfigChanger(); + changer.parseConfig(new String[] { + "-i", inputXml.getAbsolutePath(), + "-o", outputXml.getAbsolutePath(), + "-c", configTxt.getAbsolutePath() + }); + + Assertions.assertThrows(RuntimeException.class, changer::run); + } + + @Test + void testRun_negative_unknownActionThrows() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-run-neg"); + tmp.toFile().deleteOnExit(); + + File inputXml = tmp.resolve("input.xml").toFile(); + File outputXml = tmp.resolve("output.xml").toFile(); + File configTxt = tmp.resolve("config.txt").toFile(); + + writeUtf8(inputXml.toPath(), sampleConfigurationXml()); + writeUtf8(configTxt.toPath(), "sample.key x unknownverb\n"); + + XmlConfigChanger changer = new XmlConfigChanger(); + changer.parseConfig(new String[] { + "-i", inputXml.getAbsolutePath(), + "-o", outputXml.getAbsolutePath(), + "-c", configTxt.getAbsolutePath() + }); + + Assertions.assertThrows(RuntimeException.class, changer::run); + } + + @Test + void testRun_positive_installPropFileIoFailureHandled() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-run-propio"); + tmp.toFile().deleteOnExit(); + + File inputXml = tmp.resolve("input.xml").toFile(); + File outputXml = tmp.resolve("output.xml").toFile(); + File configTxt = tmp.resolve("config.txt").toFile(); + File propAsDir = tmp.resolve("prophasdir").toFile(); + + Assertions.assertTrue(propAsDir.mkdir()); + + writeUtf8(inputXml.toPath(), sampleConfigurationXml()); + writeUtf8(configTxt.toPath(), "sample.key fromenv mod\n"); + + XmlConfigChanger changer = new XmlConfigChanger(); + changer.parseConfig(new String[] { + "-i", inputXml.getAbsolutePath(), + "-o", outputXml.getAbsolutePath(), + "-c", configTxt.getAbsolutePath(), + "-p", propAsDir.getAbsolutePath() + }); + + Assertions.assertDoesNotThrow(changer::run); + Assertions.assertTrue(outputXml.exists()); + } + + @Test + void testRun_positive_skipsBlankCommentAndInlineCommentLines() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-run-cmnt"); + tmp.toFile().deleteOnExit(); + + File inputXml = tmp.resolve("input.xml").toFile(); + File outputXml = tmp.resolve("output.xml").toFile(); + File configTxt = tmp.resolve("config.txt").toFile(); + + writeUtf8(inputXml.toPath(), sampleConfigurationXml()); + writeUtf8(configTxt.toPath(), + "\n" + + "# full line comment\n" + + "sample.key aftercomment mod # inline stripped\n"); + + XmlConfigChanger changer = new XmlConfigChanger(); + changer.parseConfig(new String[] { + "-i", inputXml.getAbsolutePath(), + "-o", outputXml.getAbsolutePath(), + "-c", configTxt.getAbsolutePath() + }); + + changer.run(); + Assertions.assertTrue(readUtf8(outputXml.toPath()).contains("aftercomment")); + } + + @Test + void testRun_positive_writesModifiedXml() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-run-pos"); + tmp.toFile().deleteOnExit(); + + File inputXml = tmp.resolve("input.xml").toFile(); + File outputXml = tmp.resolve("output.xml").toFile(); + File configTxt = tmp.resolve("config.txt").toFile(); + + writeUtf8(inputXml.toPath(), sampleConfigurationXml()); + writeUtf8(configTxt.toPath(), "sample.key newvalue mod\n"); + + XmlConfigChanger changer = new XmlConfigChanger(); + changer.parseConfig(new String[] { + "-i", inputXml.getAbsolutePath(), + "-o", outputXml.getAbsolutePath(), + "-c", configTxt.getAbsolutePath() + }); + + changer.run(); + + Assertions.assertTrue(outputXml.exists()); + String out = readUtf8(outputXml.toPath()); + + Assertions.assertTrue(out.contains("newvalue")); + Assertions.assertFalse(out.contains("original")); + } + + @Test + void testRun_positive_exercisesAddDelAppendDelvalVarSubstAndInstallProps() throws Exception { + Path tmp = Files.createTempDirectory("xmlcc-run-all"); + tmp.toFile().deleteOnExit(); + + File inputXml = tmp.resolve("input.xml").toFile(); + File outputXml = tmp.resolve("output.xml").toFile(); + File configTxt = tmp.resolve("config.txt").toFile(); + File installProp = tmp.resolve("install.properties").toFile(); + + writeUtf8(inputXml.toPath(), multiPropertyConfigurationXml()); + writeUtf8(installProp.toPath(), + "EMPTY_MARK=%EMPTY%\n" + + "PLUS=inserted\n"); + writeUtf8(configTxt.toPath(), + "PREFIX pre var\n" + + "%PREFIX%_added val%PLUS% add\n" + + "inline.key plain add # tail comment\n" + + "to.delete x del\n" + + "empty.val was-empty mod\n" + + "empty.val %EMPTY_MARK% mod\n" + + "sample.key pre%PLUS%suf mod\n" + + "list.key second append create-if-not-exists ,\n" + + "brand.new appended append create-if-not-exists\n" + + "empty.append tail append\n" + + "append.dup dup append\n" + + "delval.list p2 delval\n" + + "comma.list c2 delval create-if-not-exists ,\n" + + "really.missing noop mod\n" + + "missing.key created mod create-if-not-exists\n"); + + XmlConfigChanger changer = new XmlConfigChanger(); + changer.parseConfig(new String[] { + "-i", inputXml.getAbsolutePath(), + "-o", outputXml.getAbsolutePath(), + "-c", configTxt.getAbsolutePath(), + "-p", installProp.getAbsolutePath() + }); + + changer.run(); + + String out = readUtf8(outputXml.toPath()); + Assertions.assertFalse(out.contains("to.delete")); + Assertions.assertTrue(out.contains("pre_added")); + Assertions.assertTrue(out.contains("inline.key")); + Assertions.assertTrue(out.contains("valinserted")); + Assertions.assertTrue(out.contains("preinsertedsuf")); + Assertions.assertTrue(out.contains("second")); + Assertions.assertTrue(out.contains("brand.new")); + Assertions.assertTrue(out.contains("tail")); + Assertions.assertTrue(out.contains("missing.key")); + Assertions.assertTrue(out.contains("created")); + Assertions.assertTrue(out.contains("p1 p3")); + Assertions.assertFalse(out.contains("p1 p2 p3")); + Assertions.assertTrue(out.contains("c1,c3")); + Assertions.assertFalse(out.contains("c1,c2,c3")); + } + + @Test + void testValidationException_negative_nullCause() { + XmlConfigChanger.ValidationException ex = new XmlConfigChanger.ValidationException((Throwable) null); + + Assertions.assertNull(ex.getCause()); + } + + @Test + void testValidationException_positive_wrapsThrowableCause() { + IllegalArgumentException cause = new IllegalArgumentException("nested"); + XmlConfigChanger.ValidationException ex = new XmlConfigChanger.ValidationException(cause); + + Assertions.assertSame(cause, ex.getCause()); + } + + private static String multiPropertyConfigurationXml() { + return "\n" + + "<" + XmlConfigChanger.ROOT_NODE_NAME + ">\n" + + " <" + XmlConfigChanger.PROPERTY_NODE_NAME + ">\n" + + " <" + XmlConfigChanger.NAME_NODE_NAME + ">sample.key\n" + + " <" + XmlConfigChanger.VALUE_NODE_NAME + ">orig\n" + + " \n" + + " <" + XmlConfigChanger.PROPERTY_NODE_NAME + ">\n" + + " <" + XmlConfigChanger.NAME_NODE_NAME + ">to.delete\n" + + " <" + XmlConfigChanger.VALUE_NODE_NAME + ">x\n" + + " \n" + + " <" + XmlConfigChanger.PROPERTY_NODE_NAME + ">\n" + + " <" + XmlConfigChanger.NAME_NODE_NAME + ">list.key\n" + + " <" + XmlConfigChanger.VALUE_NODE_NAME + ">first\n" + + " \n" + + " <" + XmlConfigChanger.PROPERTY_NODE_NAME + ">\n" + + " <" + XmlConfigChanger.NAME_NODE_NAME + ">empty.val\n" + + " <" + XmlConfigChanger.VALUE_NODE_NAME + ">\n" + + " \n" + + " <" + XmlConfigChanger.PROPERTY_NODE_NAME + ">\n" + + " <" + XmlConfigChanger.NAME_NODE_NAME + ">empty.append\n" + + " <" + XmlConfigChanger.VALUE_NODE_NAME + ">\n" + + " \n" + + " <" + XmlConfigChanger.PROPERTY_NODE_NAME + ">\n" + + " <" + XmlConfigChanger.NAME_NODE_NAME + ">append.dup\n" + + " <" + XmlConfigChanger.VALUE_NODE_NAME + ">same\n" + + " \n" + + " <" + XmlConfigChanger.PROPERTY_NODE_NAME + ">\n" + + " <" + XmlConfigChanger.NAME_NODE_NAME + ">delval.list\n" + + " <" + XmlConfigChanger.VALUE_NODE_NAME + ">p1 p2 p3\n" + + " \n" + + " <" + XmlConfigChanger.PROPERTY_NODE_NAME + ">\n" + + " <" + XmlConfigChanger.NAME_NODE_NAME + ">comma.list\n" + + " <" + XmlConfigChanger.VALUE_NODE_NAME + ">c1,c2,c3\n" + + " \n" + + "\n"; + } + + private static String sampleConfigurationXml() { + return "\n" + + "<" + XmlConfigChanger.ROOT_NODE_NAME + ">\n" + + " <" + XmlConfigChanger.PROPERTY_NODE_NAME + ">\n" + + " <" + XmlConfigChanger.NAME_NODE_NAME + ">sample.key\n" + + " <" + XmlConfigChanger.VALUE_NODE_NAME + ">original\n" + + " \n" + + "\n"; + } + + private static void writeUtf8(Path path, String text) throws IOException { + Files.write(path, text.getBytes(StandardCharsets.UTF_8)); + } + + private static String readUtf8(Path path) throws IOException { + return new String(Files.readAllBytes(path), StandardCharsets.UTF_8); + } +}