Skip to content

Commit

Permalink
response handling for idle state (#121) (#126)
Browse files Browse the repository at this point in the history
  • Loading branch information
MxEh-TT authored Apr 30, 2024
1 parent 834e024 commit 4ea18a8
Show file tree
Hide file tree
Showing 19 changed files with 633 additions and 200 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,27 @@
*/
package de.tracetronic.jenkins.plugins.ecutestexecution.builder


import de.tracetronic.jenkins.plugins.ecutestexecution.clients.RestApiClient
import de.tracetronic.jenkins.plugins.ecutestexecution.clients.RestApiClientFactory
import de.tracetronic.jenkins.plugins.ecutestexecution.clients.model.ApiException
import de.tracetronic.jenkins.plugins.ecutestexecution.security.ControllerToAgentCallableWithTimeout
import de.tracetronic.jenkins.plugins.ecutestexecution.clients.model.ExecutionOrder
import de.tracetronic.jenkins.plugins.ecutestexecution.clients.model.ReportInfo
import de.tracetronic.jenkins.plugins.ecutestexecution.configs.ExecutionConfig
import de.tracetronic.jenkins.plugins.ecutestexecution.configs.TestConfig
import de.tracetronic.jenkins.plugins.ecutestexecution.model.CheckPackageResult
import de.tracetronic.jenkins.plugins.ecutestexecution.model.GenerationResult
import de.tracetronic.jenkins.plugins.ecutestexecution.model.TestResult
import de.tracetronic.jenkins.plugins.ecutestexecution.model.ToolInstallations
import de.tracetronic.jenkins.plugins.ecutestexecution.steps.CheckPackageStep
import de.tracetronic.jenkins.plugins.ecutestexecution.util.LogConfigUtil
import hudson.EnvVars
import hudson.Launcher
import hudson.model.Result
import hudson.model.Run
import hudson.model.TaskListener
import jenkins.security.MasterToSlaveCallable
import org.apache.commons.lang.StringUtils
import org.jenkinsci.plugins.workflow.steps.StepContext


/**
* Common base class for all test related steps implemented in this plugin.
*/
Expand All @@ -37,7 +36,9 @@ abstract class AbstractTestBuilder implements Serializable {
final StepContext context

protected abstract String getTestArtifactName()

protected abstract LogConfigUtil getLogConfig()

protected abstract ExecutionOrderBuilder getExecutionOrderBuilder()

AbstractTestBuilder(String testCasePath, TestConfig testConfig, ExecutionConfig executionConfig,
Expand All @@ -58,41 +59,31 @@ abstract class AbstractTestBuilder implements Serializable {
}

/**
* Performs CheckPackageStep if executePackageCheck option was set in the execution config and calls the execution
* of the package.
* Calls the execution of the package.
* @return TestResult
* results of the test execution
*/
TestResult runTest() {
TaskListener listener = context.get(TaskListener.class)
ToolInstallations toolInstallations = new ToolInstallations(context)

if (executionConfig.executePackageCheck){
CheckPackageStep step = new CheckPackageStep(testCasePath)
step.setExecutionConfig(executionConfig)
CheckPackageResult check_result = step.start(context).run()
if (executionConfig.stopOnError && check_result.result == "ERROR") {
listener.logger.println(
"Skipping execution of ${testArtifactName} ${testCasePath} due to failed package checks"
)
return new TestResult(null, "ERROR",null)
}
}

TestResult result
try {
return context.get(Launcher.class).getChannel().call(new RunTestCallable(testCasePath,
result = context.get(Launcher.class).getChannel().call(new RunTestCallable(testCasePath,
context.get(EnvVars.class), listener, executionConfig,
getTestArtifactName(), getLogConfig(), getExecutionOrderBuilder(), toolInstallations))
} catch (Exception e) {
context.get(TaskListener.class).error(e.message)
listener.logger.println("Executing ${testArtifactName} '${testCasePath}' failed!")
listener.error(e.message)
context.get(Run.class).setResult(Result.FAILURE)
return new TestResult(null, "A problem occured during the report generation. See caused exception for more details.", null)
result = new TestResult(null, "A problem occurred during the report generation. See caused exception for more details.", null)
}
listener.logger.flush()
return result
}

private static final class RunTestCallable extends MasterToSlaveCallable<TestResult, IOException> {
private static final long serialVersionUID = 1L
private static final class RunTestCallable extends ControllerToAgentCallableWithTimeout<TestResult, IOException> {

private static final long serialVersionUID = 1L

private final String testCasePath
private final EnvVars envVars
Expand All @@ -102,10 +93,12 @@ abstract class AbstractTestBuilder implements Serializable {
private final String testArtifactName
private final LogConfigUtil configUtil
private final ToolInstallations toolInstallations
private RestApiClient apiClient

RunTestCallable(final String testCasePath, EnvVars envVars, TaskListener listener,
ExecutionConfig executionConfig, String testArtifactName, LogConfigUtil configUtil,
ExecutionOrderBuilder executionOrderBuilder, ToolInstallations toolInstallations) {
super(executionConfig.timeout, listener)
this.testCasePath = testCasePath
this.envVars = envVars
this.listener = listener
Expand All @@ -114,25 +107,43 @@ abstract class AbstractTestBuilder implements Serializable {
this.configUtil = configUtil
this.executionOrderBuilder = executionOrderBuilder
this.toolInstallations = toolInstallations

}

/**
* Performs CheckPackageStep if executePackageCheck option was set in the execution config and
* executes the package
* @return TestResult results of the test execution
* @throws IOException
*/
@Override
TestResult call() throws IOException {
TestResult execute() throws IOException {
listener.logger.println("Executing ${testArtifactName} '${testCasePath}'...")
apiClient = RestApiClientFactory.getRestApiClient(envVars.get('ET_API_HOSTNAME'), envVars.get('ET_API_PORT'))
if (executionConfig.executePackageCheck) {
listener.logger.println("Executing package checks for '${testCasePath}'")
CheckPackageResult check_result = apiClient.runPackageCheck(testCasePath)
listener.logger.println(check_result.toString())
if (executionConfig.stopOnError && check_result.result == "ERROR") {
listener.logger.println(
"Skipping execution of ${testArtifactName} '${testCasePath}' due to failed package checks"
)
listener.logger.flush()
return new TestResult(null, "ERROR", null)
}
}
ExecutionOrder executionOrder = executionOrderBuilder.build()
RestApiClient apiClient = RestApiClientFactory.getRestApiClient(envVars.get('ET_API_HOSTNAME'), envVars.get('ET_API_PORT'))

listener.logger.println("Executing ${testArtifactName} ${testCasePath}...")
configUtil.log()

ReportInfo reportInfo = apiClient.runTest(executionOrder, executionConfig.timeout)
ReportInfo reportInfo = apiClient.runTest(executionOrder)

TestResult result
if (reportInfo) {
result = new TestResult(reportInfo.testReportId, reportInfo.result, reportInfo.reportDir)
listener.logger.println("${StringUtils.capitalize(testArtifactName)} executed successfully.")
} else {
result = new TestResult(null, 'ERROR', null)
listener.logger.println("Executing ${testArtifactName} failed!")
listener.logger.println("Executing ${testArtifactName} '${testCasePath}' failed!")
if (executionConfig.stopOnError) {
toolInstallations.stopToolInstances(executionConfig.timeout)
if (executionConfig.stopUndefinedTools) {
Expand All @@ -141,7 +152,18 @@ abstract class AbstractTestBuilder implements Serializable {
}
}
listener.logger.println(result.toString())
listener.logger.flush()
return result
}

/**
* Cancels the package check because it exceeded the configured timeout
* If the RestApiClientFactory has not return an apiClient for this class yet, it will be canceled there
*/
@Override
void cancel() {
listener.logger.println("Canceling ${testArtifactName} execution!")
!apiClient ? RestApiClientFactory.setTimeoutExceeded() : apiClient.setTimeoutExceeded()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,44 @@ import java.util.concurrent.TimeoutException

interface RestApiClient {

/**
* Sets the timeoutExceeded to true, which will stop the execution at the next check
*/
abstract void setTimeoutExceeded()
/**
* Waits until the ecu.test REST api is alive or timeout is reached.
* @param timeout time in seconds to wait for alive check
* @return boolean:
* true, if the the ecu.test API sends an alive signal within the timeout range
* false, otherwise
* @throws TimeoutException if the execution time exceeded the timeout
*/
abstract boolean waitForAlive(int timeout)
abstract boolean waitForAlive(int timeout) throws TimeoutException

/**
* This method performs the package check for the given test package or project via REST api.
* The method will abort upon a thread interruption signal used by the TimeoutControllerToAgentCallable to handle the
* timeout from outside this class.
* {@see de.tracetronic.jenkins.plugins.ecutestexecution.security.TimeoutControllerToAgentCallable}
* @param testPkgPath the path to the package or project to be checked
* @param timeout Time in seconds until the check package execution will be aborted
* @return CheckPackageResult with the result of the check
* @throws ApiException on error status codes
* @throws TimeoutException on timeout exceeded
* @throws ApiException on error status codes (except 409 (busy) where it will wait until success or timeout)
* @throws TimeoutException if the execution time exceeded the timeout
*/
abstract CheckPackageResult runPackageCheck(String testPkgPath, int timeout) throws ApiException, TimeoutException
abstract CheckPackageResult runPackageCheck(String testPkgPath) throws ApiException, TimeoutException

/**
* Executes the test package or project of the given ExecutionOrder via REST api.
* The method will abort upon a thread interruption signal used by the TimeoutControllerToAgentCallable to handle the
* timeout from outside this class.
* {@see de.tracetronic.jenkins.plugins.ecutestexecution.security.TimeoutControllerToAgentCallable}
* @param executionOrder is an ExecutionOrder object which defines the test environment and even the test package
* or project
* @param timeout Time in seconds until the test execution will be aborted
* @return ReportInfo with report information about the test execution
* @throws ApiException on error status codes (except 409 (busy) where it will wait until success or timeout)
* @throws TimeoutException if the execution time exceeded the timeout
*/
abstract ReportInfo runTest(ExecutionOrder executionOrder, int timeout)
abstract ReportInfo runTest(ExecutionOrder executionOrder) throws ApiException, TimeoutException

/**
* Generates a report for a given report ID. The report has the format defined by the ReportGenerationOrder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ package de.tracetronic.jenkins.plugins.ecutestexecution.clients
import de.tracetronic.jenkins.plugins.ecutestexecution.clients.model.ApiException
import org.apache.commons.lang.StringUtils

import java.util.concurrent.TimeoutException

class RestApiClientFactory {
private static int DEFAULT_TIMEOUT = 10
private static final String DEFAULT_HOSTNAME = 'localhost'
private static final String DEFAULT_PORT = '5050'

private static RestApiClient apiClient
/**
* Determine the client for the highest REST api version of the given ecu.test.
* @param hostName (optional) set if ecu.test is hosted on a custom host
Expand All @@ -25,16 +27,24 @@ class RestApiClientFactory {
hostName = StringUtils.isBlank(hostName) ? DEFAULT_HOSTNAME : StringUtils.trim(hostName)
port = StringUtils.isBlank(port) ? DEFAULT_PORT : StringUtils.trim(port)

RestApiClient apiClientV2 = new RestApiClientV2(hostName, port)
if (apiClientV2.waitForAlive(timeout)) {
return apiClientV2
apiClient = new RestApiClientV2(hostName, port)
if (apiClient.waitForAlive(timeout)) {
return apiClient
}

RestApiClient apiClientV1 = new RestApiClientV1(hostName, port)
if (apiClientV1.waitForAlive(timeout)) {
return apiClientV1
apiClient = new RestApiClientV1(hostName, port)
if (apiClient.waitForAlive(timeout)) {
return apiClient
}

throw new ApiException("Could not find a ecu.test REST api for host: ${hostName}:${port}")
}

/**
* Sets the executionTimedOut of the current ApiClient to true, which will stop the execution of ApiCalls and
* throw a TimeoutException
*/
static setTimeoutExceeded() {
apiClient.setTimeoutExceeded()
}
}
Loading

0 comments on commit 4ea18a8

Please sign in to comment.