diff --git a/doc/dev/containerTest.md b/doc/dev/containerTest.md index d123174..cb42131 100644 --- a/doc/dev/containerTest.md +++ b/doc/dev/containerTest.md @@ -1,11 +1,15 @@ -Should be added in dev_circumstances for single unit tests to get repeatable results ('fresh container'): -ContainerStartMode.CREATE_NEW_KILL_EXISTING +# Container Tests -like this way: -+import org.domaindrivenarchitecture.provs.test.tags.ContainerTest +The method `defaultTestContainer()` provides a prov instance in a container for integration-tests. -//annotate to ContainerTest -+@ContainerTest +Container-tests should be annotated by tag: `@ContainerTest` and if long-lasting (ca. > 10 - 20 sec) with @ExtensiveContainerTest + + +For performance reasons the test container is re-used among the tests. + +In case you want a fresh container for your test, add the following option: + +`ContainerStartMode.CREATE_NEW_KILL_EXISTING` + +example: `val container = defaultTestContainer(ContainerStartMode.CREATE_NEW_KILL_EXISTING)` -//and configured Testcontainer -+val container = defaultTestContainer(ContainerStartMode.CREATE_NEW_KILL_EXISTING) \ No newline at end of file diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScript.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScript.kt index c6d9d79..657871c 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScript.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScript.kt @@ -2,14 +2,17 @@ package org.domaindrivenarchitecture.provs.desktop.infrastructure import org.domaindrivenarchitecture.provs.framework.core.Prov import org.domaindrivenarchitecture.provs.framework.core.ProvResult -import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.isPackageInstalled +/** + * Installs ShadowCljs. Prerequisite: NVM and NPM are installed, otherwise fails. + */ fun Prov.installShadowCljs(): ProvResult = task { - if (!isPackageInstalled("shadow-cljs")) { - cmd(". .nvm/nvm.sh && npm install -g shadow-cljs") - cmd(". .nvm/nvm.sh && shadow-cljs --help") + if (!chk(". .nvm/nvm.sh")) { + addProvResult(false, err = "nvm not installed!") } else { - ProvResult(true, out = "shadow-cljs already installed") + if (!chk("npm list -g --depth=0 | grep shadow-cljs")) { + cmd(". .nvm/nvm.sh && npm install -g shadow-cljs") + } } } diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Go.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Go.kt index c46fb75..b3b37dc 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Go.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/Go.kt @@ -3,16 +3,16 @@ package org.domaindrivenarchitecture.provs.desktop.infrastructure import org.domaindrivenarchitecture.provs.framework.core.Prov import org.domaindrivenarchitecture.provs.framework.core.ProvResult import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.* -import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.isPackageInstalledCheckCommand +import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.checkCommand import org.domaindrivenarchitecture.provs.framework.ubuntu.web.base.downloadFromURL +//from https://go.dev/dl/ fun Prov.installGo( - //from https://go.dev/dl/ version: String = "1.23.5", enforceVersion: Boolean = false, sha256sum: String = "cbcad4a6482107c7c7926df1608106c189417163428200ce357695cc7e01d091" ) = taskWithResult { - if (isPackageInstalledCheckCommand("go") && !enforceVersion) { + if (checkCommand("go") && !enforceVersion) { return@taskWithResult ProvResult(true) } diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvm.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvm.kt index 344f8c2..0bcf674 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvm.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvm.kt @@ -2,39 +2,34 @@ package org.domaindrivenarchitecture.provs.desktop.infrastructure import org.domaindrivenarchitecture.provs.framework.core.Prov import org.domaindrivenarchitecture.provs.framework.core.ProvResult +import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.checkFile import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createFile import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.userHome -import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.isPackageInstalledCheckCommand -fun Prov.installNpmByNvm(): ProvResult = task { +/** + * Installs Node.js and NPM (Node Package Manager) by using NVM (Node Version Manager), if NVM not already installed + */ +fun Prov.installNpmByNvm(version: String = "0.40.1"): ProvResult = task { - if (!isPackageInstalledCheckCommand("npm")) { - //Node-Version-Manager from https://github.com/nvm-sh/nvm - val version = "0.40.1" + //see Node-Version-Manager at https://github.com/nvm-sh/nvm + + val bashConfigFile = "~/.bashrc.d/npmbynvm.sh" + if (!checkFile(".nvm/nvm.sh") && !checkFile(bashConfigFile)) { + + // install NVM cmd("sudo curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v$version/install.sh | bash") - cmd("chmod 755 .nvm/nvm.sh") + // configure bash - create file ".bashrc.d/npmbynvm.sh" with settings configureBashForUser() - createFile("~/.bashrc.d/npmbynvm.sh", """export NVM_DIR="${userHome()}.nvm" """ + "\n" - + """[ -s "${"\$NVM_DIR/nvm.sh"}" ] && \. "${"\$NVM_DIR/nvm.sh"}" """ + "\n") + val content = """ + export NVM_DIR="${userHome()}.nvm" + [ -s "${"\$NVM_DIR/nvm.sh"}" ] && \. "${"\$NVM_DIR/nvm.sh"}" + """.trimIndent() + createFile(bashConfigFile, content) + + // install Node.js and NPM cmd(". .nvm/nvm.sh && nvm install --lts") - - val nvmRes = cmd(". .nvm/nvm.sh && nvm --version").toString() - if (version == nvmRes) { - println("NVM version $version") - addResultToEval(ProvResult(true, out = "SUCCESS: NVM version $version installed !!")) - } else { - println("FAIL: NVM version $version is not installed !!") - addResultToEval(ProvResult(true, out = "FAIL: NVM version $version is not installed !!")) - } - cmd(". .nvm/nvm.sh && node -v") - cmd(". .nvm/nvm.sh && npm --version") - - } else { - addResultToEval(ProvResult(true, out = "npm already installed")) } - - } \ No newline at end of file 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 2b059c8..8ad433a 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/core/Prov.kt @@ -217,11 +217,12 @@ open class Prov protected constructor( fun getSecret(command: String, removeNewlineSuffix: Boolean = false): Secret? { val result = cmdNoLog(command) return if (result.success && result.out != null) { - addResultToEval(ProvResult(true, getCallingMethodName())) - val plainSecret = if (removeNewlineSuffix && result.out.takeLast(1) == "\n") result.out.dropLast(1) else result.out + addProvResult(true, getCallingMethodName()) + val plainSecret = + if (removeNewlineSuffix && result.out.takeLast(1) == "\n") result.out.dropLast(1) else result.out Secret(plainSecret) } else { - addResultToEval(ProvResult(false, getCallingMethodName(), err = result.err, exception = result.exception)) + addProvResult(false, getCallingMethodName(), err = result.err, exception = result.exception) null } } @@ -231,10 +232,26 @@ open class Prov protected constructor( * Adds a ProvResult to the overall success evaluation. * Intended for use in methods which do not automatically add results. */ + @Deprecated("since 0.39.7", replaceWith = ReplaceWith("addProvResult", )) fun addResultToEval(result: ProvResult) = taskWithResult { result } + /** + * Adds a ProvResult to the overall success evaluation. + * Intended for use in methods which do not automatically add results. + */ + fun addProvResult( + success: Boolean, + cmd: String? = null, + out: String? = null, + err: String? = null, + exception: Exception? = null, + exit: String? = null + ) = taskWithResult { + ProvResult(success, cmd, out, err, exception, exit) + } + /** * Executes multiple shell commands. Each command must be in its own line. * Multi-line commands within the script are not supported. diff --git a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/install/base/Install.kt b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/install/base/Install.kt index 10db980..5eb86eb 100644 --- a/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/install/base/Install.kt +++ b/src/main/kotlin/org/domaindrivenarchitecture/provs/framework/ubuntu/install/base/Install.kt @@ -16,9 +16,9 @@ private var aptInit = false @Suppress("UNUSED_PARAMETER") // ignoreAlreadyInstalled is added for external usage fun Prov.aptInstall(packages: String, ignoreAlreadyInstalled: Boolean = true): ProvResult = taskWithResult { val packageList = packages.split(" ") - val allInstalled: Boolean = packageList.map { isPackageInstalled(it) }.fold(true, { a, b -> a && b }) + val allInstalled: Boolean = packageList.map { checkPackage(it) }.fold(true, { a, b -> a && b }) if (!allInstalled) { - if (!isPackageInstalled(packages)) { + if (!checkPackage(packages)) { if (!aptInit) { optional { // may fail for some packages, but this should in general not be an issue @@ -31,8 +31,7 @@ fun Prov.aptInstall(packages: String, ignoreAlreadyInstalled: Boolean = true): P for (packg in packageList) { // see https://superuser.com/questions/164553/automatically-answer-yes-when-using-apt-get-install - cmd("sudo apt-get install -q=2 $packg") - //DEBIAN_FRONTEND=noninteractive + cmd("sudo DEBIAN_FRONTEND=noninteractive apt-get install -q=2 $packg") } ProvResult(true) // dummy } else { @@ -71,20 +70,36 @@ fun Prov.aptInstallFromPpa(launchPadUser: String, ppaName: String, packageName: /** * Returns true if a package is installed else false */ +@Deprecated("since 0.39.7", replaceWith = ReplaceWith("checkPackage")) fun Prov.isPackageInstalled(packageName: String): Boolean { return chk("dpkg -s $packageName") } +/** + * Returns true if a package is installed else false + */ +fun Prov.checkPackage(packageName: String): Boolean { + return chk("dpkg -s $packageName") +} + /** * Returns true if a package is installed else false */ +@Deprecated("since 0.39.7", replaceWith = ReplaceWith("checkPackage")) fun Prov.checkPackageInstalled(packageName: String): ProvResult = taskWithResult { cmd("dpkg -s $packageName") } -fun Prov.isPackageInstalledCheckCommand(packageName: String): Boolean { - return chk("command -v $packageName") +/** + * Returns true if a command is available else false. + * Can be used e.g. to check if software is installed in case it is not installed as debian package. + * ATTENTION: + * * checks only commands which are available in the shell + * * does NOT find commands which are defined in .bashrc when running in a non-interactive shell (which is the case with: `bash -c "command -v mycommand"`), + */ +fun Prov.checkCommand(commandName: String): Boolean { + return chk("command -v $commandName") } /** diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScriptKtTest.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScriptKtTest.kt index 4fa402f..2a3d042 100644 --- a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScriptKtTest.kt +++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/ClojureScriptKtTest.kt @@ -1,7 +1,11 @@ package org.domaindrivenarchitecture.provs.desktop.infrastructure +import org.domaindrivenarchitecture.provs.framework.core.processors.ContainerStartMode +import org.domaindrivenarchitecture.provs.framework.ubuntu.install.base.aptInstall import org.domaindrivenarchitecture.provs.test.defaultTestContainer import org.domaindrivenarchitecture.provs.test.tags.ContainerTest +import org.domaindrivenarchitecture.provs.test.tags.ExtensiveContainerTest +import org.junit.jupiter.api.Assertions.assertFalse import org.junit.jupiter.api.Assertions.assertTrue internal class ClojureScriptKtTest { @@ -10,19 +14,30 @@ internal class ClojureScriptKtTest { fun installShadowCljs() { // given val prov = defaultTestContainer() - - //Todo: - // To be discussed, should init container, but not available for prov.installShadowCljs() !! - // Howto work in addition prov.a() + prov.b()? - prov.installNpmByNvm() + prov.task { + aptInstall("curl") + installNpmByNvm() + } // when - // check if it can be run twice successfully - val res01 = prov.installShadowCljs() - val res02 = prov.installShadowCljs() + val res = prov.task { + installShadowCljs() + installShadowCljs() // check repeatability + } // then - assertTrue(res01.success) - assertTrue(res02.success) + assertTrue(res.success) + } + + @ExtensiveContainerTest // extensive test, as it kills the existing container and creates a new one + fun installShadowCljs_fails_if_nvm_missing() { + // given + val prov = defaultTestContainer(ContainerStartMode.CREATE_NEW_KILL_EXISTING) + + // when + val res = prov.installShadowCljs() + + // then + assertFalse(res.success) } } \ No newline at end of file diff --git a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvmKtTest.kt b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvmKtTest.kt index 3d8866a..3dacbf3 100644 --- a/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvmKtTest.kt +++ b/src/test/kotlin/org/domaindrivenarchitecture/provs/desktop/infrastructure/NpmByNvmKtTest.kt @@ -7,16 +7,22 @@ import org.junit.jupiter.api.Assertions.assertTrue internal class NpmByNvmKtTest { - @ContainerTest - fun installNVMnpm() { - // given - val container = defaultTestContainer() - container.aptInstall("curl") - // when - val res01 = container.installNpmByNvm() - val res02 = container.installNpmByNvm() - // then - assertTrue(res01.success) - assertTrue(res02.success) - } + @ContainerTest + fun installNVMnpm() { + // given + val prov = defaultTestContainer() + prov.aptInstall("curl") + + // when + val res = prov.task { + installNpmByNvm() + installNpmByNvm() // check repeatability + // check if node and npm are installed and can be called in a shell (with sourcing nvm.sh) + cmd(". .nvm/nvm.sh && node -v") + cmd(". .nvm/nvm.sh && npm --version") + } + + // then + assertTrue(res.success) + } } \ No newline at end of file