From 64471e9e3f2df36a21d9bcb24a1b9406cae22bbd Mon Sep 17 00:00:00 2001 From: az Date: Sun, 26 Mar 2023 19:30:28 +0200 Subject: [PATCH 01/18] [skip ci] remove redundant tag --- .../provs/desktop/infrastructure/FirefoxKtTest.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/FirefoxKtTest.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/FirefoxKtTest.kt index 4652113..3cf7acf 100644 --- a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/FirefoxKtTest.kt +++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/FirefoxKtTest.kt @@ -4,11 +4,9 @@ import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.isPackag import org.domaindrivenarchitecture.provs.test.defaultTestContainer import org.domaindrivenarchitecture.provs.test.tags.ExtensiveContainerTest import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.Test internal class FirefoxKtTest { - @Test @ExtensiveContainerTest fun installFirefox() { // when From 0d66421506a7a21e0d2d00edf2ee8cb34365e68c Mon Sep 17 00:00:00 2001 From: az Date: Sun, 26 Mar 2023 19:32:31 +0200 Subject: [PATCH 02/18] [skip ci] recreate defaultTestContainer if not running --- .../org/domaindrivenarchitecture/provs/test/TestSetup.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/testFixtures/kotlin/org/domaindrivenarchitecture/provs/test/TestSetup.kt b/src/testFixtures/kotlin/org/domaindrivenarchitecture/provs/test/TestSetup.kt index 046cfd9..e7427b8 100644 --- a/src/testFixtures/kotlin/org/domaindrivenarchitecture/provs/test/TestSetup.kt +++ b/src/testFixtures/kotlin/org/domaindrivenarchitecture/provs/test/TestSetup.kt @@ -2,6 +2,7 @@ package org.domaindrivenarchitecture.provs.test import org.domaindrivenarchitecture.provs.framework.core.ProgressType import org.domaindrivenarchitecture.provs.framework.core.Prov +import org.domaindrivenarchitecture.provs.framework.core.docker.containerRuns import org.domaindrivenarchitecture.provs.framework.core.docker.dockerImageExists import org.domaindrivenarchitecture.provs.framework.core.docker.dockerProvideImage import org.domaindrivenarchitecture.provs.framework.core.docker.dockerimages.UbuntuPlusUser @@ -15,7 +16,7 @@ const val defaultTestContainerName = "provs_test" private lateinit var prov: Prov fun defaultTestContainer(startMode: ContainerStartMode = ContainerStartMode.USE_RUNNING_ELSE_CREATE): Prov { - if (!::prov.isInitialized) { prov = initDefaultTestContainer(startMode) } + if (!::prov.isInitialized || !testLocal().containerRuns(defaultTestContainerName)) { prov = initDefaultTestContainer(startMode) } return prov } From e35caca49a22c0f2507d794bee0e3cddd3601ea0 Mon Sep 17 00:00:00 2001 From: az Date: Sun, 26 Mar 2023 19:49:16 +0200 Subject: [PATCH 03/18] [skip ci] disable very long running tests for desktop setup and remove 1 test --- .../desktop/domain/DesktopServiceKtTest.kt | 24 +------------------ .../resources/desktop-config-example.json | 6 ----- 2 files changed, 1 insertion(+), 29 deletions(-) delete mode 100644 src/test/resources/desktop-config-example.json diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/domain/DesktopServiceKtTest.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/domain/DesktopServiceKtTest.kt index 4924fd2..5e7878f 100644 --- a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/domain/DesktopServiceKtTest.kt +++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/domain/DesktopServiceKtTest.kt @@ -1,6 +1,5 @@ package org.domaindrivenarchitecture.provs.desktop.domain -import org.domaindrivenarchitecture.provs.desktop.infrastructure.getConfig import org.domaindrivenarchitecture.provs.framework.core.ProgressType import org.domaindrivenarchitecture.provs.framework.core.Prov import org.domaindrivenarchitecture.provs.framework.core.docker.provideContainer @@ -46,6 +45,7 @@ internal class DesktopServiceKtTest { } @ExtensiveContainerTest + @Disabled("Takes very long, enable if you want to test a desktop setup") fun provisionDesktop() { // given val prov = defaultTestContainer() @@ -87,28 +87,6 @@ internal class DesktopServiceKtTest { // then assertTrue(res.success) } - - - @ExtensiveContainerTest - fun provisionDesktopFromConfigFile() { - // given - val prov = defaultTestContainer() - - // when - // in order to test DesktopType.OFFICE: fix installing libreoffice for a fresh container as it hangs the first time but succeeds 2nd time - val config = getConfig("src/test/resources/desktop-config-example.json") - val res = prov.provisionDesktop( - DesktopType.BASIC, - config.ssh?.keyPair(), - config.gpg?.keyPair(), - config.gitUserName, - config.gitEmail, - onlyModules = null - ) - - // then - assertTrue(res.success) - } } diff --git a/src/test/resources/desktop-config-example.json b/src/test/resources/desktop-config-example.json deleted file mode 100644 index 1ac697b..0000000 --- a/src/test/resources/desktop-config-example.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "ssh": null, - "gpg": null, - "gitUserName": "mygitusername", - "gitEmail": "my@git.email" -} \ No newline at end of file From 587e978d6366df88c42e3c5e2e605da90ac12486 Mon Sep 17 00:00:00 2001 From: az Date: Sun, 26 Mar 2023 21:56:59 +0200 Subject: [PATCH 04/18] [skip ci] fix test_configureSsh --- .../provs/server/infrastructure/SshKtTest.kt | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/server/infrastructure/SshKtTest.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/server/infrastructure/SshKtTest.kt index 4863ae6..63ec68d 100644 --- a/src/test/kotlin/org/domaindrivenarchitecture/provs/server/infrastructure/SshKtTest.kt +++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/server/infrastructure/SshKtTest.kt @@ -1,7 +1,9 @@ package org.domaindrivenarchitecture.provs.server.infrastructure import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.checkFile +import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.deleteFile import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.fileContainsText +import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall import org.domaindrivenarchitecture.provs.test.defaultTestContainer import org.domaindrivenarchitecture.provs.test.tags.ExtensiveContainerTest import org.junit.jupiter.api.Assertions.assertTrue @@ -12,15 +14,21 @@ class SshKtTest { fun test_configureSsh() { // given - val p = defaultTestContainer() + val prov = defaultTestContainer() + prov.task { + aptInstall("openssh-server") + deleteFile(pathSshdHardeningConfig, sudo = true) + } // when - val res = p.configureSsh() + prov.configureSsh() // then - assertTrue(res.success) - assertTrue(p.fileContainsText("/etc/ssh/ssh_config","PasswordAuthentication no", sudo=true)) - assertTrue(p.fileContainsText("/etc/ssh/sshd_config","PasswordAuthentication no", sudo=true)) - assertTrue(p.checkFile("/etc/ssh/sshd_config.d/sshd_hardening.conf")) + + // Note: result of method configureSsh might have status failure as restart ssh within docker is not possible, + // but files should have expected content + assertTrue(prov.fileContainsText("/etc/ssh/ssh_config","PasswordAuthentication no", sudo=true)) + assertTrue(prov.fileContainsText("/etc/ssh/sshd_config","PasswordAuthentication no", sudo=true)) + assertTrue(prov.checkFile("/etc/ssh/sshd_config.d/sshd_hardening.conf")) } } \ No newline at end of file From 44deb79865cff3918a36fbc034bdf9347dff102e Mon Sep 17 00:00:00 2001 From: az Date: Fri, 31 Mar 2023 20:30:54 +0200 Subject: [PATCH 05/18] [skip ci] update rsa fingerprint github --- .../provs/framework/ubuntu/git/base/Git.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/git/base/Git.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/git/base/Git.kt index 9209be4..ddc04f7 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/git/base/Git.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/git/base/Git.kt @@ -45,10 +45,9 @@ fun Prov.gitClone( fun Prov.trustGithub() = task { // current fingerprints from https://docs.github.com/en/github/authenticating-to-github/githubs-ssh-key-fingerprints val fingerprints = setOf( - "SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8 github.com", // (RSA) - // supported beginning September 14, 2021: + "SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s github.com", // (RSA) "SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM github.com", // (ECDSA) - "SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU github.com" // (Ed25519) + "SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU github.com" // (Ed25519) ) trustHost("github.com", fingerprints) } From 075fe6cae1f84453d33412c30c9995641a3722cb Mon Sep 17 00:00:00 2001 From: az Date: Fri, 31 Mar 2023 20:31:18 +0200 Subject: [PATCH 06/18] pinning version of kubectl --- .../provs/desktop/infrastructure/DevOps.kt | 55 ++++++++++++------- .../desktop/infrastructure/DevOpsKtTest.kt | 14 +++++ 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/DevOps.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/DevOps.kt index 556fb57..5414ea0 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/DevOps.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/DevOps.kt @@ -7,7 +7,9 @@ import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInsta import org.domaindrivenarchitecture.provs.framework.ubuntu.web.base.downloadFromURL -private const val resourcePath = "org/domaindrivenarchitecture/provs/desktop/infrastructure" +private const val RESOURCE_PATH = "org/domaindrivenarchitecture/provs/desktop/infrastructure" +private const val KUBE_CONFIG_CONTEXT_SCRIPT = ".bashrc.d/kubectl.sh" + fun Prov.installDevOps() = task { installTerraform() @@ -41,20 +43,9 @@ fun Prov.installYq( fun Prov.installKubectlAndTools(): ProvResult = task { task("installKubectl") { - val kubeConfigFile = ".bashrc.d/kubectl.sh" - if (!checkFile(kubeConfigFile)) { - // prerequisites -- see https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/ - cmd("sudo apt-get update") - aptInstall("apt-transport-https ca-certificates curl") - cmd("sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg") - cmd("echo \"deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main\" | sudo tee /etc/apt/sources.list.d/kubernetes.list") - - // kubectl and bash completion - cmd("sudo apt update") - aptInstall("kubectl") - cmd("kubectl completion bash >> /etc/bash_completion.d/kubernetes", sudo = true) - createDir(".bashrc.d") - createFileFromResource(kubeConfigFile, "kubectl.sh", resourcePath) + if (!checkFile(KUBE_CONFIG_CONTEXT_SCRIPT)) { + installKubectl() + configureKubectlBashCompletion() } else { ProvResult(true, out = "Kubectl already installed") } @@ -63,20 +54,45 @@ fun Prov.installKubectlAndTools(): ProvResult = task { installDevopsScripts() } +fun Prov.installKubectl(): ProvResult = task { + + // see https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/ + val kubectlVersion = "1.23.0" + val tmpDir = "~/tmp" + + // prerequisites -- see https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/ + cmd("sudo apt-get update") + aptInstall("apt-transport-https ca-certificates curl") + createDir(tmpDir) + downloadFromURL( + "https://dl.k8s.io/release/v$kubectlVersion/bin/linux/amd64/kubectl", + path = tmpDir, + // from https://dl.k8s.io/v1.23.0/bin/linux/amd64/kubectl.sha256 + sha256sum = "2d0f5ba6faa787878b642c151ccb2c3390ce4c1e6c8e2b59568b3869ba407c4f" + ) + cmd("sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl", dir = tmpDir) +} + +fun Prov.configureKubectlBashCompletion(): ProvResult = task { + cmd("kubectl completion bash >> /etc/bash_completion.d/kubernetes", sudo = true) + createDir(".bashrc.d") + createFileFromResource(KUBE_CONFIG_CONTEXT_SCRIPT, "kubectl.sh", RESOURCE_PATH) +} + fun Prov.installDevopsScripts() { task("install ssh helper") { createFileFromResource( "/usr/local/bin/sshu.sh", "sshu.sh", - resourcePath, + RESOURCE_PATH, "555", sudo = true ) createFileFromResource( "/usr/local/bin/ssht.sh", "ssht.sh", - resourcePath, + RESOURCE_PATH, "555", sudo = true ) @@ -87,7 +103,7 @@ fun Prov.installDevopsScripts() { createFileFromResource( k3sContextFile, "k3s-create-context.sh", - resourcePath, + RESOURCE_PATH, "555", sudo = true ) @@ -98,12 +114,13 @@ fun Prov.installDevopsScripts() { createFileFromResource( k3sConnectFile, "k3s-connect.sh", - resourcePath, + RESOURCE_PATH, "555", sudo = true ) } } + fun Prov.installTerraform(): ProvResult = task { val dir = "/usr/lib/tfenv/" diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/DevOpsKtTest.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/DevOpsKtTest.kt index a42c39a..12ffb16 100644 --- a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/DevOpsKtTest.kt +++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/DevOpsKtTest.kt @@ -8,6 +8,7 @@ import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.fileC import org.domaindrivenarchitecture.provs.test.defaultTestContainer import org.domaindrivenarchitecture.provs.test.tags.ExtensiveContainerTest import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Disabled internal class DevOpsKtTest { @@ -34,4 +35,17 @@ internal class DevOpsKtTest { defaultTestContainer().checkFile("/etc/bash_completion.d/kubernetes", sudo = true) ) } + + @ExtensiveContainerTest + @Disabled("Part of test installKubectlAndTools, but can be tested separately by this test if required") + fun installKubectl() { + // given + val prov = defaultTestContainer() + + // when + val res = prov.installKubectl() + + // then + assertTrue(res.success) + } } From c9a7eb41427ee0bdfb73367673c38f645f606f65 Mon Sep 17 00:00:00 2001 From: az Date: Sat, 1 Apr 2023 11:56:36 +0200 Subject: [PATCH 07/18] add failure result to output if not yet included --- .../provs/framework/core/Prov.kt | 8 +++++ .../provs/framework/core/ProvTest.kt | 33 ++++++++++++++----- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt index 87a88c8..b45b6c3 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt @@ -312,6 +312,14 @@ open class Prov protected constructor( internalResults[resultIndex].provResult = returnValue + // Add failure result to output if not yet included, + // which is the case if the result was not part of another subtask but created and returned by the lambda itself. + // Success results do not need to be added here as they don't change the overall success evaluation, + // whereas the failure results may have a useful error message, which should be in the output. + if (!resultOfTaskLambda.success && (resultOfTaskLambda != internalResults.last().provResult)) { + internalResults.add(ResultLine(level + 1, "<>", resultOfTaskLambda)) + } + if (level == 0) { endProgress() processor.close() diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/framework/core/ProvTest.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/framework/core/ProvTest.kt index 220acc1..d78ed51 100644 --- a/src/test/kotlin/org/domaindrivenarchitecture/provs/framework/core/ProvTest.kt +++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/framework/core/ProvTest.kt @@ -254,12 +254,12 @@ internal class ProvTest { } - // given + // additional methods to be used in the tests below fun Prov.checkPrereq_evaluateToFailure() = requireLast { ProvResult(false, err = "This is a test error.") } - fun Prov.methodThatProvidesSomeOutput() = requireLast { + fun Prov.testMethodForOutputTest_with_mode_requireLast() = requireLast { if (!checkPrereq_evaluateToFailure().success) { sh( @@ -273,6 +273,17 @@ internal class ProvTest { sh("echo -End test-") } + fun Prov.testMethodForOutputTest_nested_with_failure() = taskWithResult { + + taskWithResult(name = "sub1") { + taskWithResult { + ProvResult(true) + } + ProvResult(false, err = "Iamanerrormessage") + } + cmd("echo -End test-") + } + @Test @NonCi fun prov_prints_correct_output_for_overall_success() { @@ -290,7 +301,7 @@ internal class ProvTest { // when Prov.newInstance(name = "test instance with no progress info", progressType = ProgressType.NONE) - .methodThatProvidesSomeOutput() + .testMethodForOutputTest_with_mode_requireLast() // then System.setOut(originalOut) @@ -300,7 +311,7 @@ internal class ProvTest { val expectedOutput = "============================================== SUMMARY (test instance with no progress info) =============================================\n" + - "> \u001B[92mSuccess\u001B[0m -- methodThatProvidesSomeOutput (requireLast) \n" + + "> \u001B[92mSuccess\u001B[0m -- testMethodForOutputTest_with_mode_requireLast (requireLast) \n" + "---> \u001B[93mFAILED\u001B[0m -- checkPrereq_evaluateToFailure (requireLast) -- Error: This is a test error.\n" + "---> \u001B[92mSuccess\u001B[0m -- sh \n" + "------> \u001B[92mSuccess\u001B[0m -- cmd [/bin/bash, -c, echo -Start test-]\n" + @@ -317,7 +328,7 @@ internal class ProvTest { @Test @NonCi - fun prov_prints_correct_output_for_failure() { + fun prov_prints_correct_output_for_nested_calls_with_failure() { // given setRootLoggingLevel(Level.OFF) @@ -332,7 +343,7 @@ internal class ProvTest { // when Prov.newInstance(name = "test instance with no progress info", progressType = ProgressType.NONE) - .checkPrereq_evaluateToFailure() + .testMethodForOutputTest_nested_with_failure() // then System.setOut(originalOut) @@ -342,7 +353,13 @@ internal class ProvTest { val expectedOutput = "============================================== SUMMARY (test instance with no progress info) =============================================\n" + - "> \u001B[91mFAILED\u001B[0m -- checkPrereq_evaluateToFailure (requireLast) -- Error: This is a test error.\n" + + "> \u001B[91mFAILED\u001B[0m -- testMethodForOutputTest_nested_with_failure \n" + + "---> \u001B[91mFAILED\u001B[0m -- sub1 \n" + + "------> \u001B[92mSuccess\u001B[0m -- testMethodForOutputTest_nested_with_failure \n" + + "------> \u001B[91mFAILED\u001B[0m -- <> -- Error: Iamanerrormessage\n" + + "---> \u001B[92mSuccess\u001B[0m -- cmd [/bin/bash, -c, echo -End test-]\n" + + "----------------------------------------------------------------------------------------------------\n" + + "Overall > \u001B[91mFAILED\u001B[0m \n" + "============================================ SUMMARY END ===========================================\n" + "\n" @@ -603,7 +620,7 @@ internal class ProvTest { val prov = Prov.newInstance(name = "test instance with no progress info", progressType = ProgressType.NONE) - // when + // when prov.task { addInfoText("Text1") addInfoText("Text2\nwith newline") From 2667a7c64f835296e21796e2a4c19d7b3db8a56d Mon Sep 17 00:00:00 2001 From: az Date: Sun, 2 Apr 2023 09:59:51 +0200 Subject: [PATCH 08/18] [skip ci] add meld to office desktop --- .../provs/desktop/domain/DesktopService.kt | 4 ++-- .../provs/desktop/infrastructure/PackageBundles.kt | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/domain/DesktopService.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/domain/DesktopService.kt index ef7aded..9a03b87 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/domain/DesktopService.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/domain/DesktopService.kt @@ -106,19 +106,19 @@ fun Prov.provisionMSDesktop(onlyModules: List?) { fun Prov.provisionOfficeDesktop(onlyModules: List? = null) { if (onlyModules == null) { aptInstall(ZIP_UTILS) + aptInstall(SPELLCHECKING_DE) aptInstall(BROWSER) aptInstall(EMAIL_CLIENT) installDeltaChat() aptInstall(OFFICE_SUITE) installZimWiki() installNextcloudClient() + aptInstall(COMPARE_TOOLS) // optional as installation of these tools often fail and they are not considered mandatory optional { aptInstall(DRAWING_TOOLS) } - - aptInstall(SPELLCHECKING_DE) } else if (onlyModules.contains(DesktopOnlyModule.VERIFY.name.lowercase())) { verifyOfficeSetup() } else if (onlyModules.contains(DesktopOnlyModule.FIREFOX.name.lowercase())) { diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/PackageBundles.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/PackageBundles.kt index ae890f9..f3c7faa 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/PackageBundles.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/PackageBundles.kt @@ -38,4 +38,6 @@ val CLOJURE_TOOLS = "leiningen" val PASSWORD_TOOLS = "pwgen" -val SCREEN_TOOLS = "scrcpy" \ No newline at end of file +val SCREEN_TOOLS = "scrcpy" + +val COMPARE_TOOLS = "meld" \ No newline at end of file From 29e0af0c8579f1bc0d0c58520c129ffe97303e0e Mon Sep 17 00:00:00 2001 From: az Date: Sun, 2 Apr 2023 10:00:52 +0200 Subject: [PATCH 09/18] release-0.18.2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 15d3eda..d703390 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ apply plugin: "kotlinx-serialization" group = "org.domaindrivenarchitecture.provs" -version = "0.18.2-SNAPSHOT" +version = "release-0.18.2" repositories { mavenCentral() From 727b9505255546a89f2ffd825dd502329b8ec265 Mon Sep 17 00:00:00 2001 From: az Date: Sun, 2 Apr 2023 10:04:31 +0200 Subject: [PATCH 10/18] [skip ci] 0.18.3-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d703390..e81ff17 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ apply plugin: "kotlinx-serialization" group = "org.domaindrivenarchitecture.provs" -version = "release-0.18.2" +version = "0.18.3-SNAPSHOT" repositories { mavenCentral() From b00783dd733eb86122f95c5b972a1bc6a0ae5613 Mon Sep 17 00:00:00 2001 From: az Date: Sun, 2 Apr 2023 10:05:32 +0200 Subject: [PATCH 11/18] [skip ci] add newline before eof --- .../provs/desktop/infrastructure/PackageBundles.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/PackageBundles.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/PackageBundles.kt index f3c7faa..8264d21 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/PackageBundles.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/PackageBundles.kt @@ -40,4 +40,4 @@ val PASSWORD_TOOLS = "pwgen" val SCREEN_TOOLS = "scrcpy" -val COMPARE_TOOLS = "meld" \ No newline at end of file +val COMPARE_TOOLS = "meld" From 3aeeacfebf8cb0ce3e5e05f908faeb9fa5f5ab09 Mon Sep 17 00:00:00 2001 From: az Date: Mon, 3 Apr 2023 17:39:00 +0200 Subject: [PATCH 12/18] [skip ci] add tests test_verifySpecConfig_fails & test_verifySpecConfig_succeeds --- .../infrastructure/VerificationKtTest.kt | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/syspec/infrastructure/VerificationKtTest.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/syspec/infrastructure/VerificationKtTest.kt index e1a7dec..ada979e 100644 --- a/src/test/kotlin/org/domaindrivenarchitecture/provs/syspec/infrastructure/VerificationKtTest.kt +++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/syspec/infrastructure/VerificationKtTest.kt @@ -3,10 +3,7 @@ package org.domaindrivenarchitecture.provs.syspec.infrastructure import org.domaindrivenarchitecture.provs.framework.core.ProvResult import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createDirs import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createFile -import org.domaindrivenarchitecture.provs.syspec.domain.FileSpec -import org.domaindrivenarchitecture.provs.syspec.domain.FolderSpec -import org.domaindrivenarchitecture.provs.syspec.domain.SocketSpec -import org.domaindrivenarchitecture.provs.syspec.domain.SyspecConfig +import org.domaindrivenarchitecture.provs.syspec.domain.* import org.domaindrivenarchitecture.provs.test.defaultTestContainer import org.domaindrivenarchitecture.provs.test.tags.ContainerTest import org.domaindrivenarchitecture.provs.test.testLocal @@ -131,4 +128,30 @@ internal class VerificationKtTest { assertFalse(res3) } + @ContainerTest + fun test_verifySpecConfig_succeeds() { + // given + val dir = "/home/testuser" + val prov = defaultTestContainer() + + // when + val res = prov.verifySpecConfig(SyspecConfig(folder = listOf(FolderSpec(dir)), command = listOf(CommandSpec("echo bla")))) + + // then + assertTrue(res.success) + } + + @ContainerTest + fun test_verifySpecConfig_fails() { + // given + val dir = "/home/testuser" + val prov = defaultTestContainer() + + // when + val res = prov.verifySpecConfig(SyspecConfig(command = listOf(CommandSpec("echoo bla"), CommandSpec("echo bla")), folder = listOf(FolderSpec(dir)))) + + // then + assertFalse(res.success) + } + } \ No newline at end of file From 29b8a99655a06bbd3d2e7b75c3ee7115cdd24878 Mon Sep 17 00:00:00 2001 From: az Date: Wed, 5 Apr 2023 18:49:08 +0200 Subject: [PATCH 13/18] [skip ci] remove unnecessary output line in case of <> --- .../provs/framework/core/Prov.kt | 16 ++-- .../provs/framework/core/Utils.kt | 4 +- .../provs/framework/core/ProvTest.kt | 79 +++++++++++++++++++ 3 files changed, 91 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt index b45b6c3..608c462 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt @@ -87,15 +87,15 @@ open class Prov protected constructor( /** * defines a task, which returns the returned result, the results of sub-tasks are not considered */ - fun requireLast(a: Prov.() -> ProvResult): ProvResult { - return evaluate(ResultMode.LAST) { a() } + fun requireLast(name: String? = null, a: Prov.() -> ProvResult): ProvResult { + return evaluate(ResultMode.LAST, name) { a() } } /** * defines a task, which always returns success */ - fun optional(a: Prov.() -> ProvResult): ProvResult { - return evaluate(ResultMode.OPTIONAL) { a() } + fun optional(name: String? = null, a: Prov.() -> ProvResult): ProvResult { + return evaluate(ResultMode.OPTIONAL, name) { a() } } /** @@ -316,7 +316,7 @@ open class Prov protected constructor( // which is the case if the result was not part of another subtask but created and returned by the lambda itself. // Success results do not need to be added here as they don't change the overall success evaluation, // whereas the failure results may have a useful error message, which should be in the output. - if (!resultOfTaskLambda.success && (resultOfTaskLambda != internalResults.last().provResult)) { + if (!resultOfTaskLambda.success && (resultIndex < internalResults.size - 1) && (resultOfTaskLambda != internalResults[resultIndex + 1].provResult)) { internalResults.add(ResultLine(level + 1, "<>", resultOfTaskLambda)) } @@ -330,8 +330,12 @@ open class Prov protected constructor( } + /** + * Returns true if the task at the specified index has no subtasks. + * I.e. if the task is the last one or if level of the next task is the same or less (which means same level or "higher" in the tree) + */ private fun internalResultIsLeaf(resultIndex: Int): Boolean { - return !(resultIndex < internalResults.size - 1 && internalResults[resultIndex + 1].level > internalResults[resultIndex].level) + return (resultIndex >= internalResults.size - 1 || internalResults[resultIndex].level >= internalResults[resultIndex + 1].level) } diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Utils.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Utils.kt index 0087aa5..98fa90a 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Utils.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Utils.kt @@ -20,7 +20,7 @@ internal fun getCallingMethodName(): String? { val offsetVal = 1 val exclude = arrayOf("task", "task\$default", "taskWithResult\$default", "taskWithResult", "def", "def\$default", "record", "invoke", "invoke0", "evaluate", "evaluate\$default", ) // suffixes are also ignored as method names but will be added as suffix in the evaluation results - val suffixes = arrayOf("optional", "requireAll", "requireLast", "inContainer") + val suffixes = arrayOf("optional", "optional\$default", "requireAll", "requireLast", "requireLast\$default", "inContainer") var suffix = "" val callingFrame = Thread.currentThread().stackTrace @@ -30,7 +30,7 @@ internal fun getCallingMethodName(): String? { var inc = 0 while ((method in exclude) or (method in suffixes)) { if (method in suffixes && suffix == "") { - suffix = method + suffix = method.split("$")[0] } inc++ method = callingFrame[i + offsetVal + inc].methodName diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/framework/core/ProvTest.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/framework/core/ProvTest.kt index d78ed51..cd469d1 100644 --- a/src/test/kotlin/org/domaindrivenarchitecture/provs/framework/core/ProvTest.kt +++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/framework/core/ProvTest.kt @@ -646,5 +646,84 @@ internal class ProvTest { } + // method to be used in the next test + fun Prov.testMethodForOutputTest_with_returned_results() = taskWithResult { + + taskWithResult(name = "sub1") { + taskWithResult("sub2a") { + ProvResult(true) + } + taskWithResult("sub2b") { + ProvResult(false, err = "error msg A for sub2b should be shown as result of sub2b") + } + optional("sub2c-optional") { + taskWithResult("sub3a-taskWithResult") { + addResultToEval(ProvResult(false, err = "returned-result - error msg B should be once in output - in addResultToEval")) + } + } + requireLast("sub2d-requireLast") { + taskWithResult("sub3b-taskWithResult without error message") { + ProvResult(false) // no error message + } + } + task("sub2e-task") { + addResultToEval(ProvResult(true)) + ProvResult(false, err = "error should NOT be in output as results of task (not taskWithResult) are ignored") + } + taskWithResult("sub2f-taskWithResult") { + ProvResult(false, err = "returned-result - error msg C should be once in output - at the end of sub3taskWithResult ") + } + ProvResult(false, err = "returned-result - error msg D should be once in output - at the end of sub1 ") + } + } + + @Test + @NonCi + fun prov_prints_correct_output_for_returned_results() { + + // given + setRootLoggingLevel(Level.OFF) + + val outContent = ByteArrayOutputStream() + val errContent = ByteArrayOutputStream() + val originalOut = System.out + val originalErr = System.err + + System.setOut(PrintStream(outContent)) + System.setErr(PrintStream(errContent)) + + // when + Prov.newInstance(name = "test instance with no progress info", progressType = ProgressType.NONE) + .testMethodForOutputTest_with_returned_results() + + // then + System.setOut(originalOut) + System.setErr(originalErr) + + println(outContent.toString()) + + val expectedOutput = + "============================================== SUMMARY (test instance with no progress info) =============================================\n" + + "> \u001B[91mFAILED\u001B[0m -- testMethodForOutputTest_with_returned_results \n" + + "---> \u001B[91mFAILED\u001B[0m -- sub1 \n" + + "------> \u001B[92mSuccess\u001B[0m -- sub2a \n" + + "------> \u001B[91mFAILED\u001B[0m -- sub2b -- Error: error msg A for sub2b should be shown as result of sub2b\n" + + "------> \u001B[92mSuccess\u001B[0m -- sub2c-optional \n" + + "---------> \u001B[93mFAILED\u001B[0m -- sub3a-taskWithResult \n" + + "------------> \u001B[93mFAILED\u001B[0m -- addResultToEval -- Error: returned-result - error msg B should be once in output - in addResultToEval\n" + + "------> \u001B[91mFAILED\u001B[0m -- sub2d-requireLast \n" + + "---------> \u001B[91mFAILED\u001B[0m -- sub3b-taskWithResult without error message \n" + + "------> \u001B[92mSuccess\u001B[0m -- sub2e-task \n" + + "---------> \u001B[92mSuccess\u001B[0m -- addResultToEval \n" + + "------> \u001B[91mFAILED\u001B[0m -- sub2f-taskWithResult -- Error: returned-result - error msg C should be once in output - at the end of sub3taskWithResult \n" + + "------> \u001B[91mFAILED\u001B[0m -- <> -- Error: returned-result - error msg D should be once in output - at the end of sub1 \n" + + "----------------------------------------------------------------------------------------------------\n" + + "Overall > \u001B[91mFAILED\u001B[0m \n" + + "============================================ SUMMARY END ===========================================\n" + + "\n" + + assertEquals(expectedOutput, outContent.toString().replace("\r", "")) + } + } From 332978cfa1aa6f9a4cdbae59084c1c8c8a051f57 Mon Sep 17 00:00:00 2001 From: az Date: Wed, 5 Apr 2023 18:54:08 +0200 Subject: [PATCH 14/18] [skip ci] add comment --- .../org/domaindrivenarchitecture/provs/framework/core/Prov.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt index 608c462..adb2f11 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt @@ -316,6 +316,7 @@ open class Prov protected constructor( // which is the case if the result was not part of another subtask but created and returned by the lambda itself. // Success results do not need to be added here as they don't change the overall success evaluation, // whereas the failure results may have a useful error message, which should be in the output. + // Only direct result objects are added, but not result objects that were passed from a subtask as they are already handled in the subtask. if (!resultOfTaskLambda.success && (resultIndex < internalResults.size - 1) && (resultOfTaskLambda != internalResults[resultIndex + 1].provResult)) { internalResults.add(ResultLine(level + 1, "<>", resultOfTaskLambda)) } From a46cc9d2aed9826a092d05af026c9fc462404ba3 Mon Sep 17 00:00:00 2001 From: az Date: Wed, 5 Apr 2023 18:55:08 +0200 Subject: [PATCH 15/18] release-0.18.3 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e81ff17..0603eea 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ apply plugin: "kotlinx-serialization" group = "org.domaindrivenarchitecture.provs" -version = "0.18.3-SNAPSHOT" +version = "release-0.18.3" repositories { mavenCentral() From abd8c34d2cabcfeef904edca4a94cef7485f735a Mon Sep 17 00:00:00 2001 From: az Date: Wed, 5 Apr 2023 18:56:18 +0200 Subject: [PATCH 16/18] [skip ci] 0.18.4-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0603eea..6575455 100644 --- a/build.gradle +++ b/build.gradle @@ -18,7 +18,7 @@ apply plugin: "kotlinx-serialization" group = "org.domaindrivenarchitecture.provs" -version = "release-0.18.3" +version = "0.18.4-SNAPSHOT" repositories { mavenCentral() From 54b4d3075c10b87ca3c85fc6237264ab6cd082d3 Mon Sep 17 00:00:00 2001 From: az Date: Wed, 5 Apr 2023 21:02:10 +0200 Subject: [PATCH 17/18] [skip ci] remove redundant firefox installation --- .../provs/desktop/infrastructure/PackageBundles.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/PackageBundles.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/PackageBundles.kt index 8264d21..039cb1e 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/PackageBundles.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/PackageBundles.kt @@ -8,7 +8,7 @@ val NETWORK_TOOLS = "curl wget net-tools" val KEY_MANAGEMENT_GUI = "seahorse" -val BROWSER = "firefox chromium-browser" +val BROWSER = "chromium-browser" // firefox can be installed by installFirefox val EMAIL_CLIENT = "thunderbird" From 8e2c5e13a66865211ca701ce65454e8214dc129c Mon Sep 17 00:00:00 2001 From: az Date: Thu, 6 Apr 2023 17:58:19 +0200 Subject: [PATCH 18/18] [skip ci] add installation of python packages for pybuilder --- .../provs/desktop/infrastructure/Python.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Python.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Python.kt index 38c0b6c..03b0724 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Python.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Python.kt @@ -28,8 +28,9 @@ fun Prov.configureVenv(): ProvResult = task { } fun Prov.installPybuilder(): ProvResult = task { - cmd("pip3 install pybuilder ddadevops pypandoc mockito coverage unittest-xml-reporting deprecation python_terraform " + - "boto3") + cmd("pip3 install pybuilder ddadevops pypandoc mockito coverage unittest-xml-reporting deprecation" + + " python_terraform dda_python_terraform boto3 pyyaml ") + cmd("pip3 install --upgrade ddadevops") } fun Prov.installRestClient(): ProvResult = task {