Skip to content

Commit

Permalink
add first internal review notes (#143)
Browse files Browse the repository at this point in the history
- adjust step name
- adjust container tests
- use report folder name for identification
- also provide err logs
  • Loading branch information
MxEh-TT committed Jul 25, 2024
1 parent 81bbc2c commit 2762e4c
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import hudson.FilePath
import hudson.model.Run
import jenkins.model.RunAction2

class ProvideReportLogsAction implements RunAction2 {
class ProvideLogsAction implements RunAction2 {
private transient Run<?, ?> run

ProvideReportLogsAction(Run<?, ?> run) {
ProvideLogsAction(Run<?, ?> run) {
this.run = run
}

Expand Down Expand Up @@ -41,7 +41,7 @@ class ProvideReportLogsAction implements RunAction2 {
return run
}

List<Run.Artifact> getReportLogs() {
List<Run.Artifact> getLogs() {
return run?.artifacts ?: []
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ package de.tracetronic.jenkins.plugins.ecutestexecution.steps
import com.google.common.collect.ImmutableSet
import de.tracetronic.jenkins.plugins.ecutestexecution.clients.RestApiClient
import de.tracetronic.jenkins.plugins.ecutestexecution.clients.RestApiClientFactory
import de.tracetronic.jenkins.plugins.ecutestexecution.actions.ProvideReportLogsAction
import de.tracetronic.jenkins.plugins.ecutestexecution.actions.ProvideLogsAction
import de.tracetronic.jenkins.plugins.ecutestexecution.clients.model.ApiException
import de.tracetronic.jenkins.plugins.ecutestexecution.clients.model.ReportInfo
import de.tracetronic.jenkins.plugins.ecutestexecution.util.PathUtil
Expand All @@ -21,24 +21,21 @@ import hudson.Launcher
import hudson.model.Run
import hudson.model.TaskListener
import hudson.util.ListBoxModel
import jenkins.model.Jenkins
import jenkins.security.MasterToSlaveCallable
import org.apache.commons.lang.StringUtils
import org.jenkinsci.plugins.workflow.steps.Step
import org.jenkinsci.plugins.workflow.steps.StepContext
import org.jenkinsci.plugins.workflow.steps.StepDescriptor
import org.jenkinsci.plugins.workflow.steps.StepExecution
import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution
import org.kohsuke.stapler.DataBoundConstructor

import java.text.SimpleDateFormat
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream

class ProvideReportLogsStep extends Step {
class ProvideLogsStep extends Step {

@DataBoundConstructor
ProvideReportLogsStep() {
ProvideLogsStep() {
super()
}

Expand All @@ -47,17 +44,13 @@ class ProvideReportLogsStep extends Step {
return new Execution(this, context)
}

private static List<String> removeEmptyReportIds(List<String> reportIds) {
return reportIds.findAll { id -> StringUtils.isNotBlank(id) }
}

static class Execution extends SynchronousNonBlockingStepExecution<Void> {

private static final long serialVersionUID = 1L

private final transient ProvideReportLogsStep step
private final transient ProvideLogsStep step

Execution(ProvideReportLogsStep step, StepContext context) {
Execution(ProvideLogsStep step, StepContext context) {
super(context)
this.step = step
}
Expand All @@ -83,25 +76,24 @@ class ProvideReportLogsStep extends Step {
def logDirPath = PathUtil.makeAbsoluteInPipelineHome("${logDirName}", context)

// Download report logs to workspace
List<String> logFiles = []
try {
logFiles = launcher.getChannel().call(
launcher.getChannel().call(
new ExecutionCallable(startTimeMillis, envVars, logDirPath, listener)
)
} catch (Exception e) {
throw e
}

if (workspace.child(logDirName).list().size() > 0 && logFiles) {
FilePath[] reportLogs = workspace.list("${logDirName}/*.log")
if (workspace.child(logDirName).list().size() > 0) {
FilePath[] reportLogs = workspace.list("${logDirName}/**/*.log")
def artifactsMap = new HashMap<String, String>()
reportLogs.each { log ->
def relativePath = log.getRemote().substring(workspace.getRemote().length() + 1)
artifactsMap.put(relativePath, relativePath)
}
listener.logger.println("Adding report logs to artifacts")
run.artifactManager.archive(workspace, launcher, listener, artifactsMap)
run.addAction(new ProvideReportLogsAction(run))
run.addAction(new ProvideLogsAction(run))

}
listener.logger.println("Cleaning report folder in jenkins workspace")
Expand All @@ -114,7 +106,6 @@ class ProvideReportLogsStep extends Step {

private static final long serialVersionUID = 1L

private List<String> reportIds
private final long startTimeMillis
private final EnvVars envVars
private final String logDirPath
Expand All @@ -131,31 +122,30 @@ class ProvideReportLogsStep extends Step {
/**
* Calls downloadReportFolder via the RestApiClient for all report ids.
* Then extracts and saves the ecu.test log out of the returned zip folder.
* Logs a warning if no reportIds were returned by ecu.test.
* Logs a warning if no reports were returned by ecu.test.
* @return List of strings containing the paths of the logs.
*/
@Override
List<String> call() throws IOException {
listener.logger.println("Providing ecu.test report logs to jenkins.")
listener.logger.println("Providing ecu.test logs to jenkins.")
List<String> logs = []
RestApiClient apiClient = RestApiClientFactory.getRestApiClient(envVars.get('ET_API_HOSTNAME'), envVars.get('ET_API_PORT'))
List<ReportInfo> reports = apiClient.getAllReports()

if (reports == null || reports.isEmpty()) {
listener.logger.println("[WARNING] No report files returned by ecu.test")
}
reports*.reportDir.each { String reportDir ->
for (def report : reports) {
String reportDir = report.reportDir.split('/').last()
if (!checkReportFolderCreationDate(reportDir)) {
listener.logger.println("[WARNING] ecu.test report folder includes files older than this run. ${reportDir}")
listener.logger.println("[WARNING] ecu.test report folder includes files older than this run. ${report.reportDir}")
}
}

reports*.testReportId.each { String reportId ->
listener.logger.println("Downloading reportFolder for ${reportId}")
listener.logger.println("Downloading reportFolder for ${report.testReportId}")
try {
File reportFolderZip = apiClient.downloadReportFolder(reportId)
File log = extractLogFileFromZip(reportFolderZip, "test/ecu.test_out.log", reportId)
logs.add(log.name)
File reportFolderZip = apiClient.downloadReportFolder(report.testReportId)
extractLogFileFromZip(reportFolderZip, "test/ecu.test_out.log", "${logDirPath}/${reportDir}/${reportDir}_test_out.log")
extractLogFileFromZip(reportFolderZip, "test/ecu.test_err.log", "${logDirPath}/${reportDir}/${reportDir}_test_err.log")
}
catch (ApiException e) {
if (e instanceof de.tracetronic.cxs.generated.et.client.v2.ApiException && e.code == 404) {
Expand Down Expand Up @@ -184,13 +174,12 @@ class ProvideReportLogsStep extends Step {
}
}

File extractLogFileFromZip(File reportFolderZip, String fileNameToExtract, String newName) {
File extractLogFileFromZip(File reportFolderZip, String fileNameToExtract, String saveToPath) {
ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(reportFolderZip))
ZipEntry entry
while ((entry = zipInputStream.nextEntry) != null) {
newName
if (entry.name == fileNameToExtract) {
File outputFile = new File("${logDirPath}/${newName}.log")
File outputFile = new File(saveToPath)
outputFile.parentFile.mkdirs()

def outputStream = new FileOutputStream(outputFile)
Expand All @@ -199,12 +188,11 @@ class ProvideReportLogsStep extends Step {
} finally {
outputStream.close()
}
listener.logger.println("Extracted ${fileNameToExtract} to ${logDirPath}")
zipInputStream.close()
return outputFile
}
}
throw new Exception("No ecu.test log not found in given report zip!")
throw new Exception("No ecu.test logs not found in given report zip!")
}
}

Expand All @@ -223,12 +211,12 @@ class ProvideReportLogsStep extends Step {

@Override
String getFunctionName() {
'ttProvideReportLogs'
'ttProvideLogs'
}

@Override
String getDisplayName() {
'[TT] Provide ecu.test report logs in jenkins.'
'[TT] Provide ecu.test logs in jenkins.'
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<l:main-panel>
<h1>${it.displayName}</h1>
<ul>
<j:forEach var="log" items="${it.reportLogs}">
<j:forEach var="log" items="${it.logs}">
<li>
<td>
<a href="${rootURL}/${it.run.url}artifact/${log.relativePath}">${log.fileName}</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class ETV1ContainerTest extends ETContainerTest {
.waitingFor(Wait.forHttp("/api/v1/live"))
}

def "Perform provide report logs step with reports"() {
def "Perform provide logs step with reports"() {
given: "a test execution pipeline"
String script = """
node {
Expand All @@ -55,7 +55,7 @@ class ETV1ContainerTest extends ETContainerTest {
WorkflowRun run = jenkins.buildAndAssertStatus(Result.FAILURE, job)

then: "expect successful test completion"
jenkins.assertLogContains("Providing ecu.test report logs to jenkins.", run)
jenkins.assertLogContains("Adding report logs to artifacts", run)
jenkins.assertLogContains("Providing ecu.test logs to jenkins.", run)
jenkins.assertLogContains("Downloading report folders is not supported by api v1. Use ecu.test > 2024.2 with api v2 instead.", run)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ class ETV2ContainerTest extends ETContainerTest {
.waitingFor(Wait.forHttp("/api/v2/live"))
}

def "Perform provide report logs step with no reports"() {
def "Perform provide logs step with no reports"() {
given: "a test execution pipeline"
String script = """
node {
withEnv(['ET_API_HOSTNAME=${etContainer.host}', 'ET_API_PORT=${etContainer.getMappedPort(ET_PORT)}']) {
ttProvideReportLogs()
ttProvideLogs()
}
}
""".stripIndent()
Expand All @@ -54,17 +54,17 @@ class ETV2ContainerTest extends ETContainerTest {
WorkflowRun run = jenkins.buildAndAssertStatus(Result.SUCCESS, job)

then: "expect successful test completion"
jenkins.assertLogContains("Providing ecu.test report logs to jenkins.", run)
jenkins.assertLogContains("Providing ecu.test logs to jenkins.", run)
jenkins.assertLogContains("[WARNING] No report files returned by ecu.test", run)
}

def "Perform provide report logs step with reports"() {
def "Perform provide logs step with reports"() {
given: "a test execution pipeline"
String script = """
node {
withEnv(['ET_API_HOSTNAME=${etContainer.host}', 'ET_API_PORT=${etContainer.getMappedPort(ET_PORT)}']) {
ttRunPackage testCasePath: 'test.pkg'
ttProvideReportLogs()
ttProvideLogs()
}
}
""".stripIndent()
Expand All @@ -74,7 +74,7 @@ class ETV2ContainerTest extends ETContainerTest {
WorkflowRun run = jenkins.buildAndAssertStatus(Result.SUCCESS, job)

then: "expect successful test completion"
jenkins.assertLogContains("Providing ecu.test report logs to jenkins.", run)
jenkins.assertLogContains("Adding report logs to artifacts", run)
jenkins.assertLogContains("Providing ecu.test logs to jenkins.", run)
jenkins.assertLogContains("Adding logs to artifacts", run)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.jenkinsci.plugins.workflow.job.WorkflowRun
import org.jenkinsci.plugins.workflow.steps.StepConfigTester
import org.jvnet.hudson.test.JenkinsRule

class ProvideReportLogStepIT extends IntegrationTestBase {
class ProvideLogStepIT extends IntegrationTestBase {
def setup() {
ETInstallation.DescriptorImpl etDescriptor = jenkins.jenkins
.getDescriptorByType(ETInstallation.DescriptorImpl.class)
Expand All @@ -21,27 +21,27 @@ class ProvideReportLogStepIT extends IntegrationTestBase {

def 'Default config round trip'() {
given:
ProvideReportLogsStep before = new ProvideReportLogsStep()
ProvideLogsStep before = new ProvideLogsStep()
when:
ProvideReportLogsStep after = new StepConfigTester(jenkins).configRoundTrip(before)
ProvideLogsStep after = new StepConfigTester(jenkins).configRoundTrip(before)
then:
jenkins.assertEqualDataBoundBeans(before, after)
}
def 'Snippet generator'() {
given:
SnippetizerTester st = new SnippetizerTester(jenkins)
when:
ProvideReportLogsStep step = new ProvideReportLogsStep()
ProvideLogsStep step = new ProvideLogsStep()
then:
st.assertRoundTrip(step, "ttProvideReportLogs()")
}

def 'Run pipeline'() {
given:
WorkflowJob job = jenkins.createProject(WorkflowJob.class, 'pipeline')
job.setDefinition(new CpsFlowDefinition("node {ttProvideReportLogs()}", true))
job.setDefinition(new CpsFlowDefinition("node {ttProvideLogs()}", true))
expect:
WorkflowRun run = jenkins.assertBuildStatus(Result.FAILURE, job.scheduleBuild2(0).get())
jenkins.assertLogContains("Providing ecu.test report logs to jenkins.", run)
jenkins.assertLogContains("Providing ecu.test logs to jenkins.", run)
}
}

0 comments on commit 2762e4c

Please sign in to comment.