diff --git a/pom.xml b/pom.xml index d20d1d70..0787fe2a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jenkins-ci.plugins plugin - 3.4 + 3.57 matlab @@ -20,7 +20,7 @@ - 2.7.3 + 2.164.3 8 @@ -52,14 +52,57 @@ http://github.com/jenkinsci/matlab-plugin HEAD - + + + + io.jenkins.tools.bom + bom-2.164.x + 4 + import + pom + + + - - - org.jenkins-ci.plugins - matrix-project - 1.14 - + + + + + org.jenkins-ci.plugins + matrix-project + + + + org.jenkins-ci.plugins.workflow + workflow-step-api + + + org.jenkins-ci.plugins.workflow + workflow-api + + + + + + org.jenkins-ci.plugins.workflow + workflow-basic-steps + test + + + org.jenkins-ci.plugins.workflow + workflow-cps + test + + + org.jenkins-ci.plugins.workflow + workflow-durable-task-step + test + + + org.jenkins-ci.plugins.workflow + workflow-job + test + diff --git a/src/main/java/com/mathworks/ci/MatlabStepExecution.java b/src/main/java/com/mathworks/ci/MatlabStepExecution.java new file mode 100644 index 00000000..dfffe258 --- /dev/null +++ b/src/main/java/com/mathworks/ci/MatlabStepExecution.java @@ -0,0 +1,82 @@ +package com.mathworks.ci; + +/** + * Copyright 2020 The MathWorks, Inc. + * + */ + +import java.io.IOException; +import org.jenkinsci.plugins.workflow.steps.StepContext; +import org.jenkinsci.plugins.workflow.steps.StepExecution; +import hudson.EnvVars; +import hudson.FilePath; +import hudson.Launcher; +import hudson.Launcher.ProcStarter; +import hudson.model.Result; +import hudson.model.TaskListener; + +public class MatlabStepExecution extends StepExecution implements MatlabBuild { + + private static final long serialVersionUID = 6704588180717665100L; + + private String command; + + + public MatlabStepExecution(StepContext context, String command) { + super(context); + this.command = command; + } + + private String getCommand() { + return this.command; + } + + @Override + public boolean start() throws Exception { + final Launcher launcher = getContext().get(Launcher.class); + final FilePath workspace = getContext().get(FilePath.class); + final TaskListener listener = getContext().get(TaskListener.class); + final EnvVars env = getContext().get(EnvVars.class); + + //Make sure the Workspace exists before run + + workspace.mkdirs(); + + int res = execMatlabCommand(workspace, launcher, listener, env); + + getContext().setResult((res == 0) ? Result.SUCCESS : Result.FAILURE); + + getContext().onSuccess(true); + + //return false represents the asynchronous run. + return false; + } + + @Override + public void stop(Throwable cause) throws Exception { + getContext().onFailure(cause); + } + + private synchronized int execMatlabCommand(FilePath workspace, Launcher launcher, + TaskListener listener, EnvVars envVars) throws IOException, InterruptedException { + final String uniqueTmpFldrName = getUniqueNameForRunnerFile(); + try { + ProcStarter matlabLauncher = getProcessToRunMatlabCommand(workspace, launcher, listener, envVars, + envVars.expand(getCommand()), uniqueTmpFldrName); + + + return matlabLauncher.join(); + } catch (Exception e) { + listener.getLogger().println(e.getMessage()); + return 1; + } finally { + // Cleanup the runner File from tmp directory + final FilePath matlabRunnerScript = + getFilePathForUniqueFolder(launcher, uniqueTmpFldrName, workspace); + if (matlabRunnerScript.exists()) { + matlabRunnerScript.deleteRecursive(); + } + } + + } +} diff --git a/src/main/java/com/mathworks/ci/RunMatlabCommandBuilder.java b/src/main/java/com/mathworks/ci/RunMatlabCommandBuilder.java index 9dbcf410..da289bfa 100644 --- a/src/main/java/com/mathworks/ci/RunMatlabCommandBuilder.java +++ b/src/main/java/com/mathworks/ci/RunMatlabCommandBuilder.java @@ -61,7 +61,7 @@ private EnvVars getEnv() { return this.env; } - @Symbol("RunMatlabCommand") + @Extension public static class RunMatlabCommandDescriptor extends BuildStepDescriptor { diff --git a/src/main/java/com/mathworks/ci/RunMatlabCommandStep.java b/src/main/java/com/mathworks/ci/RunMatlabCommandStep.java new file mode 100644 index 00000000..3b388185 --- /dev/null +++ b/src/main/java/com/mathworks/ci/RunMatlabCommandStep.java @@ -0,0 +1,58 @@ +package com.mathworks.ci; + +/** + * Copyright 2020 The MathWorks, Inc. + * + */ + +import java.util.Set; +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.kohsuke.stapler.DataBoundConstructor; +import com.google.common.collect.ImmutableSet; +import hudson.EnvVars; +import hudson.Extension; +import hudson.FilePath; +import hudson.Launcher; +import hudson.model.Run; +import hudson.model.TaskListener; + +public class RunMatlabCommandStep extends Step { + + + private String command; + + @DataBoundConstructor + public RunMatlabCommandStep(String command) { + this.command = command; + } + + + public String getCommand() { + return this.command; + } + + @Override + public StepExecution start(StepContext context) throws Exception { + return new MatlabStepExecution(context, getCommand()); + } + + @Extension + public static class CommandStepDescriptor extends StepDescriptor { + + @Override + public Set> getRequiredContext() { + return ImmutableSet.of(TaskListener.class, FilePath.class, Launcher.class, + EnvVars.class, Run.class); + } + + @Override + public String getFunctionName() { + return Message.getValue("matlab.command.build.step.name"); + } + } +} + + diff --git a/src/main/java/com/mathworks/ci/RunMatlabTestsBuilder.java b/src/main/java/com/mathworks/ci/RunMatlabTestsBuilder.java index 93840829..3c4a8ee3 100644 --- a/src/main/java/com/mathworks/ci/RunMatlabTestsBuilder.java +++ b/src/main/java/com/mathworks/ci/RunMatlabTestsBuilder.java @@ -185,7 +185,7 @@ protected Object readResolve() { } - @Symbol("RunMatlabTests") + @Extension public static class RunMatlabTestsDescriptor extends BuildStepDescriptor { diff --git a/src/main/java/com/mathworks/ci/RunMatlabTestsStep.java b/src/main/java/com/mathworks/ci/RunMatlabTestsStep.java new file mode 100644 index 00000000..603b8d9f --- /dev/null +++ b/src/main/java/com/mathworks/ci/RunMatlabTestsStep.java @@ -0,0 +1,180 @@ +package com.mathworks.ci; +/** + * Copyright 2020 The MathWorks, Inc. + * + */ +import java.io.IOException; +import java.io.InputStream; + +/** + * Copyright 2020 The MathWorks, Inc. + * + */ + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.apache.commons.io.FilenameUtils; +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.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; +import com.google.common.collect.ImmutableSet; +import hudson.EnvVars; +import hudson.Extension; +import hudson.FilePath; +import hudson.Launcher; +import hudson.model.Run; +import hudson.model.TaskListener; + +public class RunMatlabTestsStep extends Step { + + private String testResultsPDF; + private String testResultsTAP; + private String testResultsJUnit; + private String codeCoverageCobertura; + private String testResultsSimulinkTest; + private String modelCoverageCobertura; + + + @DataBoundConstructor + public RunMatlabTestsStep() { + + } + + public String getTestResultsTAP() { + return testResultsTAP; + } + + @DataBoundSetter + public void setTestResultsTAP(String testResultsTAP) { + this.testResultsTAP = testResultsTAP; + } + + public String getTestResultsPDF() { + return testResultsPDF; + } + + @DataBoundSetter + public void setTestResultsPDF(String testResultsPDF) { + this.testResultsPDF = testResultsPDF; + } + + public String getTestResultsJUnit() { + return testResultsJUnit; + } + + @DataBoundSetter + public void setTestResultsJUnit(String testResultsJUnit) { + this.testResultsJUnit = testResultsJUnit; + } + + public String getCodeCoverageCobertura() { + return codeCoverageCobertura; + } + + @DataBoundSetter + public void setCodeCoverageCobertura(String codeCoverageCobertura) { + this.codeCoverageCobertura = codeCoverageCobertura; + } + + public String getTestResultsSimulinkTest() { + return testResultsSimulinkTest; + } + + @DataBoundSetter + public void setTestResultsSimulinkTest(String testResultsSimulinkTest) { + this.testResultsSimulinkTest = testResultsSimulinkTest; + } + + public String getModelCoverageCobertura() { + return modelCoverageCobertura; + } + + + @DataBoundSetter + public void setModelCoverageCobertura(String modelCoverageCobertura) { + this.modelCoverageCobertura = modelCoverageCobertura; + } + + + @Override + public StepExecution start(StepContext context) throws Exception { + Launcher launcher = context.get(Launcher.class); + FilePath workspace = context.get(FilePath.class); + + //Copy Scratch file needed to run MATLAB tests in workspace + FilePath targetWorkspace = new FilePath(launcher.getChannel(), workspace.getRemote()); + copyScratchFileInWorkspace(MatlabBuilderConstants.MATLAB_TESTS_RUNNER_RESOURCE, + MatlabBuilderConstants.MATLAB_TESTS_RUNNER_TARGET_FILE, targetWorkspace); + return new MatlabStepExecution(context,constructCommandForTest(getInputArgs())); + } + + @Extension + public static class RunTestsStepDescriptor extends StepDescriptor { + + @Override + public Set> getRequiredContext() { + return ImmutableSet.of(TaskListener.class, FilePath.class, Launcher.class, + EnvVars.class, Run.class); + } + + @Override + public String getFunctionName() { + return Message.getValue("matlab.tests.build.step.name"); + } + } + + public String constructCommandForTest(String inputArguments) { + final String matlabFunctionName = + FilenameUtils.removeExtension(MatlabBuilderConstants.MATLAB_TESTS_RUNNER_TARGET_FILE); + final String runCommand = "exit(" + matlabFunctionName + "(" + inputArguments + "))"; + return runCommand; + } + + + private String getInputArgs() { + final List inputArgs = new ArrayList<>(); + final Map args = getMatlabArgs(); + + args.forEach((key, val) -> { + if (val != null) { + inputArgs.add("'" + key + "'" + "," + "'" + val.replaceAll("'", "''") + "'"); + } + }); + + if (inputArgs.isEmpty()) { + return ""; + } + + return String.join(",", inputArgs); + } + + private Map getMatlabArgs() { + final Map args = new HashMap(); + args.put("PDFReportPath", getTestResultsPDF()); + args.put("TAPResultsPath", getTestResultsTAP()); + args.put("JUnitResultsPath", getTestResultsJUnit()); + args.put("SimulinkTestResultsPath", getTestResultsSimulinkTest()); + args.put("CoberturaCodeCoveragePath", getCodeCoverageCobertura()); + args.put("CoberturaModelCoveragePath", getModelCoverageCobertura()); + return args; + } + + /* + * Method to copy given file from source to target node specific workspace. + */ + private void copyScratchFileInWorkspace(String sourceFile, String targetFile, FilePath targetWorkspace) + throws IOException, InterruptedException { + final ClassLoader classLoader = getClass().getClassLoader(); + FilePath targetFilePath = new FilePath(targetWorkspace, targetFile); + InputStream in = classLoader.getResourceAsStream(sourceFile); + targetFilePath.copyFrom(in); + // set executable permission + targetFilePath.chmod(0755); + } +} diff --git a/src/main/java/com/mathworks/ci/UseMatlabVersionBuildWrapper.java b/src/main/java/com/mathworks/ci/UseMatlabVersionBuildWrapper.java index cf6a2eb0..b5a2702d 100644 --- a/src/main/java/com/mathworks/ci/UseMatlabVersionBuildWrapper.java +++ b/src/main/java/com/mathworks/ci/UseMatlabVersionBuildWrapper.java @@ -56,7 +56,7 @@ private void setEnv(EnvVars env) { this.env = env; } - @Symbol("Matlab") + @Extension public static final class UseMatlabVersionDescriptor extends BuildWrapperDescriptor { diff --git a/src/main/resources/com/mathworks/ci/RunMatlabCommandStep/config.jelly b/src/main/resources/com/mathworks/ci/RunMatlabCommandStep/config.jelly new file mode 100644 index 00000000..28414b78 --- /dev/null +++ b/src/main/resources/com/mathworks/ci/RunMatlabCommandStep/config.jelly @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/com/mathworks/ci/RunMatlabTestsStep/config.jelly b/src/main/resources/com/mathworks/ci/RunMatlabTestsStep/config.jelly new file mode 100644 index 00000000..564268fd --- /dev/null +++ b/src/main/resources/com/mathworks/ci/RunMatlabTestsStep/config.jelly @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/config.properties b/src/main/resources/config.properties index 7cf08e48..3c9c1dd1 100644 --- a/src/main/resources/config.properties +++ b/src/main/resources/config.properties @@ -16,4 +16,6 @@ Builder.matlab.modelcoverage.support.warning = To generate a Cobertura model cov Builder.matlab.exportstmresults.support.warning = To export Simulink Test Manager results, use MATLAB R2019a or a newer release. Builder.matlab.runner.script.target.file.linux.name = run_matlab_command.sh Builder.matlab.runner.script.target.file.windows.name = run_matlab_command.bat -build.workspace.computer.not.found = Unable to access the computer for this build. \ No newline at end of file +build.workspace.computer.not.found = Unable to access the computer for this build. +matlab.command.build.step.name = runMATLABCommand +matlab.tests.build.step.name = runMATLABTests \ No newline at end of file diff --git a/src/test/java/com/mathworks/ci/RunMatlabCommandStepTest.java b/src/test/java/com/mathworks/ci/RunMatlabCommandStepTest.java new file mode 100644 index 00000000..36fe579c --- /dev/null +++ b/src/test/java/com/mathworks/ci/RunMatlabCommandStepTest.java @@ -0,0 +1,107 @@ +package com.mathworks.ci; +/** + * Copyright 2020 The MathWorks, Inc. + * + */ + +import java.io.IOException; +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; +import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; +import hudson.FilePath; +import hudson.slaves.DumbSlave; + +public class RunMatlabCommandStepTest { + + + private WorkflowJob project; + + + + @Rule + public JenkinsRule j = new JenkinsRule(); + + @Before + public void testSetup() throws IOException { + this.project = j.createProject(WorkflowJob.class); + } + + + /* + * Verify when MATLAB is not in PATH variable. + */ + + @Test + public void verifyMATLABPathNotSet() throws Exception { + project.setDefinition( + new CpsFlowDefinition("node { runMATLABCommand(command: 'pwd')}", true)); + WorkflowRun build = project.scheduleBuild2(0).get(); + j.assertLogContains("MATLAB_ROOT", build); + } + + /* + * Verify MATLAB is invoked when valid MATLAB is in PATH. + * + */ + + @Test + public void verifyMATLABPathSet() throws Exception { + project.setDefinition( + new CpsFlowDefinition("node { testMATLABCommand(command: 'pwd')}", true)); + WorkflowRun build = project.scheduleBuild2(0).get(); + j.assertLogContains("tester_started", build); + } + + /* + * Verify Pipeline script runs on Slave with valid MATLAB + * + */ + + @Test + public void verifyPipelineOnSlave() throws Exception { + DumbSlave s = j.createOnlineSlave(); + project.setDefinition(new CpsFlowDefinition( + "node('!master') { testMATLABCommand(command: 'pwd')}", + true)); + + s.getWorkspaceFor(project); + WorkflowRun build = project.scheduleBuild2(0).get(); + + j.assertBuildStatusSuccess(build); + } + + /* + * Verify appropriate command is invoked as in pipeline script + * + */ + + @Test + public void verifyCommandSameAsScript() throws Exception { + project.setDefinition( + new CpsFlowDefinition("node { runMATLABCommand(command: 'pwd')}", true)); + + WorkflowRun build = project.scheduleBuild2(0).get(); + j.assertLogContains("pwd", build); + } + + /* + * Verify script can run Matrix build + * + */ + + @Test + public void verifyMatrixBuild() throws Exception { + project.setDefinition(new CpsFlowDefinition( + "node { matrix {\n" + "agent any\n" + "axes {\n" + "axis {\n" + "name: 'CMD'\n" + + "values: 'pwd','ver'\n }}\n" + "runMATLABCommand(command: '${CMD}')}}", + true)); + + WorkflowRun build = project.scheduleBuild2(0).get(); + j.assertLogContains("pwd", build); + j.assertLogContains("ver", build); + } +} diff --git a/src/test/java/com/mathworks/ci/RunMatlabCommandStepTester.java b/src/test/java/com/mathworks/ci/RunMatlabCommandStepTester.java new file mode 100644 index 00000000..ed51a0ae --- /dev/null +++ b/src/test/java/com/mathworks/ci/RunMatlabCommandStepTester.java @@ -0,0 +1,48 @@ +package com.mathworks.ci; + +/** + * Copyright 2020 The MathWorks, Inc. + * + */ + +import java.util.Set; +import org.jenkinsci.plugins.workflow.steps.StepContext; +import org.jenkinsci.plugins.workflow.steps.StepDescriptor; +import org.jenkinsci.plugins.workflow.steps.StepExecution; +import org.kohsuke.stapler.DataBoundConstructor; +import com.google.common.collect.ImmutableSet; +import hudson.EnvVars; +import hudson.Extension; +import hudson.FilePath; +import hudson.Launcher; +import hudson.model.Run; +import hudson.model.TaskListener; + +public class RunMatlabCommandStepTester extends RunMatlabCommandStep { + @DataBoundConstructor + public RunMatlabCommandStepTester(String command) { + super(command); + } + + @Override + public StepExecution start(StepContext context) throws Exception { + + return new TestStepExecution(context,this.getCommand()); + } + + @Extension + public static class CommandStepTestDescriptor extends StepDescriptor { + + @Override + public Set> getRequiredContext() { + return ImmutableSet.of(TaskListener.class, FilePath.class, Launcher.class, + EnvVars.class, Run.class); + } + + @Override + public String getFunctionName() { + return "testMATLABCommand"; + } + } + +} diff --git a/src/test/java/com/mathworks/ci/RunMatlabTestsStepTest.java b/src/test/java/com/mathworks/ci/RunMatlabTestsStepTest.java new file mode 100644 index 00000000..6501ea2f --- /dev/null +++ b/src/test/java/com/mathworks/ci/RunMatlabTestsStepTest.java @@ -0,0 +1,115 @@ +package com.mathworks.ci; + +/** + * Copyright 2020 The MathWorks, Inc. + * + */ + +import java.io.IOException; +import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; +import org.jenkinsci.plugins.workflow.job.WorkflowJob; +import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; +import hudson.slaves.DumbSlave; + +public class RunMatlabTestsStepTest { + + private WorkflowJob project; + + @Rule + public JenkinsRule j = new JenkinsRule(); + + @Before + public void testSetup() throws IOException { + this.project = j.createProject(WorkflowJob.class); + } + + + /* + * Verify when MATLAB Path is not set + */ + @Test + public void verifyMATLABPathNotSet() throws Exception { + project.setDefinition(new CpsFlowDefinition( + "node {runMATLABTests(testResultsPDF:'myresult/result.pdf')}", true)); + WorkflowRun build = project.scheduleBuild2(0).get(); + j.assertLogContains("MATLAB_ROOT", build); + } + + + /* + * VErify when MATLAB PATH is set. + */ + + @Test + public void verifyMATLABPathSet() throws Exception { + project.setDefinition(new CpsFlowDefinition( + "node {testMATLABTests(testResultsPDF:'myresult/result.pdf')}", true)); + WorkflowRun build = project.scheduleBuild2(0).get(); + j.assertLogContains("tester_started", build); + } + + /* + * Verify Pipeline runs on slave node + */ + + @Test + public void verifyOnslave() throws Exception { + DumbSlave s = j.createOnlineSlave(); + project.setDefinition(new CpsFlowDefinition( + "node('!master') {testMATLABTests(testResultsPDF:'myresult/result.pdf')}", true)); + s.getWorkspaceFor(project); + WorkflowRun build = project.scheduleBuild2(0).get(); + j.assertBuildStatusSuccess(build); + } + + /* + * Verify artifact path is correct. + */ + + @Test + public void verifyArtifactPath() throws Exception { + project.setDefinition(new CpsFlowDefinition( + "node {runMATLABTests(testResultsPDF:'myresult/result.pdf')}", true)); + WorkflowRun build = project.scheduleBuild2(0).get(); + j.assertLogContains("'PDFReportPath','myresult/result.pdf'", build); + } + + /* + * Verify Artifact is not sent as parameter if not selected in script. + */ + + @Test + public void verifyArtifactParameters() throws Exception { + project.setDefinition(new CpsFlowDefinition( + "node {runMATLABTests(testResultsPDF:'myresult/result.pdf')}", true)); + WorkflowRun build = project.scheduleBuild2(0).get(); + j.assertLogContains("'PDFReportPath','myresult/result.pdf'", build); + j.assertLogNotContains("TAPResultsPath", build); + j.assertLogNotContains("JUnitResultsPath", build); + j.assertLogNotContains("CoberturaCodeCoveragePath", build); + j.assertLogNotContains("SimulinkTestResultsPath", build); + j.assertLogNotContains("CoberturaModelCoveragePath", build); + } + + /* + * Verify runMatlabTests runs with empty parameters when nothing no artifact selected + */ + + @Test + public void verifyEmptyParameter() throws Exception { + project.setDefinition(new CpsFlowDefinition( + "node {runMATLABTests()}", true)); + WorkflowRun build = project.scheduleBuild2(0).get(); + j.assertLogContains("runMatlabTests()", build); + j.assertLogNotContains("PDFReportPath", build); + j.assertLogNotContains("TAPResultsPath", build); + j.assertLogNotContains("JUnitResultsPath", build); + j.assertLogNotContains("CoberturaCodeCoveragePath", build); + j.assertLogNotContains("SimulinkTestResultsPath", build); + j.assertLogNotContains("CoberturaModelCoveragePath", build); + } +} diff --git a/src/test/java/com/mathworks/ci/RunMatlabTestsStepTester.java b/src/test/java/com/mathworks/ci/RunMatlabTestsStepTester.java new file mode 100644 index 00000000..60a38311 --- /dev/null +++ b/src/test/java/com/mathworks/ci/RunMatlabTestsStepTester.java @@ -0,0 +1,72 @@ +package com.mathworks.ci; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import org.jenkinsci.plugins.workflow.steps.StepContext; +import org.jenkinsci.plugins.workflow.steps.StepDescriptor; +import org.jenkinsci.plugins.workflow.steps.StepExecution; +import org.kohsuke.stapler.DataBoundConstructor; +import com.google.common.collect.ImmutableSet; +import hudson.EnvVars; +import hudson.Extension; +import hudson.FilePath; +import hudson.Launcher; +import hudson.model.Run; +import hudson.model.TaskListener; + +public class RunMatlabTestsStepTester extends RunMatlabTestsStep { + + + @DataBoundConstructor + public RunMatlabTestsStepTester() { + + } + + @Override + public StepExecution start(StepContext context) throws Exception { + Launcher launcher = context.get(Launcher.class); + FilePath workspace = context.get(FilePath.class); + + // Copy Scratch file needed to run MATLAB tests in workspace + FilePath targetWorkspace = new FilePath(launcher.getChannel(), workspace.getRemote()); + copyScratchFileInWorkspace(MatlabBuilderConstants.MATLAB_TESTS_RUNNER_RESOURCE, + MatlabBuilderConstants.MATLAB_TESTS_RUNNER_TARGET_FILE, targetWorkspace); + return new TestStepExecution(context, constructCommandForTest(getInputArgs())); + } + + private void copyScratchFileInWorkspace(String sourceFile, String targetFile, + FilePath targetWorkspace) throws IOException, InterruptedException { + final ClassLoader classLoader = getClass().getClassLoader(); + FilePath targetFilePath = new FilePath(targetWorkspace, targetFile); + InputStream in = classLoader.getResourceAsStream(sourceFile); + targetFilePath.copyFrom(in); + // set executable permission + targetFilePath.chmod(0755); + } + + @Extension + public static class CommandStepTestDescriptor extends StepDescriptor { + + @Override + public Set> getRequiredContext() { + return ImmutableSet.of(TaskListener.class, FilePath.class, Launcher.class, + EnvVars.class, Run.class); + } + + @Override + public String getFunctionName() { + return "testMATLABTests"; + } + } + + public String getInputArgs() { + List args = Arrays.asList(getTestResultsPDF(), getTestResultsTAP(), + getTestResultsJUnit(), getTestResultsSimulinkTest(), getCodeCoverageCobertura(), + getModelCoverageCobertura()); + + return String.join(",", args); + } +} diff --git a/src/test/java/com/mathworks/ci/TestStepExecution.java b/src/test/java/com/mathworks/ci/TestStepExecution.java new file mode 100644 index 00000000..aa840f6c --- /dev/null +++ b/src/test/java/com/mathworks/ci/TestStepExecution.java @@ -0,0 +1,48 @@ +package com.mathworks.ci; +/** + * Copyright 2020 The MathWorks, Inc. + * + */ + +import java.io.IOException; +import org.jenkinsci.plugins.workflow.steps.StepContext; +import hudson.EnvVars; +import hudson.FilePath; +import hudson.Launcher; +import hudson.Launcher.ProcStarter; +import hudson.model.TaskListener; + +public class TestStepExecution extends MatlabStepExecution { + + public TestStepExecution(StepContext context, String command) { + super(context, command); + + } + + @Override + public ProcStarter getProcessToRunMatlabCommand(FilePath workspace, Launcher launcher, + TaskListener listener, EnvVars envVars, String matlabCommand, String uniqueName) + throws IOException, InterruptedException { + // Get node specific tmp directory to copy matlab runner script + String tmpDir = getNodeSpecificTmpFolderPath(workspace); + FilePath targetWorkspace = new FilePath(launcher.getChannel(), tmpDir); + ProcStarter matlabLauncher; + if (launcher.isUnix()) { + final String runnerScriptName = uniqueName + "/run_matlab_command_test.sh"; + matlabLauncher = launcher.launch().pwd(workspace).envs(envVars) + .cmds(tmpDir + "/" + runnerScriptName, matlabCommand).stdout(listener); + + // Copy runner .sh for linux platform in workspace. + copyFileInWorkspace("run_matlab_command_test.sh", runnerScriptName, targetWorkspace); + } else { + final String runnerScriptName = uniqueName + "\\run_matlab_command_test.bat"; + launcher = launcher.decorateByPrefix("cmd.exe", "/C"); + matlabLauncher = launcher.launch().pwd(workspace).envs(envVars) + .cmds(tmpDir + "\\" + runnerScriptName, "\"" + matlabCommand + "\"") + .stdout(listener); + // Copy runner.bat for Windows platform in workspace. + copyFileInWorkspace("run_matlab_command_test.bat", runnerScriptName, targetWorkspace); + } + return matlabLauncher; + } +} diff --git a/src/test/resources/run_matlab_command_test.bat b/src/test/resources/run_matlab_command_test.bat new file mode 100755 index 00000000..f17d2e8a --- /dev/null +++ b/src/test/resources/run_matlab_command_test.bat @@ -0,0 +1,7 @@ +rem Copyright 2020 The MathWorks, Inc. + +echo "tester_started" + +set "arg1=%~1" + +echo "%arg1%" diff --git a/src/test/resources/run_matlab_command_test.sh b/src/test/resources/run_matlab_command_test.sh new file mode 100755 index 00000000..1d0ddcaa --- /dev/null +++ b/src/test/resources/run_matlab_command_test.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +#Copyright 2020 The MathWorks, Inc. + +echo "tester_started" +echo $1