From 77e11db68b1c0d0aaee3aa060d0716a5971b0c29 Mon Sep 17 00:00:00 2001 From: Bartosz Spyrko-Smietanko Date: Mon, 8 Jul 2024 15:48:42 +0100 Subject: [PATCH 1/3] [WFCORE-6893] Add information to product-info --- .../GlobalInstallationReportHandler.java | 1 + .../operations/InstallationReportHandler.java | 14 ++++---- .../core/instmgr/InstMgrConstants.java | 3 ++ .../core/instmgr/InstMgrHistoryHandler.java | 11 +++++- .../core/instmgr/cli/HistoryCommand.java | 11 ++++-- .../AbstractInstallationReporter.java | 36 ++++++++++++++----- .../operations/InstallationReportHandler.java | 15 ++++---- .../TestInstallationManager.java | 9 ++--- 8 files changed, 70 insertions(+), 30 deletions(-) diff --git a/controller/src/main/java/org/jboss/as/controller/operations/global/GlobalInstallationReportHandler.java b/controller/src/main/java/org/jboss/as/controller/operations/global/GlobalInstallationReportHandler.java index bad7b77bb9d..94a86a86070 100644 --- a/controller/src/main/java/org/jboss/as/controller/operations/global/GlobalInstallationReportHandler.java +++ b/controller/src/main/java/org/jboss/as/controller/operations/global/GlobalInstallationReportHandler.java @@ -66,6 +66,7 @@ public class GlobalInstallationReportHandler extends GlobalOperationHandlers.Abs public static final String PRODUCT_HOME = "product-home"; public static final String PRODUCT_INSTALLATION_DATE = "installation-date"; public static final String PRODUCT_LAST_UPDATE = "last-update-date"; + public static final String PRODUCT_CHANNEL_VERSIONS = "channel-versions"; public static final String STANDALONE_DOMAIN_IDENTIFIER = "standalone-or-domain-identifier"; public static final String SUMMARY = "summary"; diff --git a/host-controller/src/main/java/org/jboss/as/host/controller/operations/InstallationReportHandler.java b/host-controller/src/main/java/org/jboss/as/host/controller/operations/InstallationReportHandler.java index d499fc69d3d..7357cff1475 100644 --- a/host-controller/src/main/java/org/jboss/as/host/controller/operations/InstallationReportHandler.java +++ b/host-controller/src/main/java/org/jboss/as/host/controller/operations/InstallationReportHandler.java @@ -53,13 +53,13 @@ private InstallationReportHandler(HostControllerEnvironment environment) { @Override public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { - final ModelNode patchingInfo = new ModelNode(); - PathAddress patchingAddress = PathAddress.pathAddress( + final ModelNode installerInfo = new ModelNode(); + PathAddress installerAddress = PathAddress.pathAddress( PathElement.pathElement(HOST, environment.getHostControllerName()), - PathElement.pathElement(CORE_SERVICE, "patching")); - OperationEntry opEntry = context.getRootResourceRegistration().getOperationEntry(patchingAddress, "show-history"); - if(opEntry != null) { - context.addStep(patchingInfo, Util.createOperation("show-history", patchingAddress), + PathElement.pathElement(CORE_SERVICE, "installer")); + OperationEntry opEntry = context.getRootResourceRegistration().getOperationEntry(installerAddress, "history"); + if (opEntry != null) { + context.addStep(installerInfo, Util.createOperation("history", installerAddress), opEntry.getOperationHandler(), OperationContext.Stage.RUNTIME); } final Path installationDir = environment.getHomeDir().toPath(); @@ -68,7 +68,7 @@ public void execute(OperationContext context, ModelNode operation) throws Operat public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { ModelNode result = context.getResult(); result.get(SUMMARY_DEFINITION.getName()).set(createProductNode(context, new InstallationConfiguration( - environment, environment.getProductConfig(), patchingInfo, installationDir))); + environment, environment.getProductConfig(), installerInfo, installationDir))); } }, OperationContext.Stage.RUNTIME); } diff --git a/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrConstants.java b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrConstants.java index 2abebd93f1f..bd03ace3e88 100644 --- a/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrConstants.java +++ b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrConstants.java @@ -33,6 +33,7 @@ public interface InstMgrConstants { String HISTORY_DETAILED_CHANNEL_REPOSITORIES = "repositories"; String HISTORY_DETAILED_CHANNEL_STATUS = "status"; String HISTORY_RESULT_DESCRIPTION = "description"; + String HISTORY_RESULT_CHANNEL_VERSIONS = "channel-versions"; String HISTORY_RESULT_DETAILED_ARTIFACT_CHANGES = "artifact-changes"; String HISTORY_RESULT_DETAILED_CHANNEL_CHANGES = "channel-changes"; String HISTORY_RESULT_HASH = "hash"; @@ -62,4 +63,6 @@ public interface InstMgrConstants { String REVISION = "revision"; String TOOL_NAME = "installer"; String INTERNAL_REPO_PREFIX = "repo-"; + String INSTALLED_VERSIONS = "installed-versions"; + String VERSION = "version"; } diff --git a/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrHistoryHandler.java b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrHistoryHandler.java index 728da3826ec..ac3f8788f9f 100644 --- a/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrHistoryHandler.java +++ b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrHistoryHandler.java @@ -18,10 +18,12 @@ import org.jboss.dmr.ModelNode; import org.jboss.dmr.ModelType; import org.wildfly.installationmanager.HistoryResult; +import org.wildfly.installationmanager.ManifestVersion; import org.wildfly.installationmanager.MavenOptions; import org.wildfly.installationmanager.spi.InstallationManager; import org.wildfly.installationmanager.spi.InstallationManagerFactory; + /** * Operation handler to get the history of the installation manager changes, either artifacts or configuration metadata as * channel changes. @@ -53,6 +55,13 @@ public void execute(OperationContext context, ModelNode operation) throws Operat entry.get(InstMgrConstants.HISTORY_RESULT_HASH).set(hr.getName()); entry.get(InstMgrConstants.HISTORY_RESULT_TIMESTAMP).set(hr.timestamp().toString()); entry.get(InstMgrConstants.HISTORY_RESULT_TYPE).set(hr.getType().toLowerCase(Locale.ENGLISH)); + if (hr.getVersions() != null && !hr.getVersions().isEmpty()) { + final ModelNode versions = entry.get(InstMgrConstants.HISTORY_RESULT_CHANNEL_VERSIONS); + hr.getVersions().stream() + .map(ManifestVersion::getDescription) + .map(ModelNode::new) + .forEach(versions::add); + } if (hr.getDescription() != null) { entry.get(InstMgrConstants.HISTORY_RESULT_DESCRIPTION).set(hr.getDescription()); } @@ -66,6 +75,6 @@ public void execute(OperationContext context, ModelNode operation) throws Operat throw new RuntimeException(e); } } - }, OperationContext.Stage.RUNTIME); + }, OperationContext.Stage.RUNTIME, true); } } diff --git a/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/HistoryCommand.java b/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/HistoryCommand.java index 83500dd8752..6f6b29b7bb6 100644 --- a/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/HistoryCommand.java +++ b/installation-manager/src/main/java/org/wildfly/core/instmgr/cli/HistoryCommand.java @@ -9,6 +9,7 @@ import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT; import java.util.List; +import java.util.stream.Collectors; import org.aesh.command.CommandDefinition; import org.aesh.command.CommandException; @@ -109,8 +110,14 @@ public CommandResult execute(CLICommandInvocation commandInvocation) throws Comm String hash = resultMn.get(InstMgrConstants.HISTORY_RESULT_HASH).asString(); String timeStamp = resultMn.get(InstMgrConstants.HISTORY_RESULT_TIMESTAMP).asString(); String type = resultMn.get(InstMgrConstants.HISTORY_RESULT_TYPE).asString(); - String description = resultMn.get(InstMgrConstants.HISTORY_RESULT_DESCRIPTION).asStringOrNull(); - description = description == null ? "[]" : description; + final List versions = resultMn.get(InstMgrConstants.HISTORY_RESULT_CHANNEL_VERSIONS).asListOrEmpty().stream().map(ModelNode::asString).collect(Collectors.toList()); + String description; + if (versions.isEmpty()) { + description = resultMn.get(InstMgrConstants.HISTORY_RESULT_DESCRIPTION).asStringOrNull(); + description = description == null ? "[]" : description; + } else { + description = "[" + String.join(" + ", versions) + "]"; + } ctx.printLine(String.format("[%s] %s - %s %s", hash, timeStamp, type, description)); } } diff --git a/server/src/main/java/org/jboss/as/server/operations/AbstractInstallationReporter.java b/server/src/main/java/org/jboss/as/server/operations/AbstractInstallationReporter.java index afa6a3331ed..ac99cbdf7ee 100644 --- a/server/src/main/java/org/jboss/as/server/operations/AbstractInstallationReporter.java +++ b/server/src/main/java/org/jboss/as/server/operations/AbstractInstallationReporter.java @@ -22,6 +22,7 @@ import static org.jboss.as.controller.operations.global.GlobalInstallationReportHandler.JVM_VENDOR; import static org.jboss.as.controller.operations.global.GlobalInstallationReportHandler.JVM_VERSION; import static org.jboss.as.controller.operations.global.GlobalInstallationReportHandler.OS; +import static org.jboss.as.controller.operations.global.GlobalInstallationReportHandler.PRODUCT_CHANNEL_VERSIONS; import static org.jboss.as.controller.operations.global.GlobalInstallationReportHandler.PRODUCT_TYPE; import static org.jboss.as.controller.operations.global.GlobalInstallationReportHandler.PRODUCT_COMMUNITY_IDENTIFIER; import static org.jboss.as.controller.operations.global.GlobalInstallationReportHandler.PRODUCT_HOME; @@ -39,6 +40,7 @@ import java.util.List; import java.util.Locale; import java.util.Properties; + import org.jboss.as.controller.OperationContext; import org.jboss.as.controller.OperationFailedException; import org.jboss.as.controller.OperationStepHandler; @@ -174,6 +176,10 @@ protected ModelNode createProductNode(OperationContext context, InstallationConf product.get(OS).set(createOSNode()); product.get(CPU).set(createCPUNode()); product.get(JVM).set(createJVMNode()); + List channelVersions = installation.getChannelVersions(); + if (channelVersions != null && !channelVersions.isEmpty()) { + product.get(PRODUCT_CHANNEL_VERSIONS).set(channelVersions); + } return product; } @@ -275,18 +281,18 @@ protected static final class InstallationConfiguration { private final ProcessEnvironment environment; private final ProductConfig config; - private final ModelNode patchingInfo; + private final ModelNode installerInfo; private final Path installationDir; - public InstallationConfiguration(ProcessEnvironment environment, ProductConfig config, ModelNode patchingInfo, Path installationDir) { + public InstallationConfiguration(ProcessEnvironment environment, ProductConfig config, ModelNode installerInfo, Path installationDir) { assert environment != null; assert config != null; - assert patchingInfo != null; + assert installerInfo != null; assert installationDir != null; this.environment = environment; this.config = config; - this.patchingInfo = patchingInfo; + this.installerInfo = installerInfo; this.installationDir = installationDir; } @@ -310,11 +316,23 @@ String getInstallationDir() { } String getLastUpdateDate() { - if (patchingInfo.isDefined()) { - List result = Operations.readResult(patchingInfo).asList(); - for (ModelNode patchAtt : result) { - if (patchAtt.has("applied-at")) { - return patchAtt.get("applied-at").asString(); + if (installerInfo.get("result").isDefined()) { + List result = Operations.readResult(installerInfo).asList(); + for (ModelNode installerAtt : result) { + if (installerAtt.has("timestamp")) { + return installerAtt.get("timestamp").asString(); + } + } + } + return null; + } + + List getChannelVersions() { + if (installerInfo.get("result").isDefined()) { + List result = Operations.readResult(installerInfo).asList(); + for (ModelNode installerAtt : result) { + if (installerAtt.has("channel-versions")) { + return installerAtt.get("channel-versions").asList(); } } } diff --git a/server/src/main/java/org/jboss/as/server/operations/InstallationReportHandler.java b/server/src/main/java/org/jboss/as/server/operations/InstallationReportHandler.java index 91ad55426fd..262d2fffb55 100644 --- a/server/src/main/java/org/jboss/as/server/operations/InstallationReportHandler.java +++ b/server/src/main/java/org/jboss/as/server/operations/InstallationReportHandler.java @@ -50,20 +50,21 @@ private InstallationReportHandler(ServerEnvironment environment) { @Override public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { - final ModelNode patchingInfo = new ModelNode(); - PathAddress patchingAddress = PathAddress.pathAddress(PathElement.pathElement(CORE_SERVICE, "patching")); - OperationEntry opEntry = context.getRootResourceRegistration().getOperationEntry(patchingAddress, "show-history"); - if(opEntry != null) { - context.addStep(patchingInfo, Util.createOperation("show-history", patchingAddress), - opEntry.getOperationHandler(), OperationContext.Stage.RUNTIME); + final ModelNode installerInfo = new ModelNode(); + final PathAddress installerAddress = PathAddress.pathAddress(PathElement.pathElement(CORE_SERVICE, "installer")); + final OperationEntry installerOpEntry = context.getRootResourceRegistration().getOperationEntry(installerAddress, "history"); + if (installerOpEntry != null) { + context.addStep(installerInfo, Util.createOperation("history", installerAddress), + installerOpEntry.getOperationHandler(), OperationContext.Stage.RUNTIME); } + final Path installationDir = environment.getHomeDir().toPath(); context.addStep(new OperationStepHandler() { @Override public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { ModelNode result = context.getResult(); result.get(SUMMARY_DEFINITION.getName()).set(createProductNode(context, new InstallationConfiguration( - environment, environment.getProductConfig(), patchingInfo, installationDir))); + environment, environment.getProductConfig(), installerInfo, installationDir))); } }, OperationContext.Stage.RUNTIME); } diff --git a/testsuite/shared/src/main/java/org/wildfly/test/installationmanager/TestInstallationManager.java b/testsuite/shared/src/main/java/org/wildfly/test/installationmanager/TestInstallationManager.java index 91b5a3928e4..e1363029cfe 100644 --- a/testsuite/shared/src/main/java/org/wildfly/test/installationmanager/TestInstallationManager.java +++ b/testsuite/shared/src/main/java/org/wildfly/test/installationmanager/TestInstallationManager.java @@ -15,6 +15,7 @@ import java.time.Instant; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -119,10 +120,10 @@ public static void initialize() throws IOException { // History sample data history = new HashMap<>(); - history.put("update", new HistoryResult("update", Instant.now(), "update", "update description")); - history.put("install", new HistoryResult("install", Instant.now(), "install", "install description")); - history.put("rollback", new HistoryResult("rollback", Instant.now(), "rollback", "rollback description")); - history.put("config_change", new HistoryResult("config_change", Instant.now(), "config_change", "config_change description")); + history.put("update", new HistoryResult("update", Instant.now(), "update", "update description", Collections.emptyList())); + history.put("install", new HistoryResult("install", Instant.now(), "install", "install description", Collections.emptyList())); + history.put("rollback", new HistoryResult("rollback", Instant.now(), "rollback", "rollback description", Collections.emptyList())); + history.put("config_change", new HistoryResult("config_change", Instant.now(), "config_change", "config_change description", Collections.emptyList())); // List Updates sample Data From 4a3fda695d1dc085333e35a105c1cd30c883c141 Mon Sep 17 00:00:00 2001 From: Bartosz Spyrko-Smietanko Date: Wed, 17 Jul 2024 10:43:28 +0100 Subject: [PATCH 2/3] [WFCORE-6893] Add standalone mode tests for installation manager integration --- .../core/instmgr/InstMgrResourceTestCase.java | 11 + ...nstallationManagerIntegrationTestCase.java | 23 + ...nstallationManagerIntegrationTestCase.java | 767 ++++++++++++++++++ ...tionmanager.spi.InstallationManagerFactory | 6 + .../test-repo-one/dummy_file_one.txt | 0 .../maven-repository/artifact-one | 0 .../other-directory-one/dummy_file_one.txt | 0 .../test-repo-two/dummy_file_two.txt | 0 .../maven-repository/artifact-two | 0 .../other-directory-two/dummy_file_two.txt | 0 .../TestInstallationManager.java | 2 +- 11 files changed, 808 insertions(+), 1 deletion(-) create mode 100644 testsuite/manualmode/src/test/java/org/jboss/as/test/manualmode/installationmanager/InstallationManagerIntegrationTestCase.java create mode 100644 testsuite/manualmode/src/test/resources/META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory create mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/dummy_file_one.txt create mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/maven-repository/artifact-one create mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/other-directory-one/dummy_file_one.txt create mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/dummy_file_two.txt create mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/maven-repository/artifact-two create mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/other-directory-two/dummy_file_two.txt diff --git a/installation-manager/src/test/java/org/wildfly/core/instmgr/InstMgrResourceTestCase.java b/installation-manager/src/test/java/org/wildfly/core/instmgr/InstMgrResourceTestCase.java index 7e65046d51d..544ec6da06c 100644 --- a/installation-manager/src/test/java/org/wildfly/core/instmgr/InstMgrResourceTestCase.java +++ b/installation-manager/src/test/java/org/wildfly/core/instmgr/InstMgrResourceTestCase.java @@ -371,7 +371,18 @@ public void testHistoryChannels() throws Exception { Assert.assertTrue(entry.hasDefined(InstMgrConstants.HISTORY_RESULT_TIMESTAMP)); Assert.assertTrue(entry.hasDefined(InstMgrConstants.HISTORY_RESULT_TYPE)); Assert.assertTrue(entry.hasDefined(InstMgrConstants.HISTORY_RESULT_DESCRIPTION)); + + // verify the channel version information is available (only "update" in test collection contains it) + if (entry.get(InstMgrConstants.HISTORY_RESULT_HASH).asString().equals("update")) { + Assert.assertTrue(entry.hasDefined(InstMgrConstants.HISTORY_RESULT_CHANNEL_VERSIONS)); + final List versions = entry.get(InstMgrConstants.HISTORY_RESULT_CHANNEL_VERSIONS).asList(); + Assert.assertEquals(1, versions.size()); + Assert.assertEquals("Update 1", versions.get(0).asString()); + } else { + Assert.assertFalse(entry.hasDefined(InstMgrConstants.HISTORY_RESULT_CHANNEL_VERSIONS)); + } } + } @Test diff --git a/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/installationmanager/InstallationManagerIntegrationTestCase.java b/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/installationmanager/InstallationManagerIntegrationTestCase.java index 9912d9d2325..a9f27e841bc 100644 --- a/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/installationmanager/InstallationManagerIntegrationTestCase.java +++ b/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/installationmanager/InstallationManagerIntegrationTestCase.java @@ -34,6 +34,7 @@ import org.jboss.as.test.integration.domain.management.util.DomainTestSupport; import org.jboss.as.test.integration.management.base.AbstractCliTestBase; import org.jboss.as.test.module.util.TestModule; +import org.jboss.dmr.ModelNode; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; @@ -786,6 +787,28 @@ public void uploadAndRemoveMultipleCustomPatches() throws IOException { removeCustomPatch(patchManifestGA_2, host, hostCustomPatchDir_2); } + @Test + public void testProductInfoIncludesInstallerInfo() throws Exception { + cli.sendLine(":product-info"); + + ModelNode res = cli.readAllAsOpResult().getResponseNode(); + + final List hostResults = res.get("result").asList(); + for (ModelNode host : hostResults) { + final List summaries = host.get("result").asList(); + for (ModelNode summary : summaries) { + summary = summary.get("summary"); + if (!summary.hasDefined("instance-identifier")) { + continue; + } + + Assert.assertTrue(summary.toString(), summary.hasDefined("last-update-date")); + Assert.assertTrue(summary.hasDefined("channel-versions")); + Assert.assertEquals(List.of(new ModelNode("Update 1")), summary.get("channel-versions").asList()); + } + } + } + public void createAndUploadCustomPatch(String customPatchManifest, String host, Path hostCustomPatchDir, String mavenDirToZip, String expectedArtifact) throws IOException { Path target = TARGET_DIR.resolve("installation-manager.zip"); File source = new File(getClass().getResource(mavenDirToZip).getFile()); diff --git a/testsuite/manualmode/src/test/java/org/jboss/as/test/manualmode/installationmanager/InstallationManagerIntegrationTestCase.java b/testsuite/manualmode/src/test/java/org/jboss/as/test/manualmode/installationmanager/InstallationManagerIntegrationTestCase.java new file mode 100644 index 00000000000..6b346b8802c --- /dev/null +++ b/testsuite/manualmode/src/test/java/org/jboss/as/test/manualmode/installationmanager/InstallationManagerIntegrationTestCase.java @@ -0,0 +1,767 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.jboss.as.test.manualmode.installationmanager; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +import jakarta.inject.Inject; + +import org.jboss.as.cli.Util; +import org.jboss.as.test.integration.management.base.AbstractCliTestBase; +import org.jboss.as.test.module.util.TestModule; +import org.jboss.as.test.shared.TestSuiteEnvironment; +import org.jboss.dmr.ModelNode; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.wildfly.core.instmgr.InstMgrConstants; +import org.wildfly.core.instmgr.cli.UpdateCommand; +import org.wildfly.core.testrunner.ManagementClient; +import org.wildfly.core.testrunner.ServerControl; +import org.wildfly.core.testrunner.ServerController; +import org.wildfly.core.testrunner.WildFlyRunner; +import org.wildfly.installationmanager.Channel; +import org.wildfly.installationmanager.Repository; +import org.wildfly.test.installationmanager.TestInstallationManager; +import org.wildfly.test.installationmanager.TestInstallationManagerFactory; + +/** + * Tests the high-level Installation Manager commands in standalone mode environment. It uses a mocked implementation of the + * installation manager, which provides dummy data for the test. + *

+ * The purpose of this test is to ensure that the high-level commands, which rely on low-level management operations, can + * retrieve the data from the mocked implementation. + *

+ * See InstMgrResourceTestCase for low-level management operation unit testing. + */ +@RunWith(WildFlyRunner.class) +@ServerControl(manual = true) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class InstallationManagerIntegrationTestCase extends AbstractCliTestBase { + + private static final String MODULE_NAME = "org.jboss.prospero"; + private static TestModule testModule; + + private static Path prepareServerDir; + + static final Path TARGET_DIR = Paths.get(System.getProperty("basedir", ".")).resolve("target"); + static Path customPatchBaseDir; + + @Inject + protected static ManagementClient client; + @Inject + protected static ServerController container; + + @BeforeClass + public static void setupDomain() throws Exception { + createTestModule(); + container.start(); + AbstractCliTestBase.initCLI(); + + prepareServerDir = Paths.get(TestSuiteEnvironment.getJBossHome()).resolve("standalone").resolve("tmp") + .resolve(InstMgrConstants.PREPARED_SERVER_SUBPATH); + + customPatchBaseDir = Paths.get(TestSuiteEnvironment.getJBossHome()).resolve(InstMgrConstants.CUSTOM_PATCH_SUBPATH); + } + + @AfterClass + public static void tearDownDomain() throws Exception { + try { + AbstractCliTestBase.closeCLI(); + } finally { + container.stop(); + testModule.remove(); + } + } + + private static void createTestModule() throws IOException { + testModule = new TestModule(MODULE_NAME, "org.wildfly.installation-manager.api"); + testModule.addResource("test-mock-installation-manager.jar").addClass(TestInstallationManager.class).addClass(TestInstallationManagerFactory.class) + .addAsManifestResource("META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory", + "services/org.wildfly.installationmanager.spi.InstallationManagerFactory"); + testModule.create(true); + } + + @After + public void clean() throws IOException { + // Clean any previous state + assertTrue(cli.sendLine("installer clean", false)); + Assert.assertTrue(!Files.exists(prepareServerDir)); + + for(File testZip : TARGET_DIR.toFile().listFiles((dir, name) -> name.startsWith("installation-manager") && name.endsWith(".zip"))) { + Files.deleteIfExists(testZip.toPath()); + } + } + + @Test + public void rejectsHost() { + final List commands = List.of("update", "clean", "revert", "history", "channel-list", + "channel-add --channel-name test --manifest test --repositories test", "channel-edit --channel-name test --manifest test --repositories test", + "channel-remove --channel-name test", "upload-custom-patch --custom-patch-file=dummy --manifest=manifest"); + + for (String command : commands) { + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer " + command + " --host=test"); + }); + + String expectedMessage = "The --host option is not available in the current context."; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage, actualMessage.contains(expectedMessage)); + } + } + + public static String buildChannelOutput(Channel channel) { + final String returnChar = Util.isWindows() ? "\r\n" : "\n"; + + StringBuilder sb = new StringBuilder("-------").append(returnChar).append("# " + channel.getName()).append(returnChar); + + if (channel.getManifestUrl().isPresent()) { + sb.append(" manifest: " + channel.getManifestUrl().get()).append(returnChar); + } else if (channel.getManifestCoordinate().isPresent()) { + sb.append(" manifest: " + channel.getManifestCoordinate().get()).append(returnChar); + } + + sb.append(" repositories:").append(returnChar); + + for (Repository repository : channel.getRepositories()) { + sb.append(" id: " + repository.getId()).append(returnChar).append(" url: " + repository.getUrl()).append(returnChar); + } + + return sb.toString(); + } + + @Test + public void _a_listChannel() throws Exception { + cli.sendLine("installer channel-list"); + String output = cli.readOutput(); + + TestInstallationManager.initialize(); + + StringBuilder expected = new StringBuilder(); + for (Channel channel : TestInstallationManager.lstChannels) { + expected.append(buildChannelOutput(channel)); + } + expected.append("-------"); + + Assert.assertEquals(expected.toString(), output); + } + + @Test + public void _b_addChannel() throws IOException { + String channelName = "test-primary"; + String manifestGavOrUrl = "group:artifact:primary-1.0.0.Final"; + String repoStr = "https://primary.com"; + + cli.sendLine( + "installer channel-add --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr); + String output = cli.readOutput(); + Assert.assertEquals("Channel '" + channelName + "' created.", output); + + cli.sendLine("installer channel-list"); + output = cli.readOutput(); + + StringBuilder expected = new StringBuilder(); + + TestInstallationManager.initialize(); + for (Channel channel : TestInstallationManager.lstChannels) { + expected.append(buildChannelOutput(channel)); + } + + Repository repository = new Repository("id0", repoStr); + Channel newChannel = new Channel(channelName, List.of(repository), manifestGavOrUrl); + expected.append(buildChannelOutput(newChannel)); + expected.append("-------"); + + Assert.assertEquals(expected.toString(), output); + } + + @Test + public void _c_removeChannel() { + String channelName = "channel-test-1"; + cli.sendLine("installer channel-remove --channel-name=" + channelName); + String output = cli.readOutput(); + Assert.assertEquals("Channel '" + channelName + "' has been successfully removed.", output); + } + + @Test + public void _d_editChannel() { + String channelName = "channel-test-2"; + String manifestGavOrUrl = "group:artifact:edited-1.0.0.Final"; + String repoStr = "https://edited.com"; + + cli.sendLine( + "installer channel-edit --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr); + String output = cli.readOutput(); + Assert.assertEquals("Channel '" + channelName + "' has been modified.", output); + + cli.sendLine("installer channel-list"); + output = cli.readOutput(); + + Repository repository = new Repository("id0", repoStr); + Channel newChannel = new Channel(channelName, List.of(repository), manifestGavOrUrl); + String expected = buildChannelOutput(newChannel); + Assert.assertTrue(output, output.contains(expected)); + } + + @Test + public void _e_editChannelNotExist() { + String channelName = "unknown"; + String manifestGavOrUrl = "group:artifact:edited-1.0.0.Final"; + String repoStr = "https://edited.com"; + + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer channel-edit --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr); + }); + + String expectedMessage = "Channel '" + channelName + "' is not present."; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage, actualMessage.contains(expectedMessage)); + } + + @Test + public void _f_testHistory() throws IOException { + cli.sendLine("installer history"); + String output = cli.readOutput(); + + String[] lines = output.split("\n"); + assertEquals(4, lines.length); + + TestInstallationManager.initialize(); + Set expectedValues = TestInstallationManager.history.keySet(); + Set actual = new HashSet<>(Arrays.asList(lines)); + for (String actualStr : actual) { + for (Iterator it = expectedValues.iterator(); it.hasNext();) { + if (actualStr.contains(it.next())) { + it.remove(); + } + } + } + Assert.assertTrue(Arrays.asList(lines).toString(), expectedValues.isEmpty()); + } + + @Test + public void testRevisionDetails() throws Exception { + cli.sendLine("installer history --revision=dummy"); + String output = cli.readOutput(); + + assertTrue(output, output.contains("org.test.groupid1:org.test.artifact1.installed")); + assertTrue(output, output.contains("org.test.groupid1:org.test.artifact1.removed")); + assertTrue(output, output.contains("org.test.groupid1:org.test.artifact1.updated")); + assertTrue(output, output.contains("[Added channel] channel-test-0")); + assertTrue(output, output.contains("[Removed channel] channel-test-0")); + assertTrue(output, output.contains("[Updated channel] channel-test-0")); + } + + @Test + public void testCreateSnapShot() throws IOException { + Path exportPath = TARGET_DIR.normalize().toAbsolutePath().resolve("generated.zip"); + try { + cli.sendLine("attachment save --operation=/core-service=installer:clone-export() --file=" + exportPath); + String output = cli.readOutput(); + String expected = "File saved to " + exportPath; + assertEquals(expected, output); + + boolean found = false; + try (ZipInputStream zis = new ZipInputStream(new FileInputStream(exportPath.toFile()))) { + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + String entryName = entry.getName(); + if (entryName.startsWith("installation-manager-test-") && entryName.endsWith(".tmp")) { + found = true; + break; + } + } + } + Assert.assertTrue("Cannot found the expected entry added by the TestInstallationManager.java in the clone export Zip result", found); + } finally { + File expectedExportFile = exportPath.toFile(); + if (expectedExportFile.exists()) { + expectedExportFile.delete(); + } + } + } + + @Test + public void updateWithDryRun() { + cli.sendLine("installer update --dry-run"); + String output = cli.readOutput(); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + } + + @Test + public void updateWithConfirm() throws IOException { + cli.sendLine("installer update --repositories=id0::http://localhost --confirm"); + String output = cli.readOutput(); + + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + + Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); + Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void updateWithConfirmRepositories() throws IOException { + cli.sendLine("installer update --confirm --repositories=id0::http://localhost"); + String output = cli.readOutput(); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + + Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); + Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void updateWithConfirmLocalCache() throws IOException { + cli.sendLine("installer update --confirm --local-cache=" + TARGET_DIR); + String output = cli.readOutput(); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + + Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); + Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void updateLocalCacheWithUseDefaultLocalCache() { + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer update --local-cache=" + TARGET_DIR + " --use-default-local-cache"); + }); + + String expectedMessage = "WFLYIM0021:"; + String actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + + exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer update --local-cache=" + TARGET_DIR + " --use-default-local-cache"); + }); + + expectedMessage = "WFLYIM0021:"; + actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + } + + @Test + public void cannotUseConfirmAndDryRunAtTheSameTime() { + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer update --confirm --dry-run"); + }); + + String expectedMessage = UpdateCommand.CONFIRM_OPTION + " and " + UpdateCommand.DRY_RUN_OPTION + " cannot be used at the same time."; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage, actualMessage.contains(expectedMessage)); + } + + @Test + public void updateWithConfirmUsingMavenZipFile() throws IOException { + Path target = TARGET_DIR.resolve("installation-manager.zip"); + File source = new File(getClass().getResource("test-repo-one").getFile()); + zipDir(source.toPath().toAbsolutePath(), target); + + cli.sendLine("installer update --confirm --maven-repo-files=" + target); + String output = cli.readOutput(); + verifyUpdatePrepareDirWasCreated(output); + + } + @Test + public void updateWithConfirmUsingMultipleMavenZipFiles() throws IOException { + Path targetOne = TARGET_DIR.resolve("installation-manager-one.zip"); + File source = new File(getClass().getResource("test-repo-one").getFile()); + zipDir(source.toPath().toAbsolutePath(), targetOne); + + Path targetTwo = TARGET_DIR.resolve("installation-manager-two.zip"); + source = new File(getClass().getResource("test-repo-two").getFile()); + zipDir(source.toPath().toAbsolutePath(), targetTwo); + + cli.sendLine("installer update --confirm --maven-repo-files=" + targetOne + "," + targetTwo); + String output = cli.readOutput(); + verifyUpdatePrepareDirWasCreated(output); + } + + public void verifyUpdatePrepareDirWasCreated(String output) throws IOException { + final Path expectedPreparedServerDir = prepareServerDir; + + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + Assert.assertTrue(output, + output.contains("The candidate server has been generated. To apply it, restart the server with 'shutdown --perform-installation' command.")); + + Assert.assertTrue(Files.exists(expectedPreparedServerDir) && Files.isDirectory(expectedPreparedServerDir)); + Assert.assertTrue(expectedPreparedServerDir + " does not contain the expected file marker", + directoryOnlyContains(expectedPreparedServerDir, p -> expectedPreparedServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + + @Test + public void updateWithDryRunMavenZipFile() throws IOException { + Path target = TARGET_DIR.resolve("installation-manager.zip"); + File source = new File(getClass().getResource("test-repo-one").getFile()); + zipDir(source.toPath().toAbsolutePath(), target); + + cli.sendLine("installer update --dry-run --maven-repo-files=" + target); + String output = cli.readOutput(); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + Assert.assertFalse(output, + output.contains("The candidate server has been generated. To apply it, restart the server with 'shutdown --perform-installation' command.")); + + Assert.assertFalse(Files.exists(prepareServerDir)); + } + + @Test + public void updateWithDryRunMultipleMavenZipFile() throws IOException { + Path targetOne = TARGET_DIR.resolve("installation-manager-one.zip"); + File source = new File(getClass().getResource("test-repo-one").getFile()); + zipDir(source.toPath().toAbsolutePath(), targetOne); + + Path targetTwo = TARGET_DIR.resolve("installation-manager-two.zip"); + source = new File(getClass().getResource("test-repo-one").getFile()); + zipDir(source.toPath().toAbsolutePath(), targetTwo); + + cli.sendLine("installer update --dry-run --maven-repo-files=" + targetOne +","+ targetTwo); + String output = cli.readOutput(); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + Assert.assertFalse(output, + output.contains("The candidate server has been generated. To apply it, restart the server with 'shutdown --perform-installation' command.")); + + Assert.assertFalse(Files.exists(prepareServerDir)); + } + + @Test + public void updateUsingBlockingTimeout() throws IOException { + assertTrue(cli.sendLine("installer update --confirm --headers={blocking-timeout=100}", false)); + + Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); + Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void updateCannotBeUsedWithMavenRepoFileAndRepositories() throws IOException { + Path target = TARGET_DIR.resolve("installation-manager.zip"); + File source = new File(getClass().getResource("test-repo-one").getFile()); + zipDir(source.toPath().toAbsolutePath(), target); + + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer update --repositories=id0::http://localhost --maven-repo-files=" + target); + }); + + String expectedMessage = "WFLYIM0012:"; + String actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + } + + @Test + public void revertWithMavenZipFile() throws IOException { + Path target = TARGET_DIR.resolve("installation-manager.zip"); + File source = new File(getClass().getResource("test-repo-one").getFile()); + zipDir(source.toPath().toAbsolutePath(), target); + + Assert.assertTrue(cli.sendLine("installer revert --revision=dummy --maven-repo-files=" + target, false)); + + Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); + Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertWithMultipleMavenZipFiles() throws IOException { + Path targetOne = TARGET_DIR.resolve("installation-manager-one.zip"); + File source = new File(getClass().getResource("test-repo-one").getFile()); + zipDir(source.toPath().toAbsolutePath(), targetOne); + + Path targetTwo = TARGET_DIR.resolve("installation-manager-two.zip"); + source = new File(getClass().getResource("test-repo-two").getFile()); + zipDir(source.toPath().toAbsolutePath(), targetTwo); + + Assert.assertTrue(cli.sendLine("installer revert --revision=dummy --maven-repo-files=" + targetOne + "," + targetTwo, false)); + + Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); + Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertWithNoResolveLocalMavenCache() throws IOException { + assertTrue(cli.sendLine("installer revert --revision=dummy --no-resolve-local-cache", false)); + + Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); + Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", + Files.list(prepareServerDir).allMatch(p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertWithUseDefaultLocalCache() throws IOException { + assertTrue(cli.sendLine("installer revert --revision=dummy --use-default-local-cache", false)); + + Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); + Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertWithLocalCacheMavenCache() throws IOException { + assertTrue(cli.sendLine("installer revert --revision=dummy --local-cache=" + TARGET_DIR, false)); + + Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); + Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertLocalCacheWithUseDefaultLocalCache() { + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer revert --revision=dummy --local-cache=" + TARGET_DIR + " --use-default-local-cache"); + }); + + String expectedMessage = "WFLYIM0021:"; + String actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + + exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer revert --revision=dummy --local-cache=" + TARGET_DIR + " --use-default-local-cache=true"); + }); + + expectedMessage = "WFLYIM0021:"; + actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + } + + @Test + public void revertWithOffline() throws IOException { + assertTrue(cli.sendLine("installer revert --revision=dummy --offline", false)); + + Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); + Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertWithHeaders() throws IOException { + assertTrue(cli.sendLine("installer revert --revision=dummy --headers={blocking-timeout=100}", false)); + + Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); + Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertWithRepositories() throws IOException { + assertTrue(cli.sendLine("installer revert --revision=dummy --repositories=id0::http://localhost", false)); + + Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); + Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void simpleRevert() throws IOException { + assertTrue(cli.sendLine("installer revert --revision=dummy", false)); + + Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); + Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertCannotBeUsedWithoutRevision() { + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer revert"); + }); + + String expectedMessage = "WFLYCTL0155:"; + String actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + } + + @Test + public void revertCannotBeUsedWithMavenRepoFileAndRepositories() throws IOException { + Path target = TARGET_DIR.resolve("installation-manager.zip"); + File source = new File(getClass().getResource("test-repo-one").getFile()); + zipDir(source.toPath().toAbsolutePath(), target); + + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer revert --revision=dummy --repositories=id0::http://localhost --maven-repo-files=" + target); + }); + + String expectedMessage = "WFLYIM0012:"; + String actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + } + + @Test + public void uploadAndRemoveCustomPatch() throws IOException { + String patchManifestGA = "group:artifact"; + Path customPatchDir = customPatchBaseDir.resolve(patchManifestGA.replace(":", "_")); + + createAndUploadCustomPatch(patchManifestGA, customPatchDir, "test-repo-one", "artifact-one"); + removeCustomPatch(patchManifestGA, customPatchDir); + } + + @Test + public void removeNonExistingCustomPatch() { + String patchManifestGA = "group-unknown:artifact-unknown"; + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer remove-custom-patch --manifest=" + patchManifestGA); + }); + String expectedMessage = "WFLYIM0020:"; + String actualMessage = exception.getMessage(); + Assert.assertTrue(actualMessage, actualMessage.contains(expectedMessage)); + + } + + @Test + public void uploadAndRemoveMultipleCustomPatches() throws IOException { + String patchManifestGA_1 = "group1:artifact1"; + Path customPatchDir_1 = customPatchBaseDir.resolve(patchManifestGA_1.replace(":", "_")); + createAndUploadCustomPatch(patchManifestGA_1, customPatchDir_1, "test-repo-one", "artifact-one"); + + String patchManifestGA_2 = "group2:artifact2"; + Path customPatchDir_2 = customPatchBaseDir.resolve(patchManifestGA_2.replace(":", "_")); + createAndUploadCustomPatch(patchManifestGA_2, customPatchDir_2, "test-repo-two", "artifact-two"); + + removeCustomPatch(patchManifestGA_1, customPatchDir_1); + + // check we still have the second patch + final Path customPatchMavenRepo = customPatchDir_2.resolve(InstMgrConstants.MAVEN_REPO_DIR_NAME_IN_ZIP_FILES); + Assert.assertTrue(Files.exists(customPatchMavenRepo) && Files.isDirectory(customPatchMavenRepo)); + Assert.assertTrue(customPatchDir_2 + " does not contain the expected maven repository", + directoryOnlyContains(customPatchMavenRepo, p -> customPatchMavenRepo.relativize(p).toString().equals("artifact-two"))); + + // remove the patch 2 + removeCustomPatch(patchManifestGA_2, customPatchDir_2); + } + + @Test + public void testProductInfoIncludesInstallerInfo() throws Exception { + cli.sendLine(":product-info"); + + ModelNode response = cli.readAllAsOpResult().getResponseNode(); + + final List results = response.get("result").asList(); + for (ModelNode res : results) { + final ModelNode summary = res.get("result").get("summary"); + if (!summary.hasDefined("instance-identifier")) { + continue; + } + + Assert.assertTrue(summary.toString(), summary.hasDefined("last-update-date")); + Assert.assertTrue(summary.hasDefined("channel-versions")); + Assert.assertEquals(List.of(new ModelNode("Update 1")), summary.get("channel-versions").asList()); + } + } + + public void createAndUploadCustomPatch(String customPatchManifest, Path customPatchDir, String mavenDirToZip, String expectedArtifact) throws IOException { + Path target = TARGET_DIR.resolve("installation-manager.zip"); + File source = new File(getClass().getResource(mavenDirToZip).getFile()); + zipDir(source.toPath().toAbsolutePath(), target); + + // verify the patch doesn't exist yet + final Path customPatchMavenRepo = customPatchDir.resolve(InstMgrConstants.MAVEN_REPO_DIR_NAME_IN_ZIP_FILES); + Assert.assertFalse(Files.exists(customPatchMavenRepo)); + + Assert.assertTrue( + cli.sendLine("installer upload-custom-patch --custom-patch-file=" + target + " --manifest=" + customPatchManifest, false)); + // verify clean operation without arguments don't remove the patch + Assert.assertTrue(cli.sendLine("installer clean", false)); + Assert.assertTrue(Files.exists(customPatchMavenRepo) && Files.isDirectory(customPatchMavenRepo)); + Assert.assertTrue(customPatchDir + " does not contain the expected artifact included in the custom patch Zip file", + directoryOnlyContains(customPatchMavenRepo, p -> customPatchMavenRepo.relativize(p).toString().equals(expectedArtifact))); + } + + public void removeCustomPatch(String customPatchManifest, Path customPatchDir) { + // remove the custom patch + final Path customPatchMavenRepo = customPatchDir.resolve(InstMgrConstants.MAVEN_REPO_DIR_NAME_IN_ZIP_FILES); + Assert.assertTrue(cli.sendLine("installer remove-custom-patch --manifest=" + customPatchManifest, false)); + Assert.assertFalse(Files.exists(customPatchMavenRepo)); + } + + @Test + public void cannotShutDownIfNoServerPrepared() { + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("shutdown --perform-installation"); + }); + String expectedMessage = "WFLYSRV0295:"; + String actualMessage = exception.getMessage(); + Assert.assertTrue(actualMessage, actualMessage.contains(expectedMessage)); + } + + public static void zipDir(Path sourcePath, Path target) throws IOException { + try (FileOutputStream fos = new FileOutputStream(target.toFile()); ZipOutputStream zos = new ZipOutputStream(fos)) { + Files.walkFileTree(sourcePath, new SimpleFileVisitor<>() { + @Override + public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { + if (!sourcePath.equals(dir)) { + zos.putNextEntry(new ZipEntry(sourcePath.relativize(dir) + "/")); + zos.closeEntry(); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { + zos.putNextEntry(new ZipEntry(sourcePath.relativize(file).toString())); + Files.copy(file, zos); + zos.closeEntry(); + return FileVisitResult.CONTINUE; + } + }); + } + } + + public String getCauseLogFailure(String description, String expectedLogCode) { + return "Unexpected Error Code. Got " + description + " It was expected: " + expectedLogCode; + } + + public boolean directoryOnlyContains(Path directory, Predicate match) throws IOException { + try (Stream stream = Files.list(directory)) { + return stream.allMatch(match); + } + } +} diff --git a/testsuite/manualmode/src/test/resources/META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory b/testsuite/manualmode/src/test/resources/META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory new file mode 100644 index 00000000000..195816af124 --- /dev/null +++ b/testsuite/manualmode/src/test/resources/META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory @@ -0,0 +1,6 @@ +# +# Copyright The WildFly Authors +# SPDX-License-Identifier: Apache-2.0 +# + +org.wildfly.test.installationmanager.TestInstallationManagerFactory diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/dummy_file_one.txt b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/dummy_file_one.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/maven-repository/artifact-one b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/maven-repository/artifact-one new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/other-directory-one/dummy_file_one.txt b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/other-directory-one/dummy_file_one.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/dummy_file_two.txt b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/dummy_file_two.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/maven-repository/artifact-two b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/maven-repository/artifact-two new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/other-directory-two/dummy_file_two.txt b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/other-directory-two/dummy_file_two.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testsuite/shared/src/main/java/org/wildfly/test/installationmanager/TestInstallationManager.java b/testsuite/shared/src/main/java/org/wildfly/test/installationmanager/TestInstallationManager.java index e1363029cfe..5c6c1350f37 100644 --- a/testsuite/shared/src/main/java/org/wildfly/test/installationmanager/TestInstallationManager.java +++ b/testsuite/shared/src/main/java/org/wildfly/test/installationmanager/TestInstallationManager.java @@ -120,7 +120,7 @@ public static void initialize() throws IOException { // History sample data history = new HashMap<>(); - history.put("update", new HistoryResult("update", Instant.now(), "update", "update description", Collections.emptyList())); + history.put("update", new HistoryResult("update", Instant.now(), "update", "update description", List.of(new ManifestVersion("org.channel", "Update 1", "1.0.0.Final", ManifestVersion.Type.MAVEN)))); history.put("install", new HistoryResult("install", Instant.now(), "install", "install description", Collections.emptyList())); history.put("rollback", new HistoryResult("rollback", Instant.now(), "rollback", "rollback description", Collections.emptyList())); history.put("config_change", new HistoryResult("config_change", Instant.now(), "config_change", "config_change description", Collections.emptyList())); From 2f17da0b813fc3ae237de488b594249cbb1e6608 Mon Sep 17 00:00:00 2001 From: Bartosz Spyrko-Smietanko Date: Fri, 19 Jul 2024 14:32:22 +0100 Subject: [PATCH 3/3] Extracting common code in InstallationManagerTestCase --- .../core/instmgr/InstMgrHistoryHandler.java | 7 +- ...nstallationManagerIntegrationTestCase.java | 820 +-------------- .../suites/SimpleRbacProviderTestSuite.java | 5 +- ...nstallationManagerIntegrationTestCase.java | 703 +------------ ...tionmanager.spi.InstallationManagerFactory | 6 - .../test-repo-one/dummy_file_one.txt | 0 .../maven-repository/artifact-one | 0 .../other-directory-one/dummy_file_one.txt | 0 .../test-repo-two/dummy_file_two.txt | 0 .../maven-repository/artifact-two | 0 .../other-directory-two/dummy_file_two.txt | 0 .../BaseInstallationManagerTestCase.java | 975 ++++++++++++++++++ ...tionmanager.spi.InstallationManagerFactory | 0 .../test-repo-one/dummy_file_one.txt | 0 .../maven-repository/artifact-one | 0 .../other-directory-one/dummy_file_one.txt | 0 .../test-repo-two/dummy_file_two.txt | 0 .../maven-repository/artifact-two | 0 .../other-directory-two/dummy_file_two.txt | 0 19 files changed, 1014 insertions(+), 1502 deletions(-) delete mode 100644 testsuite/manualmode/src/test/resources/META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory delete mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/dummy_file_one.txt delete mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/maven-repository/artifact-one delete mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/other-directory-one/dummy_file_one.txt delete mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/dummy_file_two.txt delete mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/maven-repository/artifact-two delete mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/other-directory-two/dummy_file_two.txt create mode 100644 testsuite/shared/src/main/java/org/wildfly/test/installationmanager/BaseInstallationManagerTestCase.java rename testsuite/{domain/src/test/resources/META-INF => shared/src/main/resources/org/wildfly/test/installationmanager}/services/org.wildfly.installationmanager.spi.InstallationManagerFactory (100%) rename testsuite/{domain/src/test/resources/org/jboss/as/test/integration/domain => shared/src/main/resources/org/wildfly/test}/installationmanager/test-repo-one/dummy_file_one.txt (100%) rename testsuite/{domain/src/test/resources/org/jboss/as/test/integration/domain => shared/src/main/resources/org/wildfly/test}/installationmanager/test-repo-one/maven-repository/artifact-one (100%) rename testsuite/{domain/src/test/resources/org/jboss/as/test/integration/domain => shared/src/main/resources/org/wildfly/test}/installationmanager/test-repo-one/other-directory-one/dummy_file_one.txt (100%) rename testsuite/{domain/src/test/resources/org/jboss/as/test/integration/domain => shared/src/main/resources/org/wildfly/test}/installationmanager/test-repo-two/dummy_file_two.txt (100%) rename testsuite/{domain/src/test/resources/org/jboss/as/test/integration/domain => shared/src/main/resources/org/wildfly/test}/installationmanager/test-repo-two/maven-repository/artifact-two (100%) rename testsuite/{domain/src/test/resources/org/jboss/as/test/integration/domain => shared/src/main/resources/org/wildfly/test}/installationmanager/test-repo-two/other-directory-two/dummy_file_two.txt (100%) diff --git a/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrHistoryHandler.java b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrHistoryHandler.java index ac3f8788f9f..c3203729830 100644 --- a/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrHistoryHandler.java +++ b/installation-manager/src/main/java/org/wildfly/core/instmgr/InstMgrHistoryHandler.java @@ -6,6 +6,8 @@ package org.wildfly.core.instmgr; import java.nio.file.Path; +import java.text.DateFormat; +import java.util.Date; import java.util.List; import java.util.Locale; @@ -53,7 +55,10 @@ public void execute(OperationContext context, ModelNode operation) throws Operat for (HistoryResult hr : history) { ModelNode entry = new ModelNode(); entry.get(InstMgrConstants.HISTORY_RESULT_HASH).set(hr.getName()); - entry.get(InstMgrConstants.HISTORY_RESULT_TIMESTAMP).set(hr.timestamp().toString()); + if (hr.timestamp() != null) { + final java.util.Date timestamp = Date.from(hr.timestamp()); + entry.get(InstMgrConstants.HISTORY_RESULT_TIMESTAMP).set(DateFormat.getInstance().format(timestamp)); + } entry.get(InstMgrConstants.HISTORY_RESULT_TYPE).set(hr.getType().toLowerCase(Locale.ENGLISH)); if (hr.getVersions() != null && !hr.getVersions().isEmpty()) { final ModelNode versions = entry.get(InstMgrConstants.HISTORY_RESULT_CHANNEL_VERSIONS); diff --git a/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/installationmanager/InstallationManagerIntegrationTestCase.java b/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/installationmanager/InstallationManagerIntegrationTestCase.java index a9f27e841bc..5d2462b9ef8 100644 --- a/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/installationmanager/InstallationManagerIntegrationTestCase.java +++ b/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/installationmanager/InstallationManagerIntegrationTestCase.java @@ -5,49 +5,20 @@ package org.jboss.as.test.integration.domain.installationmanager; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Stream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; - -import org.jboss.as.cli.Util; +import java.util.LinkedHashMap; import org.jboss.as.test.integration.domain.management.util.DomainTestSupport; import org.jboss.as.test.integration.management.base.AbstractCliTestBase; -import org.jboss.as.test.module.util.TestModule; -import org.jboss.dmr.ModelNode; -import org.junit.After; import org.junit.AfterClass; -import org.junit.Assert; import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; import org.wildfly.core.instmgr.InstMgrConstants; -import org.wildfly.core.instmgr.cli.UpdateCommand; -import org.wildfly.installationmanager.Channel; -import org.wildfly.installationmanager.Repository; -import org.wildfly.test.installationmanager.TestInstallationManager; -import org.wildfly.test.installationmanager.TestInstallationManagerFactory; +import org.wildfly.test.installationmanager.BaseInstallationManagerTestCase; /** * Tests the high-level Installation Manager commands in domain mode environment. It uses a mocked implementation of the @@ -59,16 +30,11 @@ * See InstMgrResourceTestCase for low-level management operation unit testing. */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class InstallationManagerIntegrationTestCase extends AbstractCliTestBase { - - private static final String MODULE_NAME = "org.jboss.prospero"; +public class InstallationManagerIntegrationTestCase extends BaseInstallationManagerTestCase { private static DomainTestSupport testSupport; - private static TestModule testModule; private static Path primaryPrepareServerDir; private static Path secondaryPrepareServerDir; - - static final Path TARGET_DIR = Paths.get(System.getProperty("basedir", ".")).resolve("target"); static Path primaryCustomPatchBaseDir; static Path secondaryCustomPatchBaseDir; @@ -102,779 +68,23 @@ public static void tearDownDomain() throws Exception { } } - private static void createTestModule() throws IOException { - testModule = new TestModule(MODULE_NAME, "org.wildfly.installation-manager.api"); - testModule.addResource("test-mock-installation-manager.jar").addClass(TestInstallationManager.class).addClass(TestInstallationManagerFactory.class) - .addAsManifestResource("META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory", - "services/org.wildfly.installationmanager.spi.InstallationManagerFactory"); - testModule.create(true); - } - - @After - public void clean() throws IOException { - String host = "secondary"; - // Clean any previous state - assertTrue(cli.sendLine("installer clean --host=" + host, false)); - Assert.assertTrue(!Files.exists(secondaryPrepareServerDir)); - - host = "primary"; - // Clean any previous state - assertTrue(cli.sendLine("installer clean --host=" + host, false)); - Assert.assertTrue(!Files.exists(primaryPrepareServerDir)); - - for(File testZip : TARGET_DIR.toFile().listFiles((dir, name) -> name.startsWith("installation-manager") && name.endsWith(".zip"))) { - Files.deleteIfExists(testZip.toPath()); - } - } - @Test public void requireHost() { - final List commands = List.of("update", "clean", "revert", "history", "channel-list", - "channel-add --channel-name test --manifest test --repositories test", "channel-edit --channel-name test --manifest test --repositories test", - "channel-remove --channel-name test", "upload-custom-patch --custom-patch-file=dummy --manifest=manifest"); - - for (String command : commands) { - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer " + command); - }); - - String expectedMessage = "The --host option must be used in domain mode."; - String actualMessage = exception.getMessage(); - - assertTrue(actualMessage, actualMessage.contains(expectedMessage)); - } - } - - public static String buildChannelOutput(Channel channel) { - final String returnChar = Util.isWindows() ? "\r\n" : "\n"; - - StringBuilder sb = new StringBuilder("-------").append(returnChar).append("# " + channel.getName()).append(returnChar); - - if (channel.getManifestUrl().isPresent()) { - sb.append(" manifest: " + channel.getManifestUrl().get()).append(returnChar); - } else if (channel.getManifestCoordinate().isPresent()) { - sb.append(" manifest: " + channel.getManifestCoordinate().get()).append(returnChar); - } - - sb.append(" repositories:").append(returnChar); - - for (Repository repository : channel.getRepositories()) { - sb.append(" id: " + repository.getId()).append(returnChar).append(" url: " + repository.getUrl()).append(returnChar); - } - - return sb.toString(); - } - - @Test - public void _a_listChannel() throws IOException { - cli.sendLine("installer channel-list --host=primary"); - String output = cli.readOutput(); - - TestInstallationManager.initialize(); - - StringBuilder expected = new StringBuilder(); - for (Channel channel : TestInstallationManager.lstChannels) { - expected.append(buildChannelOutput(channel)); - } - expected.append("-------"); - - Assert.assertEquals(expected.toString(), output); - - cli.sendLine("installer channel-list --host=secondary"); - output = cli.readOutput(); - - Assert.assertEquals(expected.toString(), output); - } - - @Test - public void _b_addChannel() throws IOException { - String channelName = "test-primary"; - String manifestGavOrUrl = "group:artifact:primary-1.0.0.Final"; - String repoStr = "https://primary.com"; - String host = "primary"; - - cli.sendLine( - "installer channel-add --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr + " --host=" + host); - String output = cli.readOutput(); - Assert.assertEquals("Channel '" + channelName + "' created.", output); - - cli.sendLine("installer channel-list --host=" + host); - output = cli.readOutput(); - - StringBuilder expected = new StringBuilder(); - - TestInstallationManager.initialize(); - for (Channel channel : TestInstallationManager.lstChannels) { - expected.append(buildChannelOutput(channel)); - } - - Repository repository = new Repository("id0", repoStr); - Channel newChannel = new Channel(channelName, List.of(repository), manifestGavOrUrl); - expected.append(buildChannelOutput(newChannel)); - expected.append("-------"); - - Assert.assertEquals(expected.toString(), output); - - // verify the secondary Host - expected = new StringBuilder(); - channelName = "test-secondary"; - manifestGavOrUrl = "/test"; - repoStr = "https://secondary.com"; - host = "secondary"; - - cli.sendLine( - "installer channel-add --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr + " --host=" + host); - output = cli.readOutput(); - Assert.assertEquals("Channel '" + channelName + "' created.", output); - - cli.sendLine("installer channel-list --host=" + host); - output = cli.readOutput(); - - TestInstallationManager.initialize(); - for (Channel channel : TestInstallationManager.lstChannels) { - expected.append(buildChannelOutput(channel)); - } - - repository = new Repository("id0", repoStr); - newChannel = new Channel(channelName, List.of(repository), Paths.get(manifestGavOrUrl).toUri().toURL()); - expected.append(buildChannelOutput(newChannel)); - expected.append("-------"); - - Assert.assertEquals(expected.toString(), output); - } - - @Test - public void _c_removeChannel() { - String channelName = "channel-test-1"; - String host = "primary"; - cli.sendLine("installer channel-remove --channel-name=" + channelName + " --host=" + host); - String output = cli.readOutput(); - Assert.assertEquals("Channel '" + channelName + "' has been successfully removed.", output); - - channelName = "channel-test-2"; - host = "secondary"; - cli.sendLine("installer channel-remove --channel-name=" + channelName + " --host=" + host); - output = cli.readOutput(); - Assert.assertEquals("Channel '" + channelName + "' has been successfully removed.", output); - } - - @Test - public void _d_editChannel() { - String channelName = "channel-test-2"; - String manifestGavOrUrl = "group:artifact:edited-1.0.0.Final"; - String repoStr = "https://edited.com"; - String host = "primary"; - - cli.sendLine( - "installer channel-edit --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr + " --host=" + host); - String output = cli.readOutput(); - Assert.assertEquals("Channel '" + channelName + "' has been modified.", output); - - cli.sendLine("installer channel-list --host=" + host); - output = cli.readOutput(); - - Repository repository = new Repository("id0", repoStr); - Channel newChannel = new Channel(channelName, List.of(repository), manifestGavOrUrl); - String expected = buildChannelOutput(newChannel); - Assert.assertTrue(output, output.contains(expected)); - - channelName = "channel-test-1"; - manifestGavOrUrl = "group:artifact:edited-1.0.0.Final"; - repoStr = "https://edited.com"; - host = "secondary"; - - cli.sendLine( - "installer channel-edit --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr + " --host=" + host); - output = cli.readOutput(); - Assert.assertEquals("Channel '" + channelName + "' has been modified.", output); - - cli.sendLine("installer channel-list --host=" + host); - output = cli.readOutput(); - - repository = new Repository("id0", repoStr); - newChannel = new Channel(channelName, List.of(repository), manifestGavOrUrl); - expected = buildChannelOutput(newChannel); - Assert.assertTrue(output, output.contains(expected)); - } - - @Test - public void _e_editChannelNotExist() { - String channelName = "unknown"; - String manifestGavOrUrl = "group:artifact:edited-1.0.0.Final"; - String repoStr = "https://edited.com"; - String host = "primary"; - - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer channel-edit --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr + " --host=" - + host); - }); - - String expectedMessage = "Channel '" + channelName + "' is not present."; - String actualMessage = exception.getMessage(); - - assertTrue(actualMessage, actualMessage.contains(expectedMessage)); - } - - @Test - public void _f_testHistory() throws IOException { - String host = "secondary"; - cli.sendLine("installer history --host=" + host); - String output = cli.readOutput(); - - String[] lines = output.split("\n"); - assertEquals(4, lines.length); - - TestInstallationManager.initialize(); - Set expectedValues = TestInstallationManager.history.keySet(); - Set actual = new HashSet<>(Arrays.asList(lines)); - for (String actualStr : actual) { - for (Iterator it = expectedValues.iterator(); it.hasNext();) { - if (actualStr.contains(it.next())) { - it.remove(); - } - } - } - Assert.assertTrue(Arrays.asList(lines).toString(), expectedValues.isEmpty()); - } - - @Test - public void testRevisionDetails() throws Exception { - String host = "primary"; - cli.sendLine("installer history --revision=dummy --host=" + host); - String output = cli.readOutput(); - - assertTrue(output, output.contains("org.test.groupid1:org.test.artifact1.installed")); - assertTrue(output, output.contains("org.test.groupid1:org.test.artifact1.removed")); - assertTrue(output, output.contains("org.test.groupid1:org.test.artifact1.updated")); - assertTrue(output, output.contains("[Added channel] channel-test-0")); - assertTrue(output, output.contains("[Removed channel] channel-test-0")); - assertTrue(output, output.contains("[Updated channel] channel-test-0")); - } - - @Test - public void testCreateSnapShot() throws IOException { - String host = "primary"; - Path exportPath = TARGET_DIR.normalize().toAbsolutePath().resolve("generated.zip"); - try { - cli.sendLine("attachment save --operation=/host=" + host + "/core-service=installer:clone-export() --file=" + exportPath); - String output = cli.readOutput(); - String expected = "File saved to " + exportPath; - assertEquals(expected, output); - - boolean found = false; - try (ZipInputStream zis = new ZipInputStream(new FileInputStream(exportPath.toFile()))) { - ZipEntry entry; - while ((entry = zis.getNextEntry()) != null) { - String entryName = entry.getName(); - if (entryName.startsWith("installation-manager-test-") && entryName.endsWith(".tmp")) { - found = true; - break; - } - } - } - Assert.assertTrue("Cannot found the expected entry added by the TestInstallationManager.java in the clone export Zip result", found); - } finally { - File expectedExportFile = exportPath.toFile(); - if (expectedExportFile.exists()) { - expectedExportFile.delete(); - } - } - } - - @Test - public void updateWithDryRun() { - String host = "primary"; - cli.sendLine("installer update --dry-run --host=" + host); - String output = cli.readOutput(); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - } - - @Test - public void updateWithConfirm() throws IOException { - String host = "primary"; - cli.sendLine("installer update --repositories=id0::http://localhost --confirm --host=" + host); - String output = cli.readOutput(); - - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - - Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); - Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(primaryPrepareServerDir,p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void updateWithConfirmRepositories() throws IOException { - String host = "primary"; - cli.sendLine("installer update --confirm --repositories=id0::http://localhost --host=" + host); - String output = cli.readOutput(); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - - Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); - Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void updateWithConfirmLocalCache() throws IOException { - String host = "primary"; - - cli.sendLine("installer update --confirm --local-cache=" + TARGET_DIR + " --host=" + host); - String output = cli.readOutput(); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - - Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); - Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void updateLocalCacheWithUseDefaultLocalCache() { - String host = "primary"; - - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer update --local-cache=" + TARGET_DIR + " --use-default-local-cache --host=" + host); - }); - - String expectedMessage = "WFLYIM0021:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - - exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer update --local-cache=" + TARGET_DIR + " --use-default-local-cache --host=" + host); - }); - - expectedMessage = "WFLYIM0021:"; - actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - } - - @Test - public void cannotUseConfirmAndDryRunAtTheSameTime() { - String host = "primary"; - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer update --confirm --dry-run --host=" + host); - }); - - String expectedMessage = UpdateCommand.CONFIRM_OPTION + " and " + UpdateCommand.DRY_RUN_OPTION + " cannot be used at the same time."; - String actualMessage = exception.getMessage(); - - assertTrue(actualMessage, actualMessage.contains(expectedMessage)); - } - - @Test - public void updateWithConfirmUsingMavenZipFile() throws IOException { - String host = "primary"; - Path target = TARGET_DIR.resolve("installation-manager.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), target); - - cli.sendLine("installer update --confirm --maven-repo-files=" + target + " --host=" + host); - String output = cli.readOutput(); - verifyUpdatePrepareDirWasCreated(host, output); - - } - @Test - public void updateWithConfirmUsingMultipleMavenZipFiles() throws IOException { - String host = "primary"; - Path targetOne = TARGET_DIR.resolve("installation-manager-one.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), targetOne); - - Path targetTwo = TARGET_DIR.resolve("installation-manager-two.zip"); - source = new File(getClass().getResource("test-repo-two").getFile()); - zipDir(source.toPath().toAbsolutePath(), targetTwo); - - cli.sendLine("installer update --confirm --maven-repo-files=" + targetOne + "," + targetTwo + " --host=" + host); - String output = cli.readOutput(); - verifyUpdatePrepareDirWasCreated(host, output); - } - - public void verifyUpdatePrepareDirWasCreated(String host, String output) throws IOException { - final Path expectedPreparedServerDir = host.equals("primary") ? primaryPrepareServerDir : secondaryPrepareServerDir; - - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - Assert.assertTrue(output, - output.contains("The candidate server has been generated. To apply it, restart the server with 'shutdown --perform-installation' command.")); - - Assert.assertTrue(Files.exists(expectedPreparedServerDir) && Files.isDirectory(expectedPreparedServerDir)); - Assert.assertTrue(expectedPreparedServerDir + " does not contain the expected file marker", - directoryOnlyContains(expectedPreparedServerDir, p -> expectedPreparedServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - - @Test - public void updateWithDryRunMavenZipFile() throws IOException { - String host = "primary"; - Path target = TARGET_DIR.resolve("installation-manager.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), target); - - cli.sendLine("installer update --dry-run --maven-repo-files=" + target + " --host=" + host); - String output = cli.readOutput(); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - Assert.assertFalse(output, - output.contains("The candidate server has been generated. To apply it, restart the server with 'shutdown --perform-installation' command.")); - - Assert.assertFalse(Files.exists(primaryPrepareServerDir)); - } - - @Test - public void updateWithDryRunMultipleMavenZipFile() throws IOException { - String host = "primary"; - Path targetOne = TARGET_DIR.resolve("installation-manager-one.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), targetOne); - - Path targetTwo = TARGET_DIR.resolve("installation-manager-two.zip"); - source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), targetTwo); - - cli.sendLine("installer update --dry-run --maven-repo-files=" + targetOne +","+ targetTwo + " --host=" + host); - String output = cli.readOutput(); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - Assert.assertFalse(output, - output.contains("The candidate server has been generated. To apply it, restart the server with 'shutdown --perform-installation' command.")); - - Assert.assertFalse(Files.exists(primaryPrepareServerDir)); - } - - @Test - public void updateUsingBlockingTimeout() throws IOException { - String host = "secondary"; - assertTrue(cli.sendLine("installer update --confirm --headers={blocking-timeout=100} --host=" + host, false)); - - Assert.assertTrue(Files.exists(secondaryPrepareServerDir) && Files.isDirectory(secondaryPrepareServerDir)); - Assert.assertTrue(secondaryPrepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(secondaryPrepareServerDir, p -> secondaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void updateCannotBeUsedWithMavenRepoFileAndRepositories() throws IOException { - String host = "primary"; - - Path target = TARGET_DIR.resolve("installation-manager.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), target); - - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer update --repositories=id0::http://localhost --maven-repo-files=" + target + " --host=" + host); - }); - - String expectedMessage = "WFLYIM0012:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - } - - @Test - public void revertWithMavenZipFile() throws IOException { - String host = "primary"; - - Path target = TARGET_DIR.resolve("installation-manager.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), target); - - Assert.assertTrue(cli.sendLine("installer revert --revision=dummy --maven-repo-files=" + target + " --host=" + host, false)); - - Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); - Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertWithMultipleMavenZipFiles() throws IOException { - String host = "primary"; - - Path targetOne = TARGET_DIR.resolve("installation-manager-one.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), targetOne); - - Path targetTwo = TARGET_DIR.resolve("installation-manager-two.zip"); - source = new File(getClass().getResource("test-repo-two").getFile()); - zipDir(source.toPath().toAbsolutePath(), targetTwo); - - Assert.assertTrue(cli.sendLine("installer revert --revision=dummy --maven-repo-files=" + targetOne + "," + targetTwo + " --host=" + host, false)); - - Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); - Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertWithNoResolveLocalMavenCache() throws IOException { - String host = "primary"; - - assertTrue(cli.sendLine("installer revert --revision=dummy --no-resolve-local-cache --host=" + host, false)); - - Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); - Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", - Files.list(primaryPrepareServerDir).allMatch(p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertWithUseDefaultLocalCache() throws IOException { - String host = "primary"; - - assertTrue(cli.sendLine("installer revert --revision=dummy --use-default-local-cache --host=" + host, false)); - - Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); - Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertWithLocalCacheMavenCache() throws IOException { - String host = "primary"; - - assertTrue(cli.sendLine("installer revert --revision=dummy --local-cache=" + TARGET_DIR + " --host=" + host, false)); - - Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); - Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertLocalCacheWithUseDefaultLocalCache() { - String host = "primary"; - - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer revert --revision=dummy --local-cache=" + TARGET_DIR + " --use-default-local-cache --host=" + host); - }); - - String expectedMessage = "WFLYIM0021:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - - exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer revert --revision=dummy --local-cache=" + TARGET_DIR + " --use-default-local-cache=true --host=" + host); - }); - - expectedMessage = "WFLYIM0021:"; - actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - } - - @Test - public void revertWithOffline() throws IOException { - String host = "primary"; - - assertTrue(cli.sendLine("installer revert --revision=dummy --offline --host=" + host, false)); - - Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); - Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertWithHeaders() throws IOException { - String host = "secondary"; - - assertTrue(cli.sendLine("installer revert --revision=dummy --headers={blocking-timeout=100} --host=" + host, false)); - - Assert.assertTrue(Files.exists(secondaryPrepareServerDir) && Files.isDirectory(secondaryPrepareServerDir)); - Assert.assertTrue(secondaryPrepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(secondaryPrepareServerDir, p -> secondaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertWithRepositories() throws IOException { - String host = "primary"; - - assertTrue(cli.sendLine("installer revert --revision=dummy --repositories=id0::http://localhost --host=" + host, false)); - - Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); - Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void simpleRevert() throws IOException { - String host = "primary"; - - assertTrue(cli.sendLine("installer revert --revision=dummy --host=" + host, false)); - - Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); - Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertCannotBeUsedWithoutRevision() { - String host = "primary"; - - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer revert --host=" + host); - }); - - String expectedMessage = "WFLYCTL0155:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - } - - @Test - public void revertCannotBeUsedWithMavenRepoFileAndRepositories() throws IOException { - String host = "primary"; - - Path target = TARGET_DIR.resolve("installation-manager.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), target); - - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer revert --revision=dummy --repositories=id0::http://localhost --maven-repo-files=" + target + " --host=" + host); - }); - - String expectedMessage = "WFLYIM0012:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - } - - @Test - public void uploadAndRemoveCustomPatch() throws IOException { - String host = "primary"; - String patchManifestGA = "group:artifact"; - Path hostCustomPatchDir = primaryCustomPatchBaseDir.resolve(patchManifestGA.replace(":", "_")); - - createAndUploadCustomPatch(patchManifestGA, host, hostCustomPatchDir, "test-repo-one", "artifact-one"); - removeCustomPatch(patchManifestGA, host, hostCustomPatchDir); - } - - @Test - public void removeNonExistingCustomPatch() { - String host = "primary"; - String patchManifestGA = "group-unknown:artifact-unknown"; - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer remove-custom-patch --manifest=" + patchManifestGA + " --host=" + host); - }); - String expectedMessage = "WFLYIM0020:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(actualMessage, actualMessage.contains(expectedMessage)); - - } - - @Test - public void uploadAndRemoveMultipleCustomPatches() throws IOException { - String host = "primary"; - String patchManifestGA_1 = "group1:artifact1"; - Path hostCustomPatchDir_1 = primaryCustomPatchBaseDir.resolve(patchManifestGA_1.replace(":", "_")); - createAndUploadCustomPatch(patchManifestGA_1, host, hostCustomPatchDir_1, "test-repo-one", "artifact-one"); - - String patchManifestGA_2 = "group2:artifact2"; - Path hostCustomPatchDir_2 = primaryCustomPatchBaseDir.resolve(patchManifestGA_2.replace(":", "_")); - createAndUploadCustomPatch(patchManifestGA_2, host, hostCustomPatchDir_2, "test-repo-two", "artifact-two"); - - removeCustomPatch(patchManifestGA_1, host, hostCustomPatchDir_1); - - // check we still have the second patch - final Path customPatchMavenRepo = hostCustomPatchDir_2.resolve(InstMgrConstants.MAVEN_REPO_DIR_NAME_IN_ZIP_FILES); - Assert.assertTrue(Files.exists(customPatchMavenRepo) && Files.isDirectory(customPatchMavenRepo)); - Assert.assertTrue(hostCustomPatchDir_2 + " does not contain the expected maven repository", - directoryOnlyContains(customPatchMavenRepo, p -> customPatchMavenRepo.relativize(p).toString().equals("artifact-two"))); - - // remove the patch 2 - removeCustomPatch(patchManifestGA_2, host, hostCustomPatchDir_2); - } - - @Test - public void testProductInfoIncludesInstallerInfo() throws Exception { - cli.sendLine(":product-info"); - - ModelNode res = cli.readAllAsOpResult().getResponseNode(); - - final List hostResults = res.get("result").asList(); - for (ModelNode host : hostResults) { - final List summaries = host.get("result").asList(); - for (ModelNode summary : summaries) { - summary = summary.get("summary"); - if (!summary.hasDefined("instance-identifier")) { - continue; - } - - Assert.assertTrue(summary.toString(), summary.hasDefined("last-update-date")); - Assert.assertTrue(summary.hasDefined("channel-versions")); - Assert.assertEquals(List.of(new ModelNode("Update 1")), summary.get("channel-versions").asList()); - } - } - } - - public void createAndUploadCustomPatch(String customPatchManifest, String host, Path hostCustomPatchDir, String mavenDirToZip, String expectedArtifact) throws IOException { - Path target = TARGET_DIR.resolve("installation-manager.zip"); - File source = new File(getClass().getResource(mavenDirToZip).getFile()); - zipDir(source.toPath().toAbsolutePath(), target); - - // verify the patch doesn't exist yet - final Path customPatchMavenRepo = hostCustomPatchDir.resolve(InstMgrConstants.MAVEN_REPO_DIR_NAME_IN_ZIP_FILES); - Assert.assertFalse(Files.exists(customPatchMavenRepo)); - - Assert.assertTrue( - cli.sendLine("installer upload-custom-patch --custom-patch-file=" + target + " --manifest=" + customPatchManifest + " --host=" + host, false)); - // verify clean operation without arguments don't remove the patch - Assert.assertTrue(cli.sendLine("installer clean --host=" + host, false)); - Assert.assertTrue(Files.exists(customPatchMavenRepo) && Files.isDirectory(customPatchMavenRepo)); - Assert.assertTrue(hostCustomPatchDir + " does not contain the expected artifact included in the custom patch Zip file", - directoryOnlyContains(customPatchMavenRepo, p -> customPatchMavenRepo.relativize(p).toString().equals(expectedArtifact))); - } - - public void removeCustomPatch(String customPatchManifest, String host, Path hostCustomPatchDir) { - // remove the custom patch - final Path primaryCustomPatchMavenRepo = hostCustomPatchDir.resolve(InstMgrConstants.MAVEN_REPO_DIR_NAME_IN_ZIP_FILES); - Assert.assertTrue(cli.sendLine("installer remove-custom-patch --manifest=" + customPatchManifest + " --host=" + host, false)); - Assert.assertFalse(Files.exists(primaryCustomPatchMavenRepo)); + final String expectedMessage = "The --host option must be used in domain mode."; + testHostParameter(null, (actualMessage)->assertTrue(actualMessage, actualMessage.contains(expectedMessage))); } - @Test - public void cannotShutDownIfNoServerPrepared() { - String host = "primary"; - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("shutdown --perform-installation --host=" + host); - }); - String expectedMessage = "WFLYHC0218:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(actualMessage, actualMessage.contains(expectedMessage)); - } - - public static void zipDir(Path sourcePath, Path target) throws IOException { - try (FileOutputStream fos = new FileOutputStream(target.toFile()); ZipOutputStream zos = new ZipOutputStream(fos)) { - Files.walkFileTree(sourcePath, new SimpleFileVisitor<>() { - @Override - public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { - if (!sourcePath.equals(dir)) { - zos.putNextEntry(new ZipEntry(sourcePath.relativize(dir) + "/")); - zos.closeEntry(); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { - zos.putNextEntry(new ZipEntry(sourcePath.relativize(file).toString())); - Files.copy(file, zos); - zos.closeEntry(); - return FileVisitResult.CONTINUE; - } - }); - } - } - - public String getCauseLogFailure(String description, String expectedLogCode) { - return "Unexpected Error Code. Got " + description + " It was expected: " + expectedLogCode; + @Override + protected LinkedHashMap getServerDirs() { + // Note: preserve order of insertion using LinkedHashMap + final LinkedHashMap dirs = new LinkedHashMap<>(); + dirs.put("primary", new ServerPaths(primaryPrepareServerDir, primaryCustomPatchBaseDir)); + dirs.put("secondary", new ServerPaths(secondaryPrepareServerDir, secondaryCustomPatchBaseDir)); + return dirs; } - public boolean directoryOnlyContains(Path directory, Predicate match) throws IOException { - try (Stream stream = Files.list(directory)) { - return stream.allMatch(match); - } + @Override + protected String getNoPreparedServerErrorCode() { + return "WFLYHC0218:"; } } diff --git a/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/suites/SimpleRbacProviderTestSuite.java b/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/suites/SimpleRbacProviderTestSuite.java index 0dce4dc6686..23c02255cfc 100644 --- a/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/suites/SimpleRbacProviderTestSuite.java +++ b/testsuite/domain/src/test/java/org/jboss/as/test/integration/domain/suites/SimpleRbacProviderTestSuite.java @@ -6,6 +6,7 @@ package org.jboss.as.test.integration.domain.suites; import java.io.IOException; +import java.net.URL; import org.jboss.as.test.integration.domain.extension.ExtensionSetup; import org.jboss.as.test.integration.domain.management.util.DomainTestSupport; @@ -125,10 +126,12 @@ public static boolean isTestSuiteEnabled() { private static void createTestModule() throws IOException { testModule = new TestModule(MODULE_NAME, "org.wildfly.installation-manager.api"); + final URL serviceLoader = SimpleRbacProviderTestSuite.class.getClassLoader() + .getResource("org/wildfly/test/installationmanager/services/org.wildfly.installationmanager.spi.InstallationManagerFactory"); testModule.addResource("test-mock-installation-manager.jar") .addClass(TestInstallationManager.class) .addClass(TestInstallationManagerFactory.class) - .addAsManifestResource("META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory", + .addAsManifestResource(serviceLoader, "services/org.wildfly.installationmanager.spi.InstallationManagerFactory"); testModule.create(true); } diff --git a/testsuite/manualmode/src/test/java/org/jboss/as/test/manualmode/installationmanager/InstallationManagerIntegrationTestCase.java b/testsuite/manualmode/src/test/java/org/jboss/as/test/manualmode/installationmanager/InstallationManagerIntegrationTestCase.java index 6b346b8802c..389c08e323f 100644 --- a/testsuite/manualmode/src/test/java/org/jboss/as/test/manualmode/installationmanager/InstallationManagerIntegrationTestCase.java +++ b/testsuite/manualmode/src/test/java/org/jboss/as/test/manualmode/installationmanager/InstallationManagerIntegrationTestCase.java @@ -5,56 +5,28 @@ package org.jboss.as.test.manualmode.installationmanager; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Stream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; +import java.util.LinkedHashMap; import jakarta.inject.Inject; -import org.jboss.as.cli.Util; import org.jboss.as.test.integration.management.base.AbstractCliTestBase; -import org.jboss.as.test.module.util.TestModule; import org.jboss.as.test.shared.TestSuiteEnvironment; -import org.jboss.dmr.ModelNode; -import org.junit.After; import org.junit.AfterClass; -import org.junit.Assert; import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; import org.wildfly.core.instmgr.InstMgrConstants; -import org.wildfly.core.instmgr.cli.UpdateCommand; import org.wildfly.core.testrunner.ManagementClient; import org.wildfly.core.testrunner.ServerControl; import org.wildfly.core.testrunner.ServerController; import org.wildfly.core.testrunner.WildFlyRunner; -import org.wildfly.installationmanager.Channel; -import org.wildfly.installationmanager.Repository; -import org.wildfly.test.installationmanager.TestInstallationManager; -import org.wildfly.test.installationmanager.TestInstallationManagerFactory; +import org.wildfly.test.installationmanager.BaseInstallationManagerTestCase; /** * Tests the high-level Installation Manager commands in standalone mode environment. It uses a mocked implementation of the @@ -68,14 +40,8 @@ @RunWith(WildFlyRunner.class) @ServerControl(manual = true) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class InstallationManagerIntegrationTestCase extends AbstractCliTestBase { - - private static final String MODULE_NAME = "org.jboss.prospero"; - private static TestModule testModule; - +public class InstallationManagerIntegrationTestCase extends BaseInstallationManagerTestCase { private static Path prepareServerDir; - - static final Path TARGET_DIR = Paths.get(System.getProperty("basedir", ".")).resolve("target"); static Path customPatchBaseDir; @Inject @@ -105,663 +71,22 @@ public static void tearDownDomain() throws Exception { } } - private static void createTestModule() throws IOException { - testModule = new TestModule(MODULE_NAME, "org.wildfly.installation-manager.api"); - testModule.addResource("test-mock-installation-manager.jar").addClass(TestInstallationManager.class).addClass(TestInstallationManagerFactory.class) - .addAsManifestResource("META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory", - "services/org.wildfly.installationmanager.spi.InstallationManagerFactory"); - testModule.create(true); + @Override + protected LinkedHashMap getServerDirs() { + // Note: preserve order of insertion using LinkedHashMap + final LinkedHashMap dirs = new LinkedHashMap<>(); + dirs.put(DEFAULT_HOST, new ServerPaths(prepareServerDir, customPatchBaseDir)); + return dirs; } - @After - public void clean() throws IOException { - // Clean any previous state - assertTrue(cli.sendLine("installer clean", false)); - Assert.assertTrue(!Files.exists(prepareServerDir)); - - for(File testZip : TARGET_DIR.toFile().listFiles((dir, name) -> name.startsWith("installation-manager") && name.endsWith(".zip"))) { - Files.deleteIfExists(testZip.toPath()); - } + @Override + protected String getNoPreparedServerErrorCode() { + return "WFLYSRV0295:"; } @Test public void rejectsHost() { - final List commands = List.of("update", "clean", "revert", "history", "channel-list", - "channel-add --channel-name test --manifest test --repositories test", "channel-edit --channel-name test --manifest test --repositories test", - "channel-remove --channel-name test", "upload-custom-patch --custom-patch-file=dummy --manifest=manifest"); - - for (String command : commands) { - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer " + command + " --host=test"); - }); - - String expectedMessage = "The --host option is not available in the current context."; - String actualMessage = exception.getMessage(); - - assertTrue(actualMessage, actualMessage.contains(expectedMessage)); - } - } - - public static String buildChannelOutput(Channel channel) { - final String returnChar = Util.isWindows() ? "\r\n" : "\n"; - - StringBuilder sb = new StringBuilder("-------").append(returnChar).append("# " + channel.getName()).append(returnChar); - - if (channel.getManifestUrl().isPresent()) { - sb.append(" manifest: " + channel.getManifestUrl().get()).append(returnChar); - } else if (channel.getManifestCoordinate().isPresent()) { - sb.append(" manifest: " + channel.getManifestCoordinate().get()).append(returnChar); - } - - sb.append(" repositories:").append(returnChar); - - for (Repository repository : channel.getRepositories()) { - sb.append(" id: " + repository.getId()).append(returnChar).append(" url: " + repository.getUrl()).append(returnChar); - } - - return sb.toString(); - } - - @Test - public void _a_listChannel() throws Exception { - cli.sendLine("installer channel-list"); - String output = cli.readOutput(); - - TestInstallationManager.initialize(); - - StringBuilder expected = new StringBuilder(); - for (Channel channel : TestInstallationManager.lstChannels) { - expected.append(buildChannelOutput(channel)); - } - expected.append("-------"); - - Assert.assertEquals(expected.toString(), output); - } - - @Test - public void _b_addChannel() throws IOException { - String channelName = "test-primary"; - String manifestGavOrUrl = "group:artifact:primary-1.0.0.Final"; - String repoStr = "https://primary.com"; - - cli.sendLine( - "installer channel-add --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr); - String output = cli.readOutput(); - Assert.assertEquals("Channel '" + channelName + "' created.", output); - - cli.sendLine("installer channel-list"); - output = cli.readOutput(); - - StringBuilder expected = new StringBuilder(); - - TestInstallationManager.initialize(); - for (Channel channel : TestInstallationManager.lstChannels) { - expected.append(buildChannelOutput(channel)); - } - - Repository repository = new Repository("id0", repoStr); - Channel newChannel = new Channel(channelName, List.of(repository), manifestGavOrUrl); - expected.append(buildChannelOutput(newChannel)); - expected.append("-------"); - - Assert.assertEquals(expected.toString(), output); - } - - @Test - public void _c_removeChannel() { - String channelName = "channel-test-1"; - cli.sendLine("installer channel-remove --channel-name=" + channelName); - String output = cli.readOutput(); - Assert.assertEquals("Channel '" + channelName + "' has been successfully removed.", output); - } - - @Test - public void _d_editChannel() { - String channelName = "channel-test-2"; - String manifestGavOrUrl = "group:artifact:edited-1.0.0.Final"; - String repoStr = "https://edited.com"; - - cli.sendLine( - "installer channel-edit --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr); - String output = cli.readOutput(); - Assert.assertEquals("Channel '" + channelName + "' has been modified.", output); - - cli.sendLine("installer channel-list"); - output = cli.readOutput(); - - Repository repository = new Repository("id0", repoStr); - Channel newChannel = new Channel(channelName, List.of(repository), manifestGavOrUrl); - String expected = buildChannelOutput(newChannel); - Assert.assertTrue(output, output.contains(expected)); - } - - @Test - public void _e_editChannelNotExist() { - String channelName = "unknown"; - String manifestGavOrUrl = "group:artifact:edited-1.0.0.Final"; - String repoStr = "https://edited.com"; - - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer channel-edit --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr); - }); - - String expectedMessage = "Channel '" + channelName + "' is not present."; - String actualMessage = exception.getMessage(); - - assertTrue(actualMessage, actualMessage.contains(expectedMessage)); - } - - @Test - public void _f_testHistory() throws IOException { - cli.sendLine("installer history"); - String output = cli.readOutput(); - - String[] lines = output.split("\n"); - assertEquals(4, lines.length); - - TestInstallationManager.initialize(); - Set expectedValues = TestInstallationManager.history.keySet(); - Set actual = new HashSet<>(Arrays.asList(lines)); - for (String actualStr : actual) { - for (Iterator it = expectedValues.iterator(); it.hasNext();) { - if (actualStr.contains(it.next())) { - it.remove(); - } - } - } - Assert.assertTrue(Arrays.asList(lines).toString(), expectedValues.isEmpty()); - } - - @Test - public void testRevisionDetails() throws Exception { - cli.sendLine("installer history --revision=dummy"); - String output = cli.readOutput(); - - assertTrue(output, output.contains("org.test.groupid1:org.test.artifact1.installed")); - assertTrue(output, output.contains("org.test.groupid1:org.test.artifact1.removed")); - assertTrue(output, output.contains("org.test.groupid1:org.test.artifact1.updated")); - assertTrue(output, output.contains("[Added channel] channel-test-0")); - assertTrue(output, output.contains("[Removed channel] channel-test-0")); - assertTrue(output, output.contains("[Updated channel] channel-test-0")); - } - - @Test - public void testCreateSnapShot() throws IOException { - Path exportPath = TARGET_DIR.normalize().toAbsolutePath().resolve("generated.zip"); - try { - cli.sendLine("attachment save --operation=/core-service=installer:clone-export() --file=" + exportPath); - String output = cli.readOutput(); - String expected = "File saved to " + exportPath; - assertEquals(expected, output); - - boolean found = false; - try (ZipInputStream zis = new ZipInputStream(new FileInputStream(exportPath.toFile()))) { - ZipEntry entry; - while ((entry = zis.getNextEntry()) != null) { - String entryName = entry.getName(); - if (entryName.startsWith("installation-manager-test-") && entryName.endsWith(".tmp")) { - found = true; - break; - } - } - } - Assert.assertTrue("Cannot found the expected entry added by the TestInstallationManager.java in the clone export Zip result", found); - } finally { - File expectedExportFile = exportPath.toFile(); - if (expectedExportFile.exists()) { - expectedExportFile.delete(); - } - } - } - - @Test - public void updateWithDryRun() { - cli.sendLine("installer update --dry-run"); - String output = cli.readOutput(); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - } - - @Test - public void updateWithConfirm() throws IOException { - cli.sendLine("installer update --repositories=id0::http://localhost --confirm"); - String output = cli.readOutput(); - - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - - Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); - Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void updateWithConfirmRepositories() throws IOException { - cli.sendLine("installer update --confirm --repositories=id0::http://localhost"); - String output = cli.readOutput(); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - - Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); - Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void updateWithConfirmLocalCache() throws IOException { - cli.sendLine("installer update --confirm --local-cache=" + TARGET_DIR); - String output = cli.readOutput(); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - - Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); - Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void updateLocalCacheWithUseDefaultLocalCache() { - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer update --local-cache=" + TARGET_DIR + " --use-default-local-cache"); - }); - - String expectedMessage = "WFLYIM0021:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - - exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer update --local-cache=" + TARGET_DIR + " --use-default-local-cache"); - }); - - expectedMessage = "WFLYIM0021:"; - actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - } - - @Test - public void cannotUseConfirmAndDryRunAtTheSameTime() { - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer update --confirm --dry-run"); - }); - - String expectedMessage = UpdateCommand.CONFIRM_OPTION + " and " + UpdateCommand.DRY_RUN_OPTION + " cannot be used at the same time."; - String actualMessage = exception.getMessage(); - - assertTrue(actualMessage, actualMessage.contains(expectedMessage)); - } - - @Test - public void updateWithConfirmUsingMavenZipFile() throws IOException { - Path target = TARGET_DIR.resolve("installation-manager.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), target); - - cli.sendLine("installer update --confirm --maven-repo-files=" + target); - String output = cli.readOutput(); - verifyUpdatePrepareDirWasCreated(output); - - } - @Test - public void updateWithConfirmUsingMultipleMavenZipFiles() throws IOException { - Path targetOne = TARGET_DIR.resolve("installation-manager-one.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), targetOne); - - Path targetTwo = TARGET_DIR.resolve("installation-manager-two.zip"); - source = new File(getClass().getResource("test-repo-two").getFile()); - zipDir(source.toPath().toAbsolutePath(), targetTwo); - - cli.sendLine("installer update --confirm --maven-repo-files=" + targetOne + "," + targetTwo); - String output = cli.readOutput(); - verifyUpdatePrepareDirWasCreated(output); - } - - public void verifyUpdatePrepareDirWasCreated(String output) throws IOException { - final Path expectedPreparedServerDir = prepareServerDir; - - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - Assert.assertTrue(output, - output.contains("The candidate server has been generated. To apply it, restart the server with 'shutdown --perform-installation' command.")); - - Assert.assertTrue(Files.exists(expectedPreparedServerDir) && Files.isDirectory(expectedPreparedServerDir)); - Assert.assertTrue(expectedPreparedServerDir + " does not contain the expected file marker", - directoryOnlyContains(expectedPreparedServerDir, p -> expectedPreparedServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - - @Test - public void updateWithDryRunMavenZipFile() throws IOException { - Path target = TARGET_DIR.resolve("installation-manager.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), target); - - cli.sendLine("installer update --dry-run --maven-repo-files=" + target); - String output = cli.readOutput(); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - Assert.assertFalse(output, - output.contains("The candidate server has been generated. To apply it, restart the server with 'shutdown --perform-installation' command.")); - - Assert.assertFalse(Files.exists(prepareServerDir)); - } - - @Test - public void updateWithDryRunMultipleMavenZipFile() throws IOException { - Path targetOne = TARGET_DIR.resolve("installation-manager-one.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), targetOne); - - Path targetTwo = TARGET_DIR.resolve("installation-manager-two.zip"); - source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), targetTwo); - - cli.sendLine("installer update --dry-run --maven-repo-files=" + targetOne +","+ targetTwo); - String output = cli.readOutput(); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); - Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); - Assert.assertFalse(output, - output.contains("The candidate server has been generated. To apply it, restart the server with 'shutdown --perform-installation' command.")); - - Assert.assertFalse(Files.exists(prepareServerDir)); - } - - @Test - public void updateUsingBlockingTimeout() throws IOException { - assertTrue(cli.sendLine("installer update --confirm --headers={blocking-timeout=100}", false)); - - Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); - Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void updateCannotBeUsedWithMavenRepoFileAndRepositories() throws IOException { - Path target = TARGET_DIR.resolve("installation-manager.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), target); - - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer update --repositories=id0::http://localhost --maven-repo-files=" + target); - }); - - String expectedMessage = "WFLYIM0012:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - } - - @Test - public void revertWithMavenZipFile() throws IOException { - Path target = TARGET_DIR.resolve("installation-manager.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), target); - - Assert.assertTrue(cli.sendLine("installer revert --revision=dummy --maven-repo-files=" + target, false)); - - Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); - Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertWithMultipleMavenZipFiles() throws IOException { - Path targetOne = TARGET_DIR.resolve("installation-manager-one.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), targetOne); - - Path targetTwo = TARGET_DIR.resolve("installation-manager-two.zip"); - source = new File(getClass().getResource("test-repo-two").getFile()); - zipDir(source.toPath().toAbsolutePath(), targetTwo); - - Assert.assertTrue(cli.sendLine("installer revert --revision=dummy --maven-repo-files=" + targetOne + "," + targetTwo, false)); - - Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); - Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertWithNoResolveLocalMavenCache() throws IOException { - assertTrue(cli.sendLine("installer revert --revision=dummy --no-resolve-local-cache", false)); - - Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); - Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", - Files.list(prepareServerDir).allMatch(p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertWithUseDefaultLocalCache() throws IOException { - assertTrue(cli.sendLine("installer revert --revision=dummy --use-default-local-cache", false)); - - Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); - Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertWithLocalCacheMavenCache() throws IOException { - assertTrue(cli.sendLine("installer revert --revision=dummy --local-cache=" + TARGET_DIR, false)); - - Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); - Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertLocalCacheWithUseDefaultLocalCache() { - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer revert --revision=dummy --local-cache=" + TARGET_DIR + " --use-default-local-cache"); - }); - - String expectedMessage = "WFLYIM0021:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - - exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer revert --revision=dummy --local-cache=" + TARGET_DIR + " --use-default-local-cache=true"); - }); - - expectedMessage = "WFLYIM0021:"; - actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - } - - @Test - public void revertWithOffline() throws IOException { - assertTrue(cli.sendLine("installer revert --revision=dummy --offline", false)); - - Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); - Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertWithHeaders() throws IOException { - assertTrue(cli.sendLine("installer revert --revision=dummy --headers={blocking-timeout=100}", false)); - - Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); - Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertWithRepositories() throws IOException { - assertTrue(cli.sendLine("installer revert --revision=dummy --repositories=id0::http://localhost", false)); - - Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); - Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void simpleRevert() throws IOException { - assertTrue(cli.sendLine("installer revert --revision=dummy", false)); - - Assert.assertTrue(Files.exists(prepareServerDir) && Files.isDirectory(prepareServerDir)); - Assert.assertTrue(prepareServerDir + " does not contain the expected file marker", - directoryOnlyContains(prepareServerDir, p -> prepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); - } - - @Test - public void revertCannotBeUsedWithoutRevision() { - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer revert"); - }); - - String expectedMessage = "WFLYCTL0155:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - } - - @Test - public void revertCannotBeUsedWithMavenRepoFileAndRepositories() throws IOException { - Path target = TARGET_DIR.resolve("installation-manager.zip"); - File source = new File(getClass().getResource("test-repo-one").getFile()); - zipDir(source.toPath().toAbsolutePath(), target); - - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer revert --revision=dummy --repositories=id0::http://localhost --maven-repo-files=" + target); - }); - - String expectedMessage = "WFLYIM0012:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); - } - - @Test - public void uploadAndRemoveCustomPatch() throws IOException { - String patchManifestGA = "group:artifact"; - Path customPatchDir = customPatchBaseDir.resolve(patchManifestGA.replace(":", "_")); - - createAndUploadCustomPatch(patchManifestGA, customPatchDir, "test-repo-one", "artifact-one"); - removeCustomPatch(patchManifestGA, customPatchDir); - } - - @Test - public void removeNonExistingCustomPatch() { - String patchManifestGA = "group-unknown:artifact-unknown"; - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("installer remove-custom-patch --manifest=" + patchManifestGA); - }); - String expectedMessage = "WFLYIM0020:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(actualMessage, actualMessage.contains(expectedMessage)); - - } - - @Test - public void uploadAndRemoveMultipleCustomPatches() throws IOException { - String patchManifestGA_1 = "group1:artifact1"; - Path customPatchDir_1 = customPatchBaseDir.resolve(patchManifestGA_1.replace(":", "_")); - createAndUploadCustomPatch(patchManifestGA_1, customPatchDir_1, "test-repo-one", "artifact-one"); - - String patchManifestGA_2 = "group2:artifact2"; - Path customPatchDir_2 = customPatchBaseDir.resolve(patchManifestGA_2.replace(":", "_")); - createAndUploadCustomPatch(patchManifestGA_2, customPatchDir_2, "test-repo-two", "artifact-two"); - - removeCustomPatch(patchManifestGA_1, customPatchDir_1); - - // check we still have the second patch - final Path customPatchMavenRepo = customPatchDir_2.resolve(InstMgrConstants.MAVEN_REPO_DIR_NAME_IN_ZIP_FILES); - Assert.assertTrue(Files.exists(customPatchMavenRepo) && Files.isDirectory(customPatchMavenRepo)); - Assert.assertTrue(customPatchDir_2 + " does not contain the expected maven repository", - directoryOnlyContains(customPatchMavenRepo, p -> customPatchMavenRepo.relativize(p).toString().equals("artifact-two"))); - - // remove the patch 2 - removeCustomPatch(patchManifestGA_2, customPatchDir_2); - } - - @Test - public void testProductInfoIncludesInstallerInfo() throws Exception { - cli.sendLine(":product-info"); - - ModelNode response = cli.readAllAsOpResult().getResponseNode(); - - final List results = response.get("result").asList(); - for (ModelNode res : results) { - final ModelNode summary = res.get("result").get("summary"); - if (!summary.hasDefined("instance-identifier")) { - continue; - } - - Assert.assertTrue(summary.toString(), summary.hasDefined("last-update-date")); - Assert.assertTrue(summary.hasDefined("channel-versions")); - Assert.assertEquals(List.of(new ModelNode("Update 1")), summary.get("channel-versions").asList()); - } - } - - public void createAndUploadCustomPatch(String customPatchManifest, Path customPatchDir, String mavenDirToZip, String expectedArtifact) throws IOException { - Path target = TARGET_DIR.resolve("installation-manager.zip"); - File source = new File(getClass().getResource(mavenDirToZip).getFile()); - zipDir(source.toPath().toAbsolutePath(), target); - - // verify the patch doesn't exist yet - final Path customPatchMavenRepo = customPatchDir.resolve(InstMgrConstants.MAVEN_REPO_DIR_NAME_IN_ZIP_FILES); - Assert.assertFalse(Files.exists(customPatchMavenRepo)); - - Assert.assertTrue( - cli.sendLine("installer upload-custom-patch --custom-patch-file=" + target + " --manifest=" + customPatchManifest, false)); - // verify clean operation without arguments don't remove the patch - Assert.assertTrue(cli.sendLine("installer clean", false)); - Assert.assertTrue(Files.exists(customPatchMavenRepo) && Files.isDirectory(customPatchMavenRepo)); - Assert.assertTrue(customPatchDir + " does not contain the expected artifact included in the custom patch Zip file", - directoryOnlyContains(customPatchMavenRepo, p -> customPatchMavenRepo.relativize(p).toString().equals(expectedArtifact))); - } - - public void removeCustomPatch(String customPatchManifest, Path customPatchDir) { - // remove the custom patch - final Path customPatchMavenRepo = customPatchDir.resolve(InstMgrConstants.MAVEN_REPO_DIR_NAME_IN_ZIP_FILES); - Assert.assertTrue(cli.sendLine("installer remove-custom-patch --manifest=" + customPatchManifest, false)); - Assert.assertFalse(Files.exists(customPatchMavenRepo)); - } - - @Test - public void cannotShutDownIfNoServerPrepared() { - AssertionError exception = assertThrows(AssertionError.class, () -> { - cli.sendLine("shutdown --perform-installation"); - }); - String expectedMessage = "WFLYSRV0295:"; - String actualMessage = exception.getMessage(); - Assert.assertTrue(actualMessage, actualMessage.contains(expectedMessage)); - } - - public static void zipDir(Path sourcePath, Path target) throws IOException { - try (FileOutputStream fos = new FileOutputStream(target.toFile()); ZipOutputStream zos = new ZipOutputStream(fos)) { - Files.walkFileTree(sourcePath, new SimpleFileVisitor<>() { - @Override - public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { - if (!sourcePath.equals(dir)) { - zos.putNextEntry(new ZipEntry(sourcePath.relativize(dir) + "/")); - zos.closeEntry(); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { - zos.putNextEntry(new ZipEntry(sourcePath.relativize(file).toString())); - Files.copy(file, zos); - zos.closeEntry(); - return FileVisitResult.CONTINUE; - } - }); - } - } - - public String getCauseLogFailure(String description, String expectedLogCode) { - return "Unexpected Error Code. Got " + description + " It was expected: " + expectedLogCode; - } - - public boolean directoryOnlyContains(Path directory, Predicate match) throws IOException { - try (Stream stream = Files.list(directory)) { - return stream.allMatch(match); - } + final String expectedMessage = "The --host option is not available in the current context."; + testHostParameter("--host=test", (actualMessage)->assertTrue(actualMessage, actualMessage.contains(expectedMessage))); } } diff --git a/testsuite/manualmode/src/test/resources/META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory b/testsuite/manualmode/src/test/resources/META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory deleted file mode 100644 index 195816af124..00000000000 --- a/testsuite/manualmode/src/test/resources/META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory +++ /dev/null @@ -1,6 +0,0 @@ -# -# Copyright The WildFly Authors -# SPDX-License-Identifier: Apache-2.0 -# - -org.wildfly.test.installationmanager.TestInstallationManagerFactory diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/dummy_file_one.txt b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/dummy_file_one.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/maven-repository/artifact-one b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/maven-repository/artifact-one deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/other-directory-one/dummy_file_one.txt b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-one/other-directory-one/dummy_file_one.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/dummy_file_two.txt b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/dummy_file_two.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/maven-repository/artifact-two b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/maven-repository/artifact-two deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/other-directory-two/dummy_file_two.txt b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/installationmanager/test-repo-two/other-directory-two/dummy_file_two.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/testsuite/shared/src/main/java/org/wildfly/test/installationmanager/BaseInstallationManagerTestCase.java b/testsuite/shared/src/main/java/org/wildfly/test/installationmanager/BaseInstallationManagerTestCase.java new file mode 100644 index 00000000000..f57b1bc4d1e --- /dev/null +++ b/testsuite/shared/src/main/java/org/wildfly/test/installationmanager/BaseInstallationManagerTestCase.java @@ -0,0 +1,975 @@ +/* + * Copyright The WildFly Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.wildfly.test.installationmanager; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +import org.apache.commons.io.FileUtils; +import org.jboss.as.cli.Util; +import org.jboss.as.test.integration.management.base.AbstractCliTestBase; +import org.jboss.as.test.module.util.TestModule; +import org.jboss.dmr.ModelNode; +import org.jboss.dmr.ModelType; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runners.MethodSorters; +import org.wildfly.installationmanager.Channel; +import org.wildfly.installationmanager.Repository; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public abstract class BaseInstallationManagerTestCase extends AbstractCliTestBase { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + String MAVEN_REPO_DIR_NAME_IN_ZIP_FILES = "maven-repository"; + + protected static final String MODULE_NAME = "org.jboss.prospero"; + protected static final String DEFAULT_HOST = ""; + protected static TestModule testModule; + protected Path testRepoOnePath; + protected Path testRepoTwoPath; + + protected static final Path TARGET_DIR = Paths.get(System.getProperty("basedir", ".")).resolve("target"); + + @Before + public void copyRepositories() throws Exception { + final Path reposPath = temp.newFolder("repos").toPath(); + testRepoOnePath = reposPath.resolve("test-repo-one"); + testRepoTwoPath = reposPath.resolve("test-repo-two"); + + copyRepository("test-repo-one", reposPath); + copyRepository("test-repo-two", reposPath); + } + + @After + public void clean() throws IOException { + for (String host : getHosts()) { + // Clean any previous state + assertTrue(cli.sendLine("installer clean" + getHostSuffix(host), false)); + Assert.assertTrue(!Files.exists(getPreparedServerDir(host))); + + } + + for(File testZip : TARGET_DIR.toFile().listFiles((dir, name) -> name.startsWith("installation-manager") && name.endsWith(".zip"))) { + Files.deleteIfExists(testZip.toPath()); + } + } + + @Test + public void _a_listChannel() throws Exception { + TestInstallationManager.initialize(); + StringBuilder expected = new StringBuilder(); + for (Channel channel : TestInstallationManager.lstChannels) { + expected.append(buildChannelOutput(channel)); + } + expected.append("-------"); + + for (String host : getHosts()) { + cli.sendLine("installer channel-list" + getHostSuffix(host)); + String output = cli.readOutput(); + + Assert.assertEquals(expected.toString(), output); + } + } + + @Test + public void _b_addChannel() throws IOException { + + for (String host : getHosts()) { + final ServerChannel serverChannel = getServerChannels().get(host.equals(DEFAULT_HOST) ? "primary" : host); + String channelName = serverChannel.channelName; + String manifestGavOrUrl = serverChannel.manifestGavOrUrl; + String repoStr = serverChannel.repoStr; + + cli.sendLine( + "installer channel-add --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr + getHostSuffix(host)); + String output = cli.readOutput(); + Assert.assertEquals("Channel '" + channelName + "' created.", output); + + cli.sendLine("installer channel-list" + getHostSuffix(host)); + output = cli.readOutput(); + + StringBuilder expected = new StringBuilder(); + + TestInstallationManager.initialize(); + for (Channel channel : TestInstallationManager.lstChannels) { + expected.append(buildChannelOutput(channel)); + } + + + Repository repository = new Repository("id0", repoStr); + final String manifestLocation = manifestGavOrUrl.contains(":") ? manifestGavOrUrl : Path.of(manifestGavOrUrl).toUri().toURL().toExternalForm(); + Channel newChannel = new Channel(channelName, List.of(repository), manifestLocation); + expected.append(buildChannelOutput(newChannel)); + expected.append("-------"); + + Assert.assertEquals(expected.toString(), output); + + } + } + + @Test + public void _c_removeChannel() { + for (String host: getHosts()) { + final ServerChannel serverChannel = getServerChannels().get(host.equals(DEFAULT_HOST) ? "primary" : host); + + String channelName = serverChannel.removedChannelName; + cli.sendLine("installer channel-remove --channel-name=" + channelName + getHostSuffix(host)); + String output = cli.readOutput(); + assertEquals("Channel '" + channelName + "' has been successfully removed.", output); + } + } + + @Test + public void _d_editChannel() { + for (String host: getHosts()) { + final ServerChannel serverChannel = getServerChannels().get(host.equals(DEFAULT_HOST) ? "primary" : host); + String channelName = serverChannel.editedChannelName; + String manifestGavOrUrl = serverChannel.editedManifestGavOrUrl; + String repoStr = serverChannel.editedRepoStr; + + cli.sendLine( + "installer channel-edit --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr + getHostSuffix(host)); + String output = cli.readOutput(); + Assert.assertEquals("Channel '" + channelName + "' has been modified.", output); + + cli.sendLine("installer channel-list" + getHostSuffix(host)); + output = cli.readOutput(); + + Repository repository = new Repository("id0", repoStr); + Channel newChannel = new Channel(channelName, List.of(repository), manifestGavOrUrl); + String expected = buildChannelOutput(newChannel); + Assert.assertTrue(output, output.contains(expected)); + } + } + + @Test + public void _e_editChannelNotExist() { + String host = getPrimaryHost(); + + String channelName = "unknown"; + String manifestGavOrUrl = "group:artifact:edited-1.0.0.Final"; + String repoStr = "https://edited.com"; + + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer channel-edit --channel-name=" + channelName + " --manifest=" + manifestGavOrUrl + " --repositories=" + repoStr + getHostSuffix(host)); + }); + + String expectedMessage = "Channel '" + channelName + "' is not present."; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage, actualMessage.contains(expectedMessage)); + } + + @Test + public void _f_testHistory() throws IOException { + String host = getSecondaryHost(); + cli.sendLine("installer history" + getHostSuffix(host)); + String output = cli.readOutput(); + + String[] lines = output.split("\n"); + assertEquals(4, lines.length); + + TestInstallationManager.initialize(); + Set expectedValues = TestInstallationManager.history.keySet(); + Set actual = new HashSet<>(Arrays.asList(lines)); + for (String actualStr : actual) { + for (Iterator it = expectedValues.iterator(); it.hasNext();) { + if (actualStr.contains(it.next())) { + it.remove(); + } + } + } + Assert.assertTrue(Arrays.asList(lines).toString(), expectedValues.isEmpty()); + } + + @Test + public void testRevisionDetails() throws Exception { + cli.sendLine("installer history --revision=dummy" + getHostSuffix(getPrimaryHost())); + String output = cli.readOutput(); + + assertTrue(output, output.contains("org.test.groupid1:org.test.artifact1.installed")); + assertTrue(output, output.contains("org.test.groupid1:org.test.artifact1.removed")); + assertTrue(output, output.contains("org.test.groupid1:org.test.artifact1.updated")); + assertTrue(output, output.contains("[Added channel] channel-test-0")); + assertTrue(output, output.contains("[Removed channel] channel-test-0")); + assertTrue(output, output.contains("[Updated channel] channel-test-0")); + } + + @Test + public void testCreateSnapShot() throws IOException { + String host = getPrimaryHost(); + Path exportPath = TARGET_DIR.normalize().toAbsolutePath().resolve("generated.zip"); + try { + final String operationPrefix; + if (host == null || host.equals(DEFAULT_HOST)) { + operationPrefix = ""; + } else { + operationPrefix = "/host=" + host; + } + cli.sendLine("attachment save --operation=" + operationPrefix + "/core-service=installer:clone-export() --file=" + exportPath); + String output = cli.readOutput(); + String expected = "File saved to " + exportPath; + assertEquals(expected, output); + + boolean found = false; + try (ZipInputStream zis = new ZipInputStream(new FileInputStream(exportPath.toFile()))) { + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + String entryName = entry.getName(); + if (entryName.startsWith("installation-manager-test-") && entryName.endsWith(".tmp")) { + found = true; + break; + } + } + } + Assert.assertTrue("Cannot found the expected entry added by the TestInstallationManager.java in the clone export Zip result", found); + } finally { + File expectedExportFile = exportPath.toFile(); + if (expectedExportFile.exists()) { + expectedExportFile.delete(); + } + } + } + + @Test + public void updateWithDryRun() { + String host = getPrimaryHost(); + cli.sendLine("installer update --dry-run" + getHostSuffix(host)); + String output = cli.readOutput(); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + } + + @Test + public void updateWithConfirm() throws IOException { + String host = getPrimaryHost(); + Path primaryPrepareServerDir = getPrimaryPrepareServerDir(); + + cli.sendLine("installer update --repositories=id0::http://localhost --confirm" + getHostSuffix(host)); + String output = cli.readOutput(); + + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + + Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); + Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(primaryPrepareServerDir,p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void updateWithConfirmRepositories() throws IOException { + String host = getPrimaryHost(); + Path primaryPrepareServerDir = getPrimaryPrepareServerDir(); + + cli.sendLine("installer update --confirm --repositories=id0::http://localhost" + getHostSuffix(host)); + String output = cli.readOutput(); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + + Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); + Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void updateWithConfirmLocalCache() throws IOException { + String host = getPrimaryHost(); + Path primaryPrepareServerDir = getPrimaryPrepareServerDir(); + + cli.sendLine("installer update --confirm --local-cache=" + TARGET_DIR + getHostSuffix(host)); + String output = cli.readOutput(); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + + Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); + Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void updateLocalCacheWithUseDefaultLocalCache() { + String host = getPrimaryHost(); + + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer update --local-cache=" + TARGET_DIR + " --use-default-local-cache" + getHostSuffix(host)); + }); + + String expectedMessage = "WFLYIM0021:"; + String actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + + exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer update --local-cache=" + TARGET_DIR + " --use-default-local-cache" + getHostSuffix(host)); + }); + + expectedMessage = "WFLYIM0021:"; + actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + } + + @Test + public void cannotUseConfirmAndDryRunAtTheSameTime() { + String host = getPrimaryHost(); + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer update --confirm --dry-run" + getHostSuffix(host)); + }); + + String expectedMessage = "confirm and dry-run cannot be used at the same time."; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage, actualMessage.contains(expectedMessage)); + } + + @Test + public void updateWithConfirmUsingMavenZipFile() throws Exception { + String host = getPrimaryHost(); + Path target = TARGET_DIR.resolve("installation-manager.zip"); + zipDir(testRepoOnePath.toAbsolutePath(), target); + + cli.sendLine("installer update --confirm --maven-repo-files=" + target + getHostSuffix(host)); + String output = cli.readOutput(); + verifyUpdatePrepareDirWasCreated(host, output); + } + + @Test + public void updateWithConfirmUsingMultipleMavenZipFiles() throws IOException { + String host = getPrimaryHost(); + Path targetOne = TARGET_DIR.resolve("installation-manager-one.zip"); + zipDir(testRepoOnePath.toAbsolutePath(), targetOne); + + Path targetTwo = TARGET_DIR.resolve("installation-manager-two.zip"); + zipDir(testRepoOnePath.toAbsolutePath(), targetTwo); + + cli.sendLine("installer update --confirm --maven-repo-files=" + targetOne + "," + targetTwo + getHostSuffix(host)); + String output = cli.readOutput(); + verifyUpdatePrepareDirWasCreated(host, output); + } + + @Test + public void updateWithDryRunMavenZipFile() throws IOException { + String host = getPrimaryHost(); + Path primaryPrepareServerDir = getPrimaryPrepareServerDir(); + + Path target = TARGET_DIR.resolve("installation-manager.zip"); + zipDir(testRepoOnePath.toAbsolutePath(), target); + + cli.sendLine("installer update --dry-run --maven-repo-files=" + target + getHostSuffix(host)); + String output = cli.readOutput(); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + Assert.assertFalse(output, + output.contains("The candidate server has been generated. To apply it, restart the server with 'shutdown --perform-installation' command.")); + + Assert.assertFalse(Files.exists(primaryPrepareServerDir)); + } + + @Test + public void updateWithDryRunMultipleMavenZipFile() throws IOException { + String host = getPrimaryHost(); + Path primaryPrepareServerDir = getPrimaryPrepareServerDir(); + + Path targetOne = TARGET_DIR.resolve("installation-manager-one.zip"); + zipDir(testRepoOnePath.toAbsolutePath(), targetOne); + + Path targetTwo = TARGET_DIR.resolve("installation-manager-two.zip"); + zipDir(testRepoOnePath.toAbsolutePath(), targetTwo); + + cli.sendLine("installer update --dry-run --maven-repo-files=" + targetOne +","+ targetTwo + getHostSuffix(host)); + String output = cli.readOutput(); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + Assert.assertFalse(output, + output.contains("The candidate server has been generated. To apply it, restart the server with 'shutdown --perform-installation' command.")); + + Assert.assertFalse(Files.exists(primaryPrepareServerDir)); + } + + @Test + public void updateUsingBlockingTimeout() throws IOException { + String host = getSecondaryHost(); + final Path secondaryPrepareServerDir = getPreparedServerDir(host); + + assertTrue(cli.sendLine("installer update --confirm --headers={blocking-timeout=100}" + getHostSuffix(host), false)); + + Assert.assertTrue(Files.exists(secondaryPrepareServerDir) && Files.isDirectory(secondaryPrepareServerDir)); + Assert.assertTrue(secondaryPrepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(secondaryPrepareServerDir, p -> secondaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void updateCannotBeUsedWithMavenRepoFileAndRepositories() throws IOException { + String host = getPrimaryHost(); + + Path target = TARGET_DIR.resolve("installation-manager.zip"); + zipDir(testRepoOnePath.toAbsolutePath(), target); + + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer update --repositories=id0::http://localhost --maven-repo-files=" + target + getHostSuffix(host)); + }); + + String expectedMessage = "WFLYIM0012:"; + String actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + } + + @Test + public void revertWithMavenZipFile() throws IOException { + String host = getPrimaryHost(); + Path primaryPrepareServerDir = getPrimaryPrepareServerDir(); + + Path target = TARGET_DIR.resolve("installation-manager.zip"); + zipDir(testRepoOnePath.toAbsolutePath(), target); + + Assert.assertTrue(cli.sendLine("installer revert --revision=dummy --maven-repo-files=" + target + getHostSuffix(host), false)); + + Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); + Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertWithMultipleMavenZipFiles() throws IOException { + String host = getPrimaryHost(); + Path primaryPrepareServerDir = getPrimaryPrepareServerDir(); + + Path targetOne = TARGET_DIR.resolve("installation-manager-one.zip"); + zipDir(testRepoOnePath.toAbsolutePath(), targetOne); + + Path targetTwo = TARGET_DIR.resolve("installation-manager-two.zip"); + zipDir(testRepoTwoPath.toAbsolutePath(), targetTwo); + + Assert.assertTrue(cli.sendLine("installer revert --revision=dummy --maven-repo-files=" + targetOne + "," + targetTwo + getHostSuffix(host), false)); + + Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); + Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertWithNoResolveLocalMavenCache() throws IOException { + String host = getPrimaryHost(); + Path primaryPrepareServerDir = getPrimaryPrepareServerDir(); + + assertTrue(cli.sendLine("installer revert --revision=dummy --no-resolve-local-cache" + getHostSuffix(host), false)); + + Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); + Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", + Files.list(primaryPrepareServerDir).allMatch(p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertWithUseDefaultLocalCache() throws IOException { + String host = getPrimaryHost(); + Path primaryPrepareServerDir = getPrimaryPrepareServerDir(); + + assertTrue(cli.sendLine("installer revert --revision=dummy --use-default-local-cache" + getHostSuffix(host), false)); + + Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); + Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertWithLocalCacheMavenCache() throws IOException { + String host = getPrimaryHost(); + Path primaryPrepareServerDir = getPrimaryPrepareServerDir(); + + assertTrue(cli.sendLine("installer revert --revision=dummy --local-cache=" + TARGET_DIR + getHostSuffix(host), false)); + + Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); + Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertLocalCacheWithUseDefaultLocalCache() { + String host = getPrimaryHost(); + + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer revert --revision=dummy --local-cache=" + TARGET_DIR + " --use-default-local-cache" + getHostSuffix(host)); + }); + + String expectedMessage = "WFLYIM0021:"; + String actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + + exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer revert --revision=dummy --local-cache=" + TARGET_DIR + " --use-default-local-cache=true" + getHostSuffix(host)); + }); + + expectedMessage = "WFLYIM0021:"; + actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + } + + @Test + public void revertWithOffline() throws IOException { + String host = getPrimaryHost(); + Path primaryPrepareServerDir = getPrimaryPrepareServerDir(); + + assertTrue(cli.sendLine("installer revert --revision=dummy --offline" + getHostSuffix(host), false)); + + Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); + Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertWithHeaders() throws IOException { + String host = getSecondaryHost(); + Path secondaryPrepareServerDir = getPreparedServerDir(host); + + assertTrue(cli.sendLine("installer revert --revision=dummy --headers={blocking-timeout=100}" + getHostSuffix(host), false)); + + Assert.assertTrue(Files.exists(secondaryPrepareServerDir) && Files.isDirectory(secondaryPrepareServerDir)); + Assert.assertTrue(secondaryPrepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(secondaryPrepareServerDir, p -> secondaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertWithRepositories() throws IOException { + String host = getPrimaryHost(); + Path primaryPrepareServerDir = getPrimaryPrepareServerDir(); + + assertTrue(cli.sendLine("installer revert --revision=dummy --repositories=id0::http://localhost" + getHostSuffix(host), false)); + + Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); + Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void simpleRevert() throws IOException { + String host = getPrimaryHost(); + Path primaryPrepareServerDir = getPrimaryPrepareServerDir(); + + assertTrue(cli.sendLine("installer revert --revision=dummy" + getHostSuffix(host), false)); + + Assert.assertTrue(Files.exists(primaryPrepareServerDir) && Files.isDirectory(primaryPrepareServerDir)); + Assert.assertTrue(primaryPrepareServerDir + " does not contain the expected file marker", + directoryOnlyContains(primaryPrepareServerDir, p -> primaryPrepareServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + @Test + public void revertCannotBeUsedWithoutRevision() { + String host = getPrimaryHost(); + + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer revert" + getHostSuffix(host)); + }); + + String expectedMessage = "WFLYCTL0155:"; + String actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + } + + @Test + public void revertCannotBeUsedWithMavenRepoFileAndRepositories() throws IOException { + String host = getPrimaryHost(); + + Path target = TARGET_DIR.resolve("installation-manager.zip"); + zipDir(testRepoOnePath.toAbsolutePath(), target); + + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer revert --revision=dummy --repositories=id0::http://localhost --maven-repo-files=" + target + getHostSuffix(host)); + }); + + String expectedMessage = "WFLYIM0012:"; + String actualMessage = exception.getMessage(); + Assert.assertTrue(getCauseLogFailure(actualMessage, expectedMessage), actualMessage.contains(expectedMessage)); + } + + @Test + public void uploadAndRemoveCustomPatch() throws IOException { + String patchManifestGA = "group:artifact"; + String host = getPrimaryHost(); + Path hostCustomPatchDir = getPrimaryCustomServerDir().resolve(patchManifestGA.replace(":", "_")); + + createAndUploadCustomPatch(patchManifestGA, host, hostCustomPatchDir, testRepoOnePath, "artifact-one"); + removeCustomPatch(patchManifestGA, host, hostCustomPatchDir); + } + + @Test + public void removeNonExistingCustomPatch() { + String host = getPrimaryHost(); + String patchManifestGA = "group-unknown:artifact-unknown"; + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("installer remove-custom-patch --manifest=" + patchManifestGA + getHostSuffix(host)); + }); + String expectedMessage = "WFLYIM0020:"; + String actualMessage = exception.getMessage(); + Assert.assertTrue(actualMessage, actualMessage.contains(expectedMessage)); + + } + + @Test + public void uploadAndRemoveMultipleCustomPatches() throws IOException { + String host = getPrimaryHost(); + Path primaryCustomPatchBaseDir = getPrimaryCustomServerDir(); + + String patchManifestGA_1 = "group1:artifact1"; + Path hostCustomPatchDir_1 = primaryCustomPatchBaseDir.resolve(patchManifestGA_1.replace(":", "_")); + createAndUploadCustomPatch(patchManifestGA_1, host, hostCustomPatchDir_1, testRepoOnePath, "artifact-one"); + + String patchManifestGA_2 = "group2:artifact2"; + Path hostCustomPatchDir_2 = primaryCustomPatchBaseDir.resolve(patchManifestGA_2.replace(":", "_")); + createAndUploadCustomPatch(patchManifestGA_2, host, hostCustomPatchDir_2, testRepoTwoPath, "artifact-two"); + + removeCustomPatch(patchManifestGA_1, host, hostCustomPatchDir_1); + + // check we still have the second patch + final Path customPatchMavenRepo = hostCustomPatchDir_2.resolve(MAVEN_REPO_DIR_NAME_IN_ZIP_FILES); + Assert.assertTrue(Files.exists(customPatchMavenRepo) && Files.isDirectory(customPatchMavenRepo)); + Assert.assertTrue(hostCustomPatchDir_2 + " does not contain the expected maven repository", + directoryOnlyContains(customPatchMavenRepo, p -> customPatchMavenRepo.relativize(p).toString().equals("artifact-two"))); + + // remove the patch 2 + removeCustomPatch(patchManifestGA_2, host, hostCustomPatchDir_2); + } + + @Test + public void cannotShutDownIfNoServerPrepared() { + String host = getPrimaryHost(); + AssertionError exception = assertThrows(AssertionError.class, () -> { + cli.sendLine("shutdown --perform-installation" + getHostSuffix(host)); + }); + String expectedMessage = getNoPreparedServerErrorCode(); + String actualMessage = exception.getMessage(); + Assert.assertTrue(actualMessage, actualMessage.contains(expectedMessage)); + } + + protected abstract String getNoPreparedServerErrorCode(); + + @Test + public void testProductInfoIncludesInstallerInfo() throws Exception { + cli.sendLine(":product-info"); + + ModelNode res = cli.readAllAsOpResult().getResponseNode(); + + final List hostResults = res.get("result").asList(); + for (ModelNode host : hostResults) { + final ModelNode summaryNode = host.get("result"); + final List summaries; + if (summaryNode.getType() == ModelType.LIST) { + summaries = summaryNode.asList(); + } else { + summaries = List.of(summaryNode); + } + for (ModelNode summary : summaries) { + summary = summary.get("summary"); + if (!summary.hasDefined("instance-identifier")) { + continue; + } + + Assert.assertTrue(summary.toString(), summary.hasDefined("last-update-date")); + Assert.assertTrue(summary.hasDefined("channel-versions")); + Assert.assertEquals(List.of(new ModelNode("Update 1")), summary.get("channel-versions").asList()); + } + } + } + + private String getPrimaryHost() { + return getHosts().get(0).trim(); + } + + private String getSecondaryHost() { + if (getHosts().size() == 1) { + return getPrimaryHost(); + } else { + return getHosts().get(1).trim(); + } + } + + private static String getHostSuffix(String host) { + final String hostSuffix; + if (host == null || host.equals(DEFAULT_HOST)) { + hostSuffix = ""; + } else { + hostSuffix = " --host=" + host.trim(); + } + return hostSuffix; + } + + protected List getHosts() { + return new ArrayList<>(getServerDirs().keySet()); + } + + protected Path getPrimaryPrepareServerDir() { + return getPreparedServerDir(getPrimaryHost()); + } + + protected Path getPrimaryCustomServerDir() { + return getServerDirs().get(getPrimaryHost()).customPatch; + } + + private Path getPreparedServerDir(String host) { + Objects.requireNonNull(host); + return getServerDirs().get(host).prepareServer; + } + + /** + * list of paths used in the tests. The key is the host name for Domain testing or DEFAULT_HOST for standalone + * NOTE: the order of keys determines order of operations in some tests + * + * @return + */ + protected abstract LinkedHashMap getServerDirs(); + + protected static void createTestModule() throws IOException { + testModule = new TestModule(MODULE_NAME, "org.wildfly.installation-manager.api"); + + final URL serviceLoader = BaseInstallationManagerTestCase.class.getClassLoader().getResource("org/wildfly/test/installationmanager/services/org.wildfly.installationmanager.spi.InstallationManagerFactory"); + testModule.addResource("test-mock-installation-manager.jar").addClass(TestInstallationManager.class).addClass(TestInstallationManagerFactory.class) + .addAsManifestResource(serviceLoader, + "services/org.wildfly.installationmanager.spi.InstallationManagerFactory"); + testModule.create(true); + } + + protected static String buildChannelOutput(Channel channel) { + final String returnChar = Util.isWindows() ? "\r\n" : "\n"; + + StringBuilder sb = new StringBuilder("-------").append(returnChar).append("# " + channel.getName()).append(returnChar); + + if (channel.getManifestUrl().isPresent()) { + sb.append(" manifest: " + channel.getManifestUrl().get()).append(returnChar); + } else if (channel.getManifestCoordinate().isPresent()) { + sb.append(" manifest: " + channel.getManifestCoordinate().get()).append(returnChar); + } + + sb.append(" repositories:").append(returnChar); + + for (Repository repository : channel.getRepositories()) { + sb.append(" id: " + repository.getId()).append(returnChar).append(" url: " + repository.getUrl()).append(returnChar); + } + + return sb.toString(); + } + + protected void testHostParameter(String suffix, Consumer acceptor) { + final List commands = List.of("update", "clean", "revert", "history", "channel-list", + "channel-add --channel-name test --manifest test --repositories test", "channel-edit --channel-name test --manifest test --repositories test", + "channel-remove --channel-name test", "upload-custom-patch --custom-patch-file=dummy --manifest=manifest"); + + final String trimmedSuffix = (suffix == null || suffix.equals(DEFAULT_HOST)) ? "" : " " + suffix.trim(); + + for (String command : commands) { + AssertionError exception = assertThrows(AssertionError.class, () -> + cli.sendLine("installer " + command + trimmedSuffix) + ); + + acceptor.accept(exception.getMessage()); + } + } + + protected static boolean directoryOnlyContains(Path directory, Predicate match) throws IOException { + try (Stream stream = Files.list(directory)) { + return stream.allMatch(match); + } + } + + protected static String getCauseLogFailure(String description, String expectedLogCode) { + return "Unexpected Error Code. Got " + description + " It was expected: " + expectedLogCode; + } + + protected static void zipDir(Path sourcePath, Path target) throws IOException { + try (FileOutputStream fos = new FileOutputStream(target.toFile()); ZipOutputStream zos = new ZipOutputStream(fos)) { + Files.walkFileTree(sourcePath, new SimpleFileVisitor<>() { + @Override + public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException { + if (!sourcePath.equals(dir)) { + zos.putNextEntry(new ZipEntry(sourcePath.relativize(dir) + "/")); + zos.closeEntry(); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { + zos.putNextEntry(new ZipEntry(sourcePath.relativize(file).toString())); + Files.copy(file, zos); + zos.closeEntry(); + return FileVisitResult.CONTINUE; + } + }); + } + } + + protected void verifyUpdatePrepareDirWasCreated(String host, String output) throws IOException { + final Path expectedPreparedServerDir = getPreparedServerDir(host); + + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.installed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.removed")); + Assert.assertTrue(output, output.contains("org.findupdates:findupdates.updated")); + Assert.assertTrue(output, + output.contains("The candidate server has been generated. To apply it, restart the server with 'shutdown --perform-installation' command.")); + + Assert.assertTrue(Files.exists(expectedPreparedServerDir) && Files.isDirectory(expectedPreparedServerDir)); + Assert.assertTrue(expectedPreparedServerDir + " does not contain the expected file marker", + directoryOnlyContains(expectedPreparedServerDir, p -> expectedPreparedServerDir.relativize(p).toString().startsWith("server-prepare-marker-"))); + } + + protected void createAndUploadCustomPatch(String customPatchManifest, String host, Path hostCustomPatchDir, Path mavenDirToZip, String expectedArtifact) throws IOException { + Path target = TARGET_DIR.resolve("installation-manager.zip"); + zipDir(mavenDirToZip.toAbsolutePath(), target); + + // verify the patch doesn't exist yet + final Path customPatchMavenRepo = hostCustomPatchDir.resolve(MAVEN_REPO_DIR_NAME_IN_ZIP_FILES); + Assert.assertFalse(Files.exists(customPatchMavenRepo)); + + Assert.assertTrue( + cli.sendLine("installer upload-custom-patch --custom-patch-file=" + target + " --manifest=" + customPatchManifest + getHostSuffix(host), false)); + // verify clean operation without arguments don't remove the patch + Assert.assertTrue(cli.sendLine("installer clean" + getHostSuffix(host), false)); + Assert.assertTrue(Files.exists(customPatchMavenRepo) && Files.isDirectory(customPatchMavenRepo)); + Assert.assertTrue(hostCustomPatchDir + " does not contain the expected artifact included in the custom patch Zip file", + directoryOnlyContains(customPatchMavenRepo, p -> customPatchMavenRepo.relativize(p).toString().equals(expectedArtifact))); + } + + protected void removeCustomPatch(String customPatchManifest, String host, Path hostCustomPatchDir) { + // remove the custom patch + final Path primaryCustomPatchMavenRepo = hostCustomPatchDir.resolve(MAVEN_REPO_DIR_NAME_IN_ZIP_FILES); + Assert.assertTrue(cli.sendLine("installer remove-custom-patch --manifest=" + customPatchManifest + getHostSuffix(host), false)); + Assert.assertFalse(Files.exists(primaryCustomPatchMavenRepo)); + } + + protected static void copyRepository(String name, Path target) throws URISyntaxException, IOException { + final URL repoUrl = BaseInstallationManagerTestCase.class.getClassLoader().getResource("org/wildfly/test/installationmanager/" + name); + + System.out.println(repoUrl); + if ("jar".equals(repoUrl.getProtocol())) { + String repoPath = repoUrl.getFile().split("\\!")[1]; + + copyFromJar(repoUrl.toURI(), repoPath, target.resolve(name)); + }else { + FileUtils.copyDirectory(Path.of(repoUrl.toURI()).toFile(), target.resolve(name).toFile()); + } + } + + protected static void copyFromJar(URI jar, String source, final Path target) throws URISyntaxException, IOException { + System.out.println(jar); + try (FileSystem fileSystem = FileSystems.newFileSystem( + jar, + Collections.emptyMap() + )) { + + + final Path jarPath = fileSystem.getPath(source); + + Files.walkFileTree(jarPath, new SimpleFileVisitor() { + + private Path currentTarget; + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + currentTarget = target.resolve(jarPath.relativize(dir).toString()); + Files.createDirectories(currentTarget); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.copy(file, target.resolve(jarPath.relativize(file).toString()), StandardCopyOption.REPLACE_EXISTING); + return FileVisitResult.CONTINUE; + } + + }); + } + } + + protected static class ServerPaths { + protected final Path prepareServer; + protected final Path customPatch; + + public ServerPaths(Path prepareServer, Path customPatch) { + this.prepareServer = prepareServer; + this.customPatch = customPatch; + } + } + + protected Map getServerChannels() { + final HashMap channels = new HashMap<>(); + channels.put("primary", new ServerChannel( + "test-primary", "group:artifact:primary-1.0.0.Final", "https://primary.com", "channel-test-1", + "channel-test-2", "group:artifact:edited-1.0.0.Final", "https://edited.com" + )); + channels.put("secondary", new ServerChannel( + "test-secondary", "/test", "https://secondary.com", "channel-test-2", + "channel-test-1", "group:artifact:edited-1.0.0.Final", "https://edited.com" + )); + + return channels; + } + + protected static class ServerChannel { + final String channelName; + final String manifestGavOrUrl; + final String repoStr; + final String removedChannelName; + final String editedChannelName; + final String editedManifestGavOrUrl; + final String editedRepoStr; + + public ServerChannel(String channelName, String manifestGavOrUrl, String repoStr, String removedChannelName, + String editedChannelName, String editedManifestGavOrUrl, String editedRepoStr) { + this.channelName = channelName; + this.manifestGavOrUrl = manifestGavOrUrl; + this.repoStr = repoStr; + this.removedChannelName = removedChannelName; + this.editedChannelName = editedChannelName; + this.editedManifestGavOrUrl = editedManifestGavOrUrl; + this.editedRepoStr = editedRepoStr; + } + } +} diff --git a/testsuite/domain/src/test/resources/META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory b/testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/services/org.wildfly.installationmanager.spi.InstallationManagerFactory similarity index 100% rename from testsuite/domain/src/test/resources/META-INF/services/org.wildfly.installationmanager.spi.InstallationManagerFactory rename to testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/services/org.wildfly.installationmanager.spi.InstallationManagerFactory diff --git a/testsuite/domain/src/test/resources/org/jboss/as/test/integration/domain/installationmanager/test-repo-one/dummy_file_one.txt b/testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/test-repo-one/dummy_file_one.txt similarity index 100% rename from testsuite/domain/src/test/resources/org/jboss/as/test/integration/domain/installationmanager/test-repo-one/dummy_file_one.txt rename to testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/test-repo-one/dummy_file_one.txt diff --git a/testsuite/domain/src/test/resources/org/jboss/as/test/integration/domain/installationmanager/test-repo-one/maven-repository/artifact-one b/testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/test-repo-one/maven-repository/artifact-one similarity index 100% rename from testsuite/domain/src/test/resources/org/jboss/as/test/integration/domain/installationmanager/test-repo-one/maven-repository/artifact-one rename to testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/test-repo-one/maven-repository/artifact-one diff --git a/testsuite/domain/src/test/resources/org/jboss/as/test/integration/domain/installationmanager/test-repo-one/other-directory-one/dummy_file_one.txt b/testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/test-repo-one/other-directory-one/dummy_file_one.txt similarity index 100% rename from testsuite/domain/src/test/resources/org/jboss/as/test/integration/domain/installationmanager/test-repo-one/other-directory-one/dummy_file_one.txt rename to testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/test-repo-one/other-directory-one/dummy_file_one.txt diff --git a/testsuite/domain/src/test/resources/org/jboss/as/test/integration/domain/installationmanager/test-repo-two/dummy_file_two.txt b/testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/test-repo-two/dummy_file_two.txt similarity index 100% rename from testsuite/domain/src/test/resources/org/jboss/as/test/integration/domain/installationmanager/test-repo-two/dummy_file_two.txt rename to testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/test-repo-two/dummy_file_two.txt diff --git a/testsuite/domain/src/test/resources/org/jboss/as/test/integration/domain/installationmanager/test-repo-two/maven-repository/artifact-two b/testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/test-repo-two/maven-repository/artifact-two similarity index 100% rename from testsuite/domain/src/test/resources/org/jboss/as/test/integration/domain/installationmanager/test-repo-two/maven-repository/artifact-two rename to testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/test-repo-two/maven-repository/artifact-two diff --git a/testsuite/domain/src/test/resources/org/jboss/as/test/integration/domain/installationmanager/test-repo-two/other-directory-two/dummy_file_two.txt b/testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/test-repo-two/other-directory-two/dummy_file_two.txt similarity index 100% rename from testsuite/domain/src/test/resources/org/jboss/as/test/integration/domain/installationmanager/test-repo-two/other-directory-two/dummy_file_two.txt rename to testsuite/shared/src/main/resources/org/wildfly/test/installationmanager/test-repo-two/other-directory-two/dummy_file_two.txt