From a3f931d84dab13082a99a8721a9d635c05686c3e Mon Sep 17 00:00:00 2001 From: Uladzislau Date: Wed, 25 Sep 2024 18:57:01 +0200 Subject: [PATCH] IJMP-1940 Testcases added Signed-off-by: Uladzislau --- .../declarative/ZosmfStepDeclarative.kt | 3 +- .../AbstractZosmfActionWithResultSpec.kt | 79 +++++++++++++++++++ .../declarative/ZosmfStepDeclarativeSpec.kt | 53 +++++++++++++ .../kotlin/org/zowe/zdevops/testutils/misc.kt | 51 ++++++++++++ 4 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 src/test/kotlin/org/zowe/zdevops/declarative/AbstractZosmfActionWithResultSpec.kt create mode 100644 src/test/kotlin/org/zowe/zdevops/declarative/ZosmfStepDeclarativeSpec.kt create mode 100644 src/test/kotlin/org/zowe/zdevops/testutils/misc.kt diff --git a/src/main/kotlin/org/zowe/zdevops/declarative/ZosmfStepDeclarative.kt b/src/main/kotlin/org/zowe/zdevops/declarative/ZosmfStepDeclarative.kt index 75349ed..3a99a10 100644 --- a/src/main/kotlin/org/zowe/zdevops/declarative/ZosmfStepDeclarative.kt +++ b/src/main/kotlin/org/zowe/zdevops/declarative/ZosmfStepDeclarative.kt @@ -23,11 +23,10 @@ import org.kohsuke.stapler.DataBoundConstructor import org.zowe.zdevops.utils.getZoweZosConnection import org.zowe.zdevops.utils.validateConnection - class ZosmfStepDeclarative @DataBoundConstructor constructor(private val connectionName: String) : Step() { override fun start(context: StepContext): StepExecution { val listener: TaskListener? = context.get(TaskListener::class.java) - val zosConnection = getZoweZosConnection(connectionName, listener) + val zosConnection = getZoweZosConnection(connectionName, listener) validateConnection(zosConnection) diff --git a/src/test/kotlin/org/zowe/zdevops/declarative/AbstractZosmfActionWithResultSpec.kt b/src/test/kotlin/org/zowe/zdevops/declarative/AbstractZosmfActionWithResultSpec.kt new file mode 100644 index 0000000..ef51a2a --- /dev/null +++ b/src/test/kotlin/org/zowe/zdevops/declarative/AbstractZosmfActionWithResultSpec.kt @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024 IBA Group. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBA Group + * Zowe Community + */ + +package org.zowe.zdevops.declarative + +import hudson.EnvVars +import hudson.FilePath +import hudson.model.TaskListener +import io.kotest.assertions.assertSoftly +import io.kotest.core.spec.style.ShouldSpec +import io.kotest.matchers.shouldBe +import io.mockk.* +import org.jenkinsci.plugins.workflow.steps.StepContext +import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution +import org.zowe.kotlinsdk.zowe.client.sdk.core.ZOSConnection +import org.zowe.zdevops.testutils.getPrivateFieldValue +import org.zowe.zdevops.utils.getZoweZosConnection +import java.io.ByteArrayInputStream +import java.nio.charset.StandardCharsets +import java.util.concurrent.Future + +class AbstractZosmfActionWithResultSpec : ShouldSpec({ + var runCalledCount = 0 + + val zosmfActionWithResult = object : AbstractZosmfActionWithResult() { + override fun run( + workspace: FilePath, + listener: TaskListener, + envVars: EnvVars, + zoweZOSConnection: ZOSConnection + ): String { + runCalledCount++ + return "test" + } + } + + afterEach { + runCalledCount = 0 + } + + context("declarative module: AbstractZosmfActionWithResult") { + should("check execution runs the step provided when the task is started and finished successfully") { + val workspace = mockk() + every { workspace.read() } returns ByteArrayInputStream("test".toByteArray(StandardCharsets.UTF_8)) + + val stepContext = mockk() + every { stepContext.get(FilePath::class.java) } returns workspace + every { stepContext.get(TaskListener::class.java) } returns mockk() + every { stepContext.get(EnvVars::class.java) } returns mockk() + every { stepContext.onSuccess(any()) } just Runs + + mockkStatic(::getZoweZosConnection) + every { getZoweZosConnection("test", any()) } returns mockk() + + val execution = zosmfActionWithResult.start(stepContext) as AbstractZosmfActionWithResult.Companion.Execution + execution.start() + val executionTask: Future<*> = getPrivateFieldValue( + execution, + SynchronousNonBlockingStepExecution::class.java, + "task" + ) as Future<*> + executionTask.get() + + verify(exactly = 1) { stepContext.onSuccess(any()) } + assertSoftly { runCalledCount shouldBe 1 } + } + } +}) \ No newline at end of file diff --git a/src/test/kotlin/org/zowe/zdevops/declarative/ZosmfStepDeclarativeSpec.kt b/src/test/kotlin/org/zowe/zdevops/declarative/ZosmfStepDeclarativeSpec.kt new file mode 100644 index 0000000..26a0b5b --- /dev/null +++ b/src/test/kotlin/org/zowe/zdevops/declarative/ZosmfStepDeclarativeSpec.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024 IBA Group. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBA Group + * Zowe Community + */ + +package org.zowe.zdevops.declarative + +import hudson.model.TaskListener +import io.kotest.core.spec.style.ShouldSpec +import io.mockk.* +import org.jenkinsci.plugins.workflow.steps.StepContext +import org.zowe.kotlinsdk.zowe.client.sdk.core.ZOSConnection +import org.zowe.zdevops.config.ZOSConnectionList +import org.zowe.zdevops.model.ResolvedZOSConnection +import org.zowe.zdevops.utils.getZoweZosConnection +import org.zowe.zdevops.utils.validateConnection + +class ZosmfStepDeclarativeSpec : ShouldSpec({ + context("declarative module: ZosmfStepDeclarative") { + should("check the zosmf declarative step is run, connection is formed and validated") { + val zosmfStepDeclarative = ZosmfStepDeclarative("test") + + val taskListener = mockk() + + val stepContext = mockk() + every { stepContext.get(TaskListener::class.java) } returns taskListener + + val resolvedZosConnection = mockk() + every { resolvedZosConnection.url } returns "https://test.com:1234" + every { resolvedZosConnection.username } returns "test_user" + every { resolvedZosConnection.password } returns "test_pass" + + mockkObject(ZOSConnectionList) + every { ZOSConnectionList.resolve("test") } returns resolvedZosConnection + + mockkStatic(::validateConnection) + every { validateConnection(any()) } returns Unit + + zosmfStepDeclarative.start(stepContext) + verify(exactly = 1) { validateConnection(any()) } + verify(exactly = 1) { getZoweZosConnection("test", taskListener) } + } + } +}) diff --git a/src/test/kotlin/org/zowe/zdevops/testutils/misc.kt b/src/test/kotlin/org/zowe/zdevops/testutils/misc.kt new file mode 100644 index 0000000..1ec1013 --- /dev/null +++ b/src/test/kotlin/org/zowe/zdevops/testutils/misc.kt @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 IBA Group. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBA Group + * Zowe Community + */ + +package org.zowe.zdevops.testutils + +import java.lang.reflect.Modifier + +/** + * Mock private/protected field of the class for the object + * @param sourceObj the source object to mock the field for + * @param classWithTheField the class where the field is declared + * @param fieldName the field name to mock + * @param mockValue the mock value to set for the field + */ +fun setPrivateFieldValue(sourceObj: Any, classWithTheField: Class<*>, fieldName: String, mockValue: Any) { + return classWithTheField + .declaredFields + .filter { it.modifiers.and(Modifier.PRIVATE) > 0 || it.modifiers.and(Modifier.PROTECTED) > 0 } + .find { it.name == fieldName } + ?.also { it.isAccessible = true } + ?.set(sourceObj, mockValue) + ?: throw NoSuchFieldException("Field with name '$fieldName' is not found amongst private or protected fields") +} + +/** + * Get private/protected field of the class stored in the object + * @param sourceObj the source object to get the field from + * @param classWithTheField the class where the field is declared + * @param fieldName the field name to get value of + */ +fun getPrivateFieldValue(sourceObj: Any, classWithTheField: Class<*>, fieldName: String): Any { + val theField = classWithTheField + .declaredFields + .filter { it.modifiers.and(Modifier.PRIVATE) > 0 || it.modifiers.and(Modifier.PROTECTED) > 0 } + .find { it.name == fieldName } + ?.also { it.isAccessible = true } + ?: throw NoSuchFieldException("Field with name '$fieldName' is not found amongst private or protected fields") + return theField.get(sourceObj) + ?: throw Exception("Field with name '$fieldName' is not accessible") +}