Skip to content

Commit

Permalink
Merge pull request #50 from oleg-nenashev/JENKINS-28409
Browse files Browse the repository at this point in the history
[FIXED JENKINS-28409] - Properly close parent streams in EnvInjectPasswordsOutputStream
  • Loading branch information
oleg-nenashev committed May 15, 2015
2 parents faea23f + 561f243 commit 3545325
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 0 deletions.
Expand Up @@ -198,6 +198,12 @@ protected void eol(byte[] bytes, int len) throws IOException {
}
logger.write(line.getBytes());
}

@Override
public void close() throws IOException {
super.close();
logger.close();
}
}

@Override
Expand Down
@@ -1,14 +1,24 @@
package org.jenkinsci.plugins.envinject;

import hudson.Extension;
import hudson.Launcher;
import hudson.model.*;
import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrapperDescriptor;
import hudson.util.Secret;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import junit.framework.Assert;
import org.jenkinsci.lib.envinject.EnvInjectAction;
import org.jvnet.hudson.test.HudsonTestCase;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.TestExtension;

/**
* @author Gregory Boissinot
Expand Down Expand Up @@ -53,10 +63,96 @@ public void testEnvInjectJobParameterPassword() throws Exception {
checkEnvInjectResult(build);
}

@Bug(28409)
public void testFileHandlesLeak() throws Exception {
final EnvInjectPasswordWrapper passwordWrapper = new EnvInjectPasswordWrapper();
passwordWrapper.setPasswordEntries(new EnvInjectPasswordEntry[]{
new EnvInjectPasswordEntry(PWD_KEY, PWD_VALUE)
});
final FileLeakBuildWrapper fileLeakDetector = new FileLeakBuildWrapper();

project.getBuildWrappersList().add(fileLeakDetector);
project.getBuildWrappersList().add(passwordWrapper);

@SuppressWarnings("deprecation")
FreeStyleBuild build = project.scheduleBuild2(0).get();
assertBuildStatusSuccess(build);

Assert.assertTrue("Nested output stream has not been closed", fileLeakDetector.getLastOutputStream().isClosed());
}

private void checkEnvInjectResult(FreeStyleBuild build) {
EnvInjectAction action = build.getAction(EnvInjectAction.class);
Map<String, String> envVars = action.getEnvMap();
//The value must be encrypted in the envVars
Assert.assertEquals(Secret.fromString(PWD_VALUE).getEncryptedValue(), envVars.get(PWD_KEY));
}

/**
* A wrapper for an {@link OutputStream}, which raises the flag when a
* stream gets closed externally.
* @since TODO
*/
public static class FileLeakDetectorStream extends FilterOutputStream {

private boolean closed;

public FileLeakDetectorStream(OutputStream out) {
super(out);
this.closed = false;
}

public boolean isClosed() {
return closed;
}

@Override
public void close() throws IOException {
super.close();
closed = true;
}
}

/**
* A class, which decorates loggers by {@link FileLeakDetectorStream}.
* @since TODO
*/
public static class FileLeakBuildWrapper extends BuildWrapper {

private FileLeakDetectorStream lastOutputStream = null;

public FileLeakDetectorStream getLastOutputStream() {
return lastOutputStream;
}

@Override
public OutputStream decorateLogger(AbstractBuild build, OutputStream logger) throws IOException, InterruptedException, Run.RunnerAbortedException {
lastOutputStream = new FileLeakDetectorStream(logger);
return lastOutputStream;
}

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

@TestExtension
public static class DescriptorImpl extends BuildWrapperDescriptor {

@Override
public String getDisplayName() {
return "N/A";
}

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

0 comments on commit 3545325

Please sign in to comment.