Skip to content
This repository was archived by the owner on Mar 27, 2025. It is now read-only.

Commit 6548b9e

Browse files
authored
Merge pull request #43 from mathworks/CI-78-remote-agent-support-minimal
Added changes to support running MATLAB on remote agents.
2 parents e824674 + 84602d8 commit 6548b9e

File tree

5 files changed

+67
-43
lines changed

5 files changed

+67
-43
lines changed

src/main/java/com/mathworks/ci/MatlabBuilder.java

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public class MatlabBuilder extends Builder implements SimpleBuildStep {
6060
private static final String MATLAB_RUNNER_RESOURCE =
6161
"com/mathworks/ci/MatlabBuilder/runMatlabTests.m";
6262
private static final String AUTOMATIC_OPTION = "RunTestsAutomaticallyOption";
63+
private String nodeSpecificfileSeparator;
6364

6465

6566
@DataBoundConstructor
@@ -101,6 +102,7 @@ private String getCustomMatlabCommand() {
101102
private void setEnv(EnvVars env) {
102103
this.env = env;
103104
}
105+
104106

105107
@Extension
106108
public static class MatlabDescriptor extends BuildStepDescriptor<Builder> {
@@ -190,14 +192,15 @@ public FormValidation getFirstErrorOrWarning(
190192
final MatrixPatternResolver resolver = new MatrixPatternResolver(matlabRoot);
191193
if (!resolver.hasVariablePattern()) {
192194
try {
193-
rel = new MatlabReleaseInfo(matlabRoot);
195+
FilePath matlabRootPath = new FilePath(new File(matlabRoot));
196+
rel = new MatlabReleaseInfo(matlabRootPath);
194197
if (rel.verLessThan(BASE_MATLAB_VERSION_RUNTESTS_SUPPORT)) {
195198
return FormValidation
196199
.error(Message.getValue("Builder.matlab.test.support.error"));
197200
}
198201
} catch (MatlabVersionNotFoundException e) {
199202
return FormValidation
200-
.error(Message.getValue("Builder.invalid.matlab.root.error"));
203+
.warning(Message.getValue("Builder.invalid.matlab.root.warning"));
201204
}
202205
}
203206
return FormValidation.ok();
@@ -257,7 +260,8 @@ public FormValidation doCheckTaCoberturaChkBx(@QueryParameter boolean taCobertur
257260
}
258261

259262
Function<String, FormValidation> chkCoberturaSupport = (String matlabRoot) -> {
260-
rel = new MatlabReleaseInfo(matlabRoot);
263+
FilePath matlabRootPath = new FilePath(new File(matlabRoot));
264+
rel = new MatlabReleaseInfo(matlabRootPath);
261265
final MatrixPatternResolver resolver = new MatrixPatternResolver(matlabRoot);
262266
if(!resolver.hasVariablePattern()) {
263267
try {
@@ -266,7 +270,7 @@ public FormValidation doCheckTaCoberturaChkBx(@QueryParameter boolean taCobertur
266270
.warning(Message.getValue("Builder.matlab.cobertura.support.warning"));
267271
}
268272
} catch (MatlabVersionNotFoundException e) {
269-
return FormValidation.error(Message.getValue("Builder.invalid.matlab.root.error"));
273+
return FormValidation.warning(Message.getValue("Builder.invalid.matlab.root.warning"));
270274
}
271275
}
272276

@@ -393,40 +397,44 @@ public String getStringByName(String memberName) {
393397
public void perform(@Nonnull Run<?, ?> build, @Nonnull FilePath workspace,
394398
@Nonnull Launcher launcher, @Nonnull TaskListener listener)
395399
throws InterruptedException, IOException {
396-
final boolean isLinuxLauncher = launcher.isUnix();
400+
//Set the environment variable specific to the this build
401+
setEnv(build.getEnvironment(listener));
402+
nodeSpecificfileSeparator = getNodeSpecificFileSeperator(launcher);
397403

398404
// Invoke MATLAB command and transfer output to standard
399405
// Output Console
400406

401-
buildResult = execMatlabCommand(build, workspace, launcher, listener, isLinuxLauncher);
407+
buildResult = execMatlabCommand(workspace, launcher, listener);
402408

403409
if (buildResult != 0) {
404410
build.setResult(Result.FAILURE);
405411
}
406412
}
407413

408-
private synchronized int execMatlabCommand(Run<?, ?> build, FilePath workspace, Launcher launcher,
409-
TaskListener listener, boolean isLinuxLauncher)
414+
private synchronized int execMatlabCommand(FilePath workspace, Launcher launcher,
415+
TaskListener listener)
410416
throws IOException, InterruptedException {
411-
setEnv(build.getEnvironment(listener));
412-
final String testRunMode = this.getTestRunTypeList().getDescriptor().getId();
413-
414-
// Copy MATLAB scratch file into the workspace only if Automatic option is selected.
415-
if (testRunMode.contains(AUTOMATIC_OPTION)) {
416-
copyMatlabScratchFileInWorkspace(MATLAB_RUNNER_RESOURCE, MATLAB_RUNNER_TARGET_FILE,
417-
workspace, getClass().getClassLoader());
418-
}
419417
ProcStarter matlabLauncher;
420418
try {
421-
MatlabReleaseInfo rel = new MatlabReleaseInfo(getLocalMatlab());
419+
FilePath nodeSpecificMatlabRoot = new FilePath(launcher.getChannel(),getLocalMatlab());
420+
MatlabReleaseInfo rel = new MatlabReleaseInfo(nodeSpecificMatlabRoot);
422421
matlabLauncher = launcher.launch().pwd(workspace).envs(this.env);
423422
if (rel.verLessThan(BASE_MATLAB_VERSION_BATCH_SUPPORT)) {
424423
ListenerLogDecorator outStream = new ListenerLogDecorator(listener);
425-
matlabLauncher = matlabLauncher.cmds(constructDefaultMatlabCommand(isLinuxLauncher)).stderr(outStream);
424+
matlabLauncher = matlabLauncher.cmds(constructDefaultMatlabCommand(launcher.isUnix())).stderr(outStream);
426425
} else {
427426
matlabLauncher = matlabLauncher.cmds(constructMatlabCommandWithBatch()).stdout(listener);
428427
}
429-
} catch (MatlabVersionNotFoundException e) {
428+
429+
//Check the test run mode option selected by user and identify the target workspace to copy the scratch file.
430+
final String testRunMode = this.getTestRunTypeList().getDescriptor().getId();
431+
432+
// Copy MATLAB scratch file into the workspace only if Automatic option is selected.
433+
if (testRunMode.contains(AUTOMATIC_OPTION)) {
434+
FilePath targetWorkspace = new FilePath(launcher.getChannel(), workspace.getRemote());
435+
copyMatlabScratchFileInWorkspace(MATLAB_RUNNER_RESOURCE, MATLAB_RUNNER_TARGET_FILE, targetWorkspace);
436+
}
437+
} catch (Exception e) {
430438
listener.getLogger().println(e.getMessage());
431439
return 1;
432440
}
@@ -450,7 +458,7 @@ public List<String> constructMatlabCommandWithBatch() {
450458
}
451459

452460
matlabDefaultArgs =
453-
Arrays.asList(getLocalMatlab() + File.separator + "bin" + File.separator + "matlab",
461+
Arrays.asList(getLocalMatlab() + nodeSpecificfileSeparator + "bin" + nodeSpecificfileSeparator + "matlab",
454462
"-batch", runCommand);
455463

456464
return matlabDefaultArgs;
@@ -473,7 +481,7 @@ public List<String> constructDefaultMatlabCommand(boolean isLinuxLauncher) {
473481

474482
private String[] getPreRunnerSwitches() {
475483
String[] preRunnerSwitches =
476-
{getLocalMatlab() + File.separator + "bin" + File.separator + "matlab", "-nosplash",
484+
{getLocalMatlab() + nodeSpecificfileSeparator + "bin" + nodeSpecificfileSeparator + "matlab", "-nosplash",
477485
"-nodesktop", "-noAppIcon"};
478486
return preRunnerSwitches;
479487
}
@@ -504,13 +512,22 @@ private String[] getRunnerSwitch() {
504512
}
505513

506514
private void copyMatlabScratchFileInWorkspace(String matlabRunnerResourcePath,
507-
String matlabRunnerTarget, FilePath workspace, ClassLoader classLoader)
515+
String matlabRunnerTarget, FilePath targetWorkspace)
508516
throws IOException, InterruptedException {
517+
final ClassLoader classLoader = getClass().getClassLoader();
518+
FilePath targetFile =
519+
new FilePath(targetWorkspace, Message.getValue(matlabRunnerTarget));
509520
InputStream in = classLoader.getResourceAsStream(matlabRunnerResourcePath);
510-
Path target =
511-
new File(workspace.getRemote(), Message.getValue(matlabRunnerTarget)).toPath();
512521

513-
Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING);
522+
targetFile.copyFrom(in);
523+
}
524+
525+
private String getNodeSpecificFileSeperator(Launcher launcher) {
526+
if (launcher.isUnix()) {
527+
return "/";
528+
} else {
529+
return "\\";
530+
}
514531
}
515532

516533
}

src/main/java/com/mathworks/ci/MatlabReleaseInfo.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,25 @@
66
*/
77

88
import java.io.File;
9+
import java.io.IOException;
910
import java.nio.file.NotDirectoryException;
1011
import java.util.HashMap;
1112
import java.util.Map;
1213
import javax.xml.parsers.DocumentBuilder;
1314
import javax.xml.parsers.DocumentBuilderFactory;
1415
import org.apache.commons.collections.MapUtils;
16+
import org.jenkinsci.remoting.RoleChecker;
1517
import org.w3c.dom.Document;
1618
import org.w3c.dom.Element;
1719
import org.w3c.dom.Node;
1820
import org.w3c.dom.NodeList;
1921
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
22+
import hudson.FilePath;
23+
import hudson.FilePath.FileCallable;
24+
import hudson.remoting.VirtualChannel;
2025

2126
public class MatlabReleaseInfo {
22-
private String matlabRoot;
27+
private FilePath matlabRoot;
2328
private static final String VERSION_INFO_FILE = "VersionInfo.xml";
2429
private static final String VERSION_INFO_ROOT_TAG = "MathWorks_version_info";
2530
private static final String RELEASE_TAG = "release";
@@ -34,8 +39,8 @@ public class MatlabReleaseInfo {
3439
};
3540

3641
private Map<String, String> versionInfoCache = new HashMap<String, String>();
37-
38-
public MatlabReleaseInfo(String matlabRoot) {
42+
43+
public MatlabReleaseInfo(FilePath matlabRoot) {
3944
this.matlabRoot = matlabRoot;
4045
}
4146

@@ -73,12 +78,12 @@ public boolean verLessThan(double version) throws MatlabVersionNotFoundException
7378
private Map<String, String> getVersionInfoFromFile() throws MatlabVersionNotFoundException {
7479
if (MapUtils.isEmpty(versionInfoCache)) {
7580
try {
76-
File versionFile = new File(this.matlabRoot + File.separator + VERSION_INFO_FILE);
77-
if(versionFile.isFile()) {
81+
FilePath versionFile = new FilePath(this.matlabRoot, VERSION_INFO_FILE);
82+
if(versionFile.exists()) {
7883
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
7984
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
80-
Document doc = dBuilder.parse(versionFile);
81-
85+
Document doc = dBuilder.parse(versionFile.read());
86+
8287
doc.getDocumentElement().normalize();
8388
NodeList nList = doc.getElementsByTagName(VERSION_INFO_ROOT_TAG);
8489

@@ -99,7 +104,7 @@ private Map<String, String> getVersionInfoFromFile() throws MatlabVersionNotFoun
99104
}
100105
}
101106
}
102-
else if(!new File(this.matlabRoot).exists()){
107+
else if(!this.matlabRoot.exists()){
103108
throw new NotDirectoryException("Invalid matlabroot path");
104109
}else {
105110
versionInfoCache.putAll(VERSION_OLDER_THAN_17A);
@@ -112,4 +117,4 @@ else if(!new File(this.matlabRoot).exists()){
112117
}
113118
return versionInfoCache;
114119
}
115-
}
120+
}

src/main/resources/config.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
Builder.display.name = Run MATLAB Tests
55
Builder.matlab.runner.target.file.name = runMatlabTests.m
6-
Builder.matlab.cobertura.support.warning = To generate a Cobertura report, use MATLAB R2017b or a newer version.
7-
Builder.invalid.matlab.root.error = Unable to launch MATLAB from the specified location. Verify the MATLAB root folder path.
6+
Builder.matlab.cobertura.support.warning = To generate a Cobertura report, use MATLAB R2017b or a newer release.
7+
Builder.invalid.matlab.root.warning = Unable to find MATLAB from the specified location on this system(but perhaps it exists on some agents)
88
Builder.matlab.root.empty.error = Full path to the MATLAB root folder is required.
99
Builder.matlab.test.support.error = To run tests with the Jenkins plugin, use MATLAB R2013a or a newer version.
1010
builder.matlab.automatictestoption.display.name = Automatic

src/test/java/com/mathworks/ci/MatlabBuilderTest.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import static org.junit.Assert.assertFalse;
66
import hudson.EnvVars;
7+
import hudson.FilePath;
78
import hudson.model.FreeStyleBuild;
89
import hudson.model.Result;
910
import hudson.slaves.EnvironmentVariablesNodeProperty;
@@ -245,7 +246,8 @@ public void verifyBuildStatusWhenTestFails() throws Exception {
245246

246247
@Test
247248
public void verifyVerlessThan() throws Exception {
248-
MatlabReleaseInfo rel = new MatlabReleaseInfo(getMatlabroot("R2017a"));
249+
FilePath matlabRoot = new FilePath(new File(getMatlabroot("R2017a")));
250+
MatlabReleaseInfo rel = new MatlabReleaseInfo(matlabRoot);
249251

250252
// verLessthan() will check all the versions against 9.2 which is version of R2017a
251253
assertFalse(rel.verLessThan(9.1));
@@ -383,7 +385,7 @@ public void verifyInvalidMatlabRootDisplaysError() throws Exception {
383385
project.getBuildersList().add(this.matlabBuilder);
384386
this.matlabBuilder.setMatlabRoot("/fake/matlab/path");
385387
HtmlPage page = jenkins.createWebClient().goTo("job/test0/configure");
386-
WebAssert.assertTextPresent(page, TestMessage.getValue("Builder.invalid.matlab.root.error"));
388+
WebAssert.assertTextPresent(page, TestMessage.getValue("Builder.invalid.matlab.root.warning"));
387389
}
388390

389391
/*
@@ -396,7 +398,7 @@ public void verifyValidMatlabRootDoesntDisplayError() throws Exception {
396398
project.getBuildersList().add(this.matlabBuilder);
397399
this.matlabBuilder.setMatlabRoot(getMatlabroot("R2018b"));
398400
HtmlPage page = jenkins.createWebClient().goTo("job/test0/configure");
399-
WebAssert.assertTextNotPresent(page, TestMessage.getValue("Builder.invalid.matlab.root.error"));
401+
WebAssert.assertTextNotPresent(page, TestMessage.getValue("Builder.invalid.matlab.root.warning"));
400402
}
401403

402404
/*
@@ -429,8 +431,8 @@ public void verifyCoberturaError() throws Exception {
429431
coberturaChkBx.setChecked(true);
430432
Thread.sleep(2000);
431433
String pageText = page.asText();
432-
String filteredPageText = pageText.replaceFirst(TestMessage.getValue("Builder.invalid.matlab.root.error"), "");
433-
Assert.assertTrue(filteredPageText.contains(TestMessage.getValue("Builder.invalid.matlab.root.error")));
434+
String filteredPageText = pageText.replaceFirst(TestMessage.getValue("Builder.invalid.matlab.root.warning"), "");
435+
Assert.assertTrue(filteredPageText.contains(TestMessage.getValue("Builder.invalid.matlab.root.warning")));
434436
}
435437

436438
/*

src/test/resources/testconfig.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33

44
Verify.matlab.invokes.positive = MATLAB is invoking positive tests
55
Verify.build.ignore.test.failure = Build Ignored test failure
6-
Builder.matlab.cobertura.support.warning = To generate a Cobertura report, use MATLAB R2017b or a newer version.
7-
Builder.invalid.matlab.root.error = Unable to launch MATLAB from the specified location. Verify the MATLAB root folder path.
6+
Builder.matlab.cobertura.support.warning = To generate a Cobertura report, use MATLAB R2017b or a newer release.
7+
Builder.invalid.matlab.root.warning = Unable to find MATLAB from the specified location on this system(but perhaps it exists on some agents)
88
Builder.matlab.root.empty.error = Full path to the MATLAB root folder is required.

0 commit comments

Comments
 (0)