Skip to content
Permalink
Browse files
[FIXED JENKINS-19506] - Prevent errors on nested wrappers usage
The provides workarounds for NPEs in Launcher::envs() and also properly calls inner launcher wrappers.
Resolves https://issues.jenkins-ci.org/browse/JENKINS-19506

Signed-off-by: Oleg Nenashev <nenashev@synopsys.com>
  • Loading branch information
oleg-nenashev committed Nov 12, 2013
1 parent 4128bbe commit 784a0c091b306d27df4aeb13e54b2ced43fd2db1
@@ -200,9 +200,14 @@ public Launcher decorateLauncher(AbstractBuild build, final Launcher launcher,

return new DecoratedLauncher(launcher) {
@Override
public Proc launch(ProcStarter starter) throws IOException {
EnvVars vars = toEnvVars(starter.envs());

public Proc launch(ProcStarter starter) throws IOException {
EnvVars vars;
try { // Dirty hack, which allows to avoid NPEs in Launcher::envs()
vars = toEnvVars(starter.envs());
} catch (NullPointerException npe) {
vars = new EnvVars();
}

// HACK: Avoids issue with invalid separators in EnvVars::override in case of different master/slave
String overridenPaths = vars.get("PATH");
overridenPaths += paths.toListString();
@@ -215,7 +220,7 @@ public Proc launch(ProcStarter starter) throws IOException {
injector.Inject(vars);
}

return super.launch(starter.envs(Util.mapToEnv(vars)));
return getInner().launch(starter.envs(Util.mapToEnv(vars)));
}

private EnvVars toEnvVars(String[] envs) {
@@ -87,4 +87,8 @@ public TaskListener getListener() {
public String toString() {
return super.toString()+"; decorates "+inner.toString();
}

public Launcher getInner() {
return inner;
}
}
@@ -0,0 +1,113 @@
/*
* Copyright 2012, CloudBees Inc.
* Copyright 2013, Synopsys Inc., Oleg Nenashev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cloudbees.jenkins.plugins.customtools;

import com.synopsys.arc.jenkins.plugins.customtools.util.CommandCallerInstaller;
import com.synopsys.arc.jenkins.plugins.customtools.util.StubWrapper;
import com.synopsys.arc.jenkinsci.plugins.customtools.multiconfig.MulticonfigWrapperOptions;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.tasks.BuildWrapper;
import hudson.tasks.Builder;
import hudson.tasks.Shell;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import org.jvnet.hudson.test.HudsonTestCase;

/**
* Contains tests for {@link CustomToolInstallWrapper}.
* @author rcampbell
* @author Oleg Nenashev <nenashev@synopsys.com>, Synopsys Inc.
*/
public class CustomToolInstallWrapperTest extends HudsonTestCase {
/**
* Inserts {@link CustomToolInstallWrapper} after {@link StubWrapper}.
* @throws Exception
*/
public void testNestedWrapper() throws Exception {
List<BuildWrapper> wrappers = new ArrayList<BuildWrapper>(2);
wrappers.add(new StubWrapper());
wrappers.add(setupCustomToolsWrapper());
nestedWrapperTestImpl(wrappers, true);
}

/**
* Inserts {@link StubWrapper} after {@link CustomToolInstallWrapper}.
* @throws Exception
*/
public void testNestedWrapperReverse() throws Exception {
List<BuildWrapper> wrappers = new ArrayList<BuildWrapper>(2);
wrappers.add(setupCustomToolsWrapper());
wrappers.add(new StubWrapper());
nestedWrapperTestImpl(wrappers, true);
}

/**
* Tests custom tools with wrapper, which calls wrapper without
* specifying of envs.
* @throws Exception
*/
//@Bug(19506))
public void testNestedLauncherCalls() throws Exception {
List<BuildWrapper> wrappers = new ArrayList<BuildWrapper>(2);
wrappers.add(new CommandCallerInstaller());
wrappers.add(setupCustomToolsWrapper());
nestedWrapperTestImpl(wrappers, false);
}

/**
* Implements tests for nested wrappers.
* The test checks that environment variables have been set correctly.
* It also expects existence of {@link StubWrapper} in the wrappers list.
*/
private void nestedWrapperTestImpl(List<BuildWrapper> wrappers, boolean checkEnvironment) throws Exception {
hudson.setNumExecutors(0);
createSlave();

// Create test project
FreeStyleProject project = createFreeStyleProject();
project.getBuildWrappersList().addAll(wrappers);

if (checkEnvironment) {
project.getBuildersList().add(checkVariableBuilder(StubWrapper.ENV_TESTVAR_NAME, StubWrapper.ENV_TESTVAR_VALUE));
project.getBuildersList().add(checkVariableBuilder(StubWrapper.SCRIPT_TESTVAR_NAME, StubWrapper.SCRIPT_TESTVAR_VALUE));
}

Future<FreeStyleBuild> build = project.scheduleBuild2(0);
assertBuildStatusSuccess(build);
}

private CustomToolInstallWrapper setupCustomToolsWrapper()
throws IOException {
CustomTool.DescriptorImpl tools = hudson.getDescriptorByType(CustomTool.DescriptorImpl.class);
tools.setInstallations(CustomToolInstallerTest.createTool("MyTrue"));
CustomToolInstallWrapper.SelectedTool selectedTool = new CustomToolInstallWrapper.SelectedTool("MyTrue");

return new CustomToolInstallWrapper(
new CustomToolInstallWrapper.SelectedTool[] { selectedTool },
MulticonfigWrapperOptions.DEFAULT, false);
}

private Builder checkVariableBuilder(String varName, String varValue) {
Builder b = new Shell("env \nif [ \"$"+ varName+"\" != \""+
varValue + "\" ] ; then \n echo Test failed \n exit -1 \n" +
"else \n echo OK:"+varName+"="+varValue+" \nfi");
return b;
}
}
@@ -81,7 +81,7 @@ public void testBasicCase() throws Exception {

}

private CustomTool createTool(String name) throws IOException {
static CustomTool createTool(String name) throws IOException {
List<ToolInstaller> installers = new ArrayList<ToolInstaller>();
installers.add(new CommandInstaller(null, "ln -s `which true` mytrue",
"./"));
@@ -0,0 +1,52 @@
/*
* Copyright 2013 Oleg Nenashev <nenashev@synopsys.com>, Synopsys Inc..
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.synopsys.arc.jenkins.plugins.customtools.util;

import hudson.Extension;
import hudson.Launcher;
import hudson.Launcher.ProcStarter;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import java.io.IOException;
import java.util.Map;

/**
* Implements a wrapper, which contains internal launcher call.
* The wrapper aims <a href="https://issues.jenkins-ci.org/browse/JENKINS-19506">JENKINS-19506</a> issue.
* @author Oleg Nenashev <nenashev@synopsys.com>, Synopsys Inc.
* @since 0.4.1
*/
public class CommandCallerInstaller extends StubWrapper {

@Override
public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
ProcStarter starter = launcher.launch().cmds("echo","Hello");
starter.start();
starter.join();

return new Environment() {
@Override
public void buildEnvVars(Map<String, String> env) {
super.buildEnvVars(env); //To change body of generated methods, choose Tools | Templates.
}
};
}

@Extension
public static class DescriptorImpl extends StubWrapper.DescriptorImpl {

}
}
@@ -0,0 +1,91 @@
/*
* Copyright 2013 Oleg Nenashev <nenashev@synopsys.com>, Synopsys Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.synopsys.arc.jenkins.plugins.customtools.util;

import hudson.EnvVars;
import hudson.Extension;
import hudson.Launcher;
import hudson.Proc;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Run;
import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrapperDescriptor;
import java.io.IOException;
import java.util.Map;
import java.util.TreeMap;

/**
* A stub wrapper, which injects a test variable into the build environment.
*
* @author Oleg Nenashev <nenashev@synopsys.com>, Synopsys Inc.
* @since 0.4.1
*/
public class StubWrapper extends BuildWrapper {
public static final String SCRIPT_TESTVAR_NAME = "SCRIPT_FOO_NAME";
public static final String SCRIPT_TESTVAR_VALUE = "SCRIPT_FOO_VALUE";
public static final String ENV_TESTVAR_NAME = "ENV_FOO_NAME";
public static final String ENV_TESTVAR_VALUE = "ENV_FOO_VALUE";

@Override
public Launcher decorateLauncher(AbstractBuild build, Launcher launcher, BuildListener listener)
throws IOException, InterruptedException, Run.RunnerAbortedException {
final Map<String, String> envs = new TreeMap<String, String>();

return new Launcher.LocalLauncher(listener) {
@Override
public Proc launch(Launcher.ProcStarter ps) throws IOException {
EnvVars envs = toEnvVars(ps.envs());
envs.put(SCRIPT_TESTVAR_NAME, SCRIPT_TESTVAR_VALUE);
return super.launch(ps.envs(Util.mapToEnv(envs)));
}

private EnvVars toEnvVars(String[] envs) {
EnvVars vars = new EnvVars();
for (String line : envs) {
vars.addLine(line);
}
return vars;
}
};
}

@Extension
public static class DescriptorImpl extends BuildWrapperDescriptor {
@Override
public String getDisplayName() {
return "Test stub";
}

@Override
public boolean isApplicable(AbstractProject<?, ?> ap) {
return true;
}
}

@Override
public Environment setUp(AbstractBuild build, Launcher launcher,
BuildListener listener) throws IOException, InterruptedException {
return new Environment(){
@Override
public void buildEnvVars(Map<String, String> env) {
env.put(ENV_TESTVAR_NAME, ENV_TESTVAR_VALUE);
}
};
}
}

0 comments on commit 784a0c0

Please sign in to comment.