Merge branch 'master' into printStackTrace-JDK-6507809

This commit is contained in:
Jesse Glick committed 2016-12-12 14:25:12 -05:00
commit 2abddbdfcc
3124 files changed
+75925 -26255

No files matched your search

@@ -98,10 +98,10 @@ public class BulkChangeTest {
@Test
public void nestedBulkChange() throws Exception {
Point pt = new Point();
Point _ = new Point();
Point pt2 = new Point();
BulkChange bc1 = new BulkChange(pt);
try {
BulkChange bc2 = new BulkChange(_);
BulkChange bc2 = new BulkChange(pt2);
try {
BulkChange bc3 = new BulkChange(pt);
try {
@@ -0,0 +1,69 @@
/*
* The MIT License
*
* Copyright (c) 2015, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson;
import hudson.util.VersionNumber;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
import static hudson.ClassicPluginStrategy.DetachedPlugin;
/**
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*/
public class ClassicPluginStrategyTest {
@Test
public void test_getDetachedPlugins() {
List<DetachedPlugin> list = ClassicPluginStrategy.getDetachedPlugins(new VersionNumber("1.296"));
Assert.assertTrue(list.size() >= 14); // There were 14 at the time of writing this test
Assert.assertNotNull(findPlugin("maven-plugin", list));
Assert.assertNotNull(findPlugin("subversion", list));
// Narrow the list to since "1.310" (the subversion detach version).
list = ClassicPluginStrategy.getDetachedPlugins(new VersionNumber("1.310"));
// Maven should no longer be in the list, but subversion should.
Assert.assertNull(findPlugin("maven-plugin", list));
Assert.assertNotNull(findPlugin("subversion", list));
// Narrow the list to since "1.311" (after the subversion detach version).
list = ClassicPluginStrategy.getDetachedPlugins(new VersionNumber("1.311"));
// Neither Maven or subversion should be in the list.
Assert.assertNull(findPlugin("maven-plugin", list));
Assert.assertNull(findPlugin("subversion", list));
}
private DetachedPlugin findPlugin(String shortName, List<DetachedPlugin> list) {
for (DetachedPlugin detachedPlugin : list) {
if (detachedPlugin.getShortName().equals(shortName)) {
return detachedPlugin;
}
}
return null;
}
}
+79 -3
View File
@@ -38,9 +38,11 @@ import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -58,10 +60,12 @@ import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Chmod;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeTrue;
import static org.junit.Assume.assumeFalse;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.jvnet.hudson.test.Issue;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
@@ -340,7 +344,7 @@ public class FilePathTest {
}
/**
* Checks that big files (>8GB) can be archived and then unpacked.
* Checks that big files (greater than 8GB) can be archived and then unpacked.
* This test is disabled by default due the impact on RAM.
* The actual file size limit is 8589934591 bytes.
* @throws Exception test failure
@@ -371,7 +375,7 @@ public class FilePathTest {
// Decompress
FilePath outDir = new FilePath(temp.newFolder(filePrefix + "_out"));
final FilePath outFile = outDir.child(tempFile.getName());
tmpDirPath.child( filePrefix + ".tar").untar(outDir, TarCompression.NONE);
tmpDirPath.child(tarFile.getName()).untar(outDir, TarCompression.NONE);
assertEquals("Result file after the roundtrip differs from the initial file",
new FilePath(tempFile).digest(), outFile.digest());
}
@@ -464,7 +468,7 @@ public class FilePathTest {
}
@Test public void symlinkInTar() throws Exception {
if (Functions.isWindows()) return; // can't test on Windows
assumeFalse("can't test on Windows", Functions.isWindows());
FilePath tmp = new FilePath(temp.getRoot());
FilePath in = tmp.child("in");
@@ -538,6 +542,25 @@ public class FilePathTest {
// good
}
}
@Issue("JENKINS-5253")
public void testValidateCaseSensitivity() throws Exception {
File tmp = Util.createTempDir();
try {
FilePath d = new FilePath(channels.french, tmp.getPath());
d.child("d1/d2/d3").mkdirs();
d.child("d1/d2/d3/f.txt").touch(0);
d.child("d1/d2/d3/f.html").touch(0);
d.child("d1/d2/f.txt").touch(0);
assertEquals(null, d.validateAntFileMask("**/d1/**/f.*", FilePath.VALIDATE_ANT_FILE_MASK_BOUND, true));
assertEquals(null, d.validateAntFileMask("**/d1/**/f.*", FilePath.VALIDATE_ANT_FILE_MASK_BOUND, false));
assertEquals(Messages.FilePath_validateAntFileMask_matchWithCaseInsensitive("**/D1/**/F.*"), d.validateAntFileMask("**/D1/**/F.*", FilePath.VALIDATE_ANT_FILE_MASK_BOUND, true));
assertEquals(null, d.validateAntFileMask("**/D1/**/F.*", FilePath.VALIDATE_ANT_FILE_MASK_BOUND, false));
} finally {
Util.deleteRecursive(tmp);
}
}
@Issue("JENKINS-15418")
@Test public void deleteLongPathOnWindows() throws Exception {
@@ -616,6 +639,28 @@ public class FilePathTest {
assertTrue(log, log.contains("504 Gateway Timeout"));
}
@Issue("JENKINS-23507")
@Test public void installIfNecessaryFollowsRedirects() throws Exception{
File tmp = temp.getRoot();
final FilePath d = new FilePath(tmp);
FilePath.UrlFactory urlFactory = mock(FilePath.UrlFactory.class);
d.setUrlFactory(urlFactory);
final HttpURLConnection con = mock(HttpURLConnection.class);
final HttpURLConnection con2 = mock(HttpURLConnection.class);
final URL url = someUrlToZipFile(con);
when(con.getResponseCode()).thenReturn(HttpURLConnection.HTTP_MOVED_TEMP);
URL url2 = someUrlToZipFile(con2);
String someUrl = url2.toExternalForm();
when(con.getHeaderField("Location")).thenReturn(someUrl);
when(urlFactory.newURL(someUrl)).thenReturn(url2);
when(con2.getResponseCode()).thenReturn(HttpURLConnection.HTTP_OK);
when(con2.getInputStream()).thenReturn(someZippedContent());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String message = "going ahead";
assertTrue(d.installIfNecessaryFrom(url, new StreamTaskListener(baos), message));
}
private URL someUrlToZipFile(final URLConnection con) throws IOException {
final URLStreamHandler urlHandler = new URLStreamHandler() {
@@ -659,4 +704,35 @@ public class FilePathTest {
// test conflict subdir
src.moveAllChildrenTo(dst);
}
@Issue("JENKINS-10629")
@Test
public void testEOFbrokenFlush() throws IOException, InterruptedException {
final File srcFolder = temp.newFolder("src");
// simulate magic structure with magic sizes:
// |- dir/pom.xml (2049)
// |- pom.xml (2049)
// \- small.tar (1537)
final File smallTar = new File(srcFolder, "small.tar");
givenSomeContentInFile(smallTar, 1537);
final File dir = new File(srcFolder, "dir");
dir.mkdirs();
final File pomFile = new File(dir, "pom.xml");
givenSomeContentInFile(pomFile, 2049);
FileUtils.copyFileToDirectory(pomFile, srcFolder);
final File archive = temp.newFile("archive.tar");
// Compress archive
final FilePath tmpDirPath = new FilePath(srcFolder);
int tarred = tmpDirPath.tar(new FileOutputStream(archive), "**");
assertEquals("One file should have been compressed", 3, tarred);
// Decompress
final File dstFolder = temp.newFolder("dst");
dstFolder.mkdirs();
FilePath outDir = new FilePath(dstFolder);
// and now fail when flush is bad!
tmpDirPath.child("../" + archive.getName()).untar(outDir, TarCompression.NONE);
}
}
+3 -4
View File
@@ -34,6 +34,8 @@ import java.io.File;
import jenkins.security.MasterToSlaveCallable;
import org.apache.commons.io.FileUtils;
import static org.junit.Assert.*;
import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -46,10 +48,7 @@ public class LauncherTest {
@Issue("JENKINS-4611")
@Test public void remoteKill() throws Exception {
if (File.pathSeparatorChar != ':') {
System.err.println("Skipping, currently Unix-specific test");
return;
}
Assume.assumeFalse("Skipping, currently Unix-specific test", Functions.isWindows());
File tmp = temp.newFile();
@@ -24,17 +24,33 @@
package hudson;
import java.io.File;
import java.io.FileOutputStream;
import org.apache.tools.ant.filters.StringInputStream;
import org.junit.Test;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.*;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
import org.jvnet.hudson.test.Issue;
/**
* Tests of {@link PluginManager}.
*/
public class PluginManagerTest {
@Rule public TemporaryFolder tmp = new TemporaryFolder();
@@ -68,4 +84,86 @@ public class PluginManagerTest {
assertThat(ex.getCause().getMessage(), containsString("Refusing to resolve entity with publicId(null) and systemId (file:///)"));
}
}
@Test
public void shouldProperlyParseManifestFromJar() throws IOException {
File jar = createHpiWithManifest();
final Manifest manifest = PluginManager.parsePluginManifest(jar.toURI().toURL());
assertThat("manifest should have been read from the sample", manifest, notNullValue());
assertAttribute(manifest, "Created-By", "Apache Maven");
assertAttribute(manifest, "Short-Name", "matrix-auth");
// Multi-line entries
assertAttribute(manifest, "Specification-Title", "Offers matrix-based security authorization strategies (global and per-project).");
assertAttribute(manifest, "Url", "http://wiki.jenkins-ci.org/display/JENKINS/Matrix+Authorization+Strategy+Plugin");
// Empty field
assertAttribute(manifest, "Plugin-Developers", null);
}
@Test
public void shouldProperlyRetrieveModificationDate() throws IOException {
File jar = createHpiWithManifest();
URL url = toManifestUrl(jar);
assertThat("Manifest last modified date should be equal to the file date",
PluginManager.getModificationDate(url),
equalTo(jar.lastModified()));
}
private static void assertAttribute(Manifest manifest, String attributeName, String value) throws AssertionError {
Attributes attributes = manifest.getMainAttributes();
assertThat("Main attributes must not be empty", attributes, notNullValue());
assertThat("Attribute '" + attributeName + "' does not match the sample",
attributes.getValue(attributeName),
equalTo(value));
}
private static final String SAMPLE_MANIFEST_FILE = "Manifest-Version: 1.0\n" +
"Archiver-Version: Plexus Archiver\n" +
"Created-By: Apache Maven\n" +
"Built-By: jglick\n" +
"Build-Jdk: 1.8.0_92\n" +
"Extension-Name: matrix-auth\n" +
"Specification-Title: \n" +
" Offers matrix-based security \n" +
" authorization strate\n" +
" gies (global and per-project).\n" +
"Implementation-Title: matrix-auth\n" +
"Implementation-Version: 1.4\n" +
"Group-Id: org.jenkins-ci.plugins\n" +
"Short-Name: matrix-auth\n" +
"Long-Name: Matrix Authorization Strategy Plugin\n" +
"Url: http://wiki.jenkins-ci.org/display/JENKINS/Matrix+Authorization+S\n" +
" trategy+Plugin\n" +
"Plugin-Version: 1.4\n" +
"Hudson-Version: 1.609.1\n" +
"Jenkins-Version: 1.609.1\n" +
"Plugin-Dependencies: icon-shim:2.0.3,cloudbees-folder:5.2.2;resolution\n" +
" :=optional\n" +
"Plugin-Developers: ";
private File createHpiWithManifest() throws IOException {
File newFolder = tmp.newFolder("myJar");
String manifestPath = "META-INF/MANIFEST.MF";
new File("META-INF").mkdir();
FileUtils.write(new File(newFolder, manifestPath), SAMPLE_MANIFEST_FILE);
final File f = new File(tmp.getRoot(), "my.hpi");
try(ZipOutputStream out = new ZipOutputStream(new FileOutputStream(f))) {
ZipEntry e = new ZipEntry(manifestPath);
out.putNextEntry(e);
byte[] data = SAMPLE_MANIFEST_FILE.getBytes();
out.write(data, 0, data.length);
out.closeEntry();
}
return f;
}
private URL toManifestUrl(File jarFile) throws MalformedURLException {
final String manifestPath = "META-INF/MANIFEST.MF";
return new URL("jar:" + jarFile.toURI().toURL() + "!/" + manifestPath);
}
}
@@ -0,0 +1,183 @@
package hudson;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import jenkins.model.Jenkins;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class PluginWrapperTest {
@Before
public void before() throws Exception {
Jenkins.VERSION = "2.0"; // Some value needed - tests will overwrite if necessary
}
@Test
public void dependencyTest() {
String version = "plugin:0.0.2";
PluginWrapper.Dependency dependency = new PluginWrapper.Dependency(version);
assertEquals("plugin", dependency.shortName);
assertEquals("0.0.2", dependency.version);
assertEquals(false, dependency.optional);
}
@Test
public void optionalDependencyTest() {
String version = "plugin:0.0.2;resolution:=optional";
PluginWrapper.Dependency dependency = new PluginWrapper.Dependency(version);
assertEquals("plugin", dependency.shortName);
assertEquals("0.0.2", dependency.version);
assertEquals(true, dependency.optional);
}
@Test
public void jenkinsCoreTooOld() throws Exception {
PluginWrapper pw = pluginWrapper("fake").requiredCoreVersion("3.0").buildLoaded();
try {
pw.resolvePluginDependencies();
fail();
} catch (IOException ex) {
assertContians(ex, "fake v42 failed to load", "update Jenkins from v2.0 to v3.0");
}
}
@Test
public void dependencyNotInstalled() throws Exception {
PluginWrapper pw = pluginWrapper("dependee").deps("dependency:42").buildLoaded();
try {
pw.resolvePluginDependencies();
fail();
} catch (IOException ex) {
assertContians(ex, "dependee v42 failed to load", "dependency v42 is missing. To fix, install v42 or later");
}
}
@Test
public void dependencyOutdated() throws Exception {
pluginWrapper("dependency").version("3").buildLoaded();
PluginWrapper pw = pluginWrapper("dependee").deps("dependency:5").buildLoaded();
try {
pw.resolvePluginDependencies();
fail();
} catch (IOException ex) {
assertContians(ex, "dependee v42 failed to load", "dependency v3 is older than required. To fix, install v5 or later");
}
}
@Test
public void dependencyFailedToLoad() throws Exception {
pluginWrapper("dependency").version("5").buildFailed();
PluginWrapper pw = pluginWrapper("dependee").deps("dependency:3").buildLoaded();
try {
pw.resolvePluginDependencies();
fail();
} catch (IOException ex) {
assertContians(ex, "dependee v42 failed to load", "dependency v5 failed to load. Fix this plugin first");
}
}
private void assertContians(Throwable ex, String... patterns) {
String msg = ex.getMessage();
for (String pattern : patterns) {
assertThat(msg, containsString(pattern));
}
}
private PluginWrapperBuilder pluginWrapper(String name) {
return new PluginWrapperBuilder(name);
}
// per test
private final HashMap<String, PluginWrapper> plugins = new HashMap<>();
private final PluginManager pm = mock(PluginManager.class);
{
when(pm.getPlugin(any(String.class))).thenAnswer(new Answer<PluginWrapper>() {
@Override public PluginWrapper answer(InvocationOnMock invocation) throws Throwable {
return plugins.get(invocation.getArguments()[0]);
}
});
}
private final class PluginWrapperBuilder {
private String name;
private String version = "42";
private String requiredCoreVersion = "1.0";
private List<PluginWrapper.Dependency> deps = new ArrayList<>();
private List<PluginWrapper.Dependency> optDeps = new ArrayList<>();
private PluginWrapperBuilder(String name) {
this.name = name;
}
public PluginWrapperBuilder version(String version) {
this.version = version;
return this;
}
public PluginWrapperBuilder requiredCoreVersion(String requiredCoreVersion) {
this.requiredCoreVersion = requiredCoreVersion;
return this;
}
public PluginWrapperBuilder deps(String... deps) {
for (String dep: deps) {
this.deps.add(new PluginWrapper.Dependency(dep));
}
return this;
}
public PluginWrapperBuilder optDeps(String... optDeps) {
for (String dep: optDeps) {
this.optDeps.add(new PluginWrapper.Dependency(dep));
}
return this;
}
private PluginWrapper buildLoaded() {
PluginWrapper pw = build();
plugins.put(name, pw);
return pw;
}
private PluginWrapper buildFailed() {
PluginWrapper pw = build();
PluginWrapper.NOTICE.addPlugin(pw);
return pw;
}
private PluginWrapper build() {
Manifest manifest = mock(Manifest.class);
Attributes attributes = new Attributes();
attributes.put(new Attributes.Name("Short-Name"), name);
attributes.put(new Attributes.Name("Jenkins-Version"), requiredCoreVersion);
attributes.put(new Attributes.Name("Plugin-Version"), version);
when(manifest.getMainAttributes()).thenReturn(attributes);
return new PluginWrapper(
pm,
new File("/tmp/" + name + ".jpi"),
manifest,
null,
null,
new File("/tmp/" + name + ".jpi.disabled"),
deps,
optDeps
);
}
}
}
@@ -0,0 +1,48 @@
/*
*
*/
package hudson;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import java.io.File;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.jvnet.hudson.test.Issue;
public class RemoveWindowsDirectoryJunctionTest {
@Rule
public TemporaryFolder tmp = new TemporaryFolder();
@Before
public void windowsOnly() {
assumeTrue(Functions.isWindows());
}
@Test
@Issue("JENKINS-2995")
public void testJunctionIsRemovedButNotContents() throws Exception {
File subdir1 = tmp.newFolder("notJunction");
File f1 = new File(subdir1, "testfile1.txt");
assertTrue("Unable to create temporary file in notJunction directory", f1.createNewFile());
File j1 = makeJunction(tmp.getRoot(), subdir1);
Util.deleteRecursive(j1);
assertFalse("Windows Junction should have been removed", j1.exists());
assertTrue("Contents of Windows Junction should not be removed", f1.exists());
}
private File makeJunction(File baseDir, File pointToDir) throws Exception {
File junc = new File(baseDir, "test Junction");
String cmd = "mklink /J \"" + junc.getPath() + "\" \"" + pointToDir.getPath() + "\"";
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/C", cmd);
pb.inheritIO();
Process p = pb.start();
assertEquals("Running mklink failed (cmd=" + cmd + ")", 0, p.waitFor());
return junc;
}
}
+273 -10
View File
@@ -24,17 +24,27 @@
*/
package hudson;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Locale;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.*;
import org.apache.commons.io.FileUtils;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Assume;
@@ -42,12 +52,13 @@ import org.junit.Test;
import org.jvnet.hudson.test.Issue;
import hudson.util.StreamTaskListener;
import java.io.FileOutputStream;
import java.io.OutputStream;
import org.junit.Rule;
import org.junit.internal.AssumptionViolatedException;
import org.junit.rules.TemporaryFolder;
import com.google.common.collect.Lists;
/**
* @author Kohsuke Kawaguchi
*/
@@ -248,7 +259,17 @@ public class UtilTest {
}
}
@Test public void deleteFile() throws Exception {
@Test
public void testDeleteFile() throws Exception {
File f = tmp.newFile();
// Test: File is deleted
mkfiles(f);
Util.deleteFile(f);
assertFalse("f exists after calling Util.deleteFile", f.exists());
}
@Test
public void testDeleteFile_onWindows() throws Exception {
Assume.assumeTrue(Functions.isWindows());
Class<?> c;
try {
@@ -256,23 +277,245 @@ public class UtilTest {
} catch (ClassNotFoundException x) {
throw new AssumptionViolatedException("prior to JDK 7", x);
}
File d = tmp.getRoot();
final int defaultDeletionMax = Util.DELETION_MAX;
try {
File f = new File(d, "f");
OutputStream os = new FileOutputStream(f);
File f = tmp.newFile();
// Test: If we cannot delete a file, we throw explaining why
mkfiles(f);
lockFileForDeletion(f);
Util.DELETION_MAX = 1;
try {
Util.deleteFile(f);
fail("should not have been deletable");
} catch (IOException x) {
assertEquals(c, x.getClass());
} finally {
os.close();
assertThat(calcExceptionHierarchy(x), hasItem(c));
assertThat(x.getMessage(), containsString(f.getPath()));
}
} finally {
Util.deleteRecursive(d);
Util.DELETION_MAX = defaultDeletionMax;
unlockFilesForDeletion();
}
}
@Test
public void testDeleteContentsRecursive() throws Exception {
final File dir = tmp.newFolder();
final File d1 = new File(dir, "d1");
final File d2 = new File(dir, "d2");
final File f1 = new File(dir, "f1");
final File d1f1 = new File(d1, "d1f1");
final File d2f2 = new File(d2, "d1f2");
// Test: Files and directories are deleted
mkdirs(dir, d1, d2);
mkfiles(f1, d1f1, d2f2);
Util.deleteContentsRecursive(dir);
assertTrue("dir exists", dir.exists());
assertFalse("d1 exists", d1.exists());
assertFalse("d2 exists", d2.exists());
assertFalse("f1 exists", f1.exists());
}
@Test
public void testDeleteContentsRecursive_onWindows() throws Exception {
Assume.assumeTrue(Functions.isWindows());
final File dir = tmp.newFolder();
final File d1 = new File(dir, "d1");
final File d2 = new File(dir, "d2");
final File f1 = new File(dir, "f1");
final File d1f1 = new File(d1, "d1f1");
final File d2f2 = new File(d2, "d1f2");
final int defaultDeletionMax = Util.DELETION_MAX;
final int defaultDeletionWait = Util.WAIT_BETWEEN_DELETION_RETRIES;
final boolean defaultDeletionGC = Util.GC_AFTER_FAILED_DELETE;
try {
// Test: If we cannot delete a file, we throw
// but still deletes everything it can
// even if we are not retrying deletes.
mkdirs(dir, d1, d2);
mkfiles(f1, d1f1, d2f2);
lockFileForDeletion(d1f1);
Util.GC_AFTER_FAILED_DELETE = false;
Util.DELETION_MAX = 2;
Util.WAIT_BETWEEN_DELETION_RETRIES = 0;
try {
Util.deleteContentsRecursive(dir);
fail("Expected IOException");
} catch (IOException x) {
assertFalse("d2 should not exist", d2.exists());
assertFalse("f1 should not exist", f1.exists());
assertFalse("d1f2 should not exist", d2f2.exists());
assertThat(x.getMessage(), containsString(dir.getPath()));
assertThat(x.getMessage(), allOf(not(containsString("interrupted")), containsString("Tried 2 times (of a maximum of 2)."), not(containsString("garbage-collecting")), not(containsString("wait"))));
}
} finally {
Util.DELETION_MAX = defaultDeletionMax;
Util.WAIT_BETWEEN_DELETION_RETRIES = defaultDeletionWait;
Util.GC_AFTER_FAILED_DELETE = defaultDeletionGC;
unlockFilesForDeletion();
}
}
@Test
public void testDeleteRecursive() throws Exception {
final File dir = tmp.newFolder();
final File d1 = new File(dir, "d1");
final File d2 = new File(dir, "d2");
final File f1 = new File(dir, "f1");
final File d1f1 = new File(d1, "d1f1");
final File d2f2 = new File(d2, "d1f2");
// Test: Files and directories are deleted
mkdirs(dir, d1, d2);
mkfiles(f1, d1f1, d2f2);
Util.deleteRecursive(dir);
assertFalse("dir exists", dir.exists());
}
@Test
public void testDeleteRecursive_onWindows() throws Exception {
Assume.assumeTrue(Functions.isWindows());
final File dir = tmp.newFolder();
final File d1 = new File(dir, "d1");
final File d2 = new File(dir, "d2");
final File f1 = new File(dir, "f1");
final File d1f1 = new File(d1, "d1f1");
final File d2f2 = new File(d2, "d1f2");
final int defaultDeletionMax = Util.DELETION_MAX;
final int defaultDeletionWait = Util.WAIT_BETWEEN_DELETION_RETRIES;
final boolean defaultDeletionGC = Util.GC_AFTER_FAILED_DELETE;
try {
// Test: If we cannot delete a file, we throw
// but still deletes everything it can
// even if we are not retrying deletes.
// (And when we are not retrying deletes,
// we do not do the "between retries" delay)
mkdirs(dir, d1, d2);
mkfiles(f1, d1f1, d2f2);
lockFileForDeletion(d1f1);
Util.GC_AFTER_FAILED_DELETE = false;
Util.DELETION_MAX = 1;
Util.WAIT_BETWEEN_DELETION_RETRIES = 10000; // long enough to notice
long timeWhenDeletionStarted = System.currentTimeMillis();
try {
Util.deleteRecursive(dir);
fail("Expected IOException");
} catch (IOException x) {
long timeWhenDeletionEnded = System.currentTimeMillis();
assertTrue("dir exists", dir.exists());
assertTrue("d1 exists", d1.exists());
assertTrue("d1f1 exists", d1f1.exists());
assertFalse("d2 should not exist", d2.exists());
assertFalse("f1 should not exist", f1.exists());
assertFalse("d1f2 should not exist", d2f2.exists());
assertThat(x.getMessage(), containsString(dir.getPath()));
assertThat(x.getMessage(), allOf(not(containsString("interrupted")), not(containsString("maximum of")), not(containsString("garbage-collecting"))));
long actualTimeSpentDeleting = timeWhenDeletionEnded - timeWhenDeletionStarted;
assertTrue("did not wait - took " + actualTimeSpentDeleting + "ms", actualTimeSpentDeleting<1000L);
}
unlockFileForDeletion(d1f1);
// Deletes get retried if they fail 1st time around,
// allowing the operation to succeed on subsequent attempts.
// Note: This is what bug JENKINS-15331 is all about.
mkdirs(dir, d1, d2);
mkfiles(f1, d1f1, d2f2);
lockFileForDeletion(d2f2);
Util.DELETION_MAX=4;
Util.WAIT_BETWEEN_DELETION_RETRIES = 100;
Thread unlockAfterDelay = new Thread("unlockFileAfterDelay") {
public void run() {
try {
Thread.sleep(Util.WAIT_BETWEEN_DELETION_RETRIES);
unlockFileForDeletion(d2f2);
} catch( Exception x ) { /* ignored */ }
}
};
unlockAfterDelay.start();
Util.deleteRecursive(dir);
assertFalse("dir should have been deleted", dir.exists());
unlockAfterDelay.join();
// An interrupt aborts the delete and makes it fail, even
// if we had been told to retry a lot.
mkdirs(dir, d1, d2);
mkfiles(f1, d1f1, d2f2);
lockFileForDeletion(d1f1);
Util.DELETION_MAX=10;
Util.WAIT_BETWEEN_DELETION_RETRIES = -1000;
Util.GC_AFTER_FAILED_DELETE = true;
final AtomicReference<Throwable> thrown = new AtomicReference<Throwable>();
Thread deleteToBeInterupted = new Thread("deleteToBeInterupted") {
public void run() {
try { Util.deleteRecursive(dir); }
catch( Throwable x ) { thrown.set(x); }
}
};
deleteToBeInterupted.start();
deleteToBeInterupted.interrupt();
deleteToBeInterupted.join(500);
assertFalse("deletion stopped", deleteToBeInterupted.isAlive());
assertTrue("d1f1 still exists", d1f1.exists());
unlockFileForDeletion(d1f1);
Throwable deletionInterruptedEx = thrown.get();
assertThat(deletionInterruptedEx, instanceOf(IOException.class));
assertThat(deletionInterruptedEx.getMessage(), allOf(containsString("interrupted"), containsString("maximum of " + Util.DELETION_MAX), containsString("garbage-collecting")));
} finally {
Util.DELETION_MAX = defaultDeletionMax;
Util.WAIT_BETWEEN_DELETION_RETRIES = defaultDeletionWait;
Util.GC_AFTER_FAILED_DELETE = defaultDeletionGC;
unlockFilesForDeletion();
}
}
/** Creates multiple directories. */
private static void mkdirs(File... dirs) {
for( File d : dirs ) {
d.mkdir();
assertTrue(d.getPath(), d.isDirectory());
}
}
/** Creates multiple files, each containing their filename as text content. */
private static void mkfiles(File... files) throws IOException {
for( File f : files )
FileUtils.write(f, f.getName());
}
/** Means of unlocking all the files we have locked, indexed by {@link File}. */
private final Map<File, Callable<Void>> unlockFileCallables = new HashMap<File, Callable<Void>>();
/** Prevents a file from being deleted, so we can stress the deletion code's retries. */
private void lockFileForDeletion(File f) throws IOException, InterruptedException {
assert !unlockFileCallables.containsKey(f) : f + " is already locked." ;
// Limitation: Only works on Windows. On unix we can delete anything we can create.
// On unix, can't use "chmod a-w" on the dir as the code-under-test undoes that.
// On unix, can't use "chattr +i" because that needs root.
// On unix, can't use "chattr +u" because ext fs ignores it.
// On Windows, we can't delete files that are open for reading, so we use that.
assert Functions.isWindows();
final InputStream s = new FileInputStream(f);
unlockFileCallables.put(f, new Callable<Void>() {
public Void call() throws IOException { s.close(); return null; };
});
}
/** Undoes a call to {@link #lockFileForDeletion(File)}. */
private void unlockFileForDeletion(File f) throws Exception {
unlockFileCallables.remove(f).call();
}
/** Undoes all calls to {@link #lockFileForDeletion(File)}. */
private void unlockFilesForDeletion() throws Exception {
while( !unlockFileCallables.isEmpty() ) {
unlockFileForDeletion(unlockFileCallables.keySet().iterator().next());
}
}
/** Returns all classes in the exception hierarchy. */
private static Iterable<Class<?>> calcExceptionHierarchy(Throwable t) {
final List<Class<?>> result = Lists.newArrayList();
for( ; t!=null ; t = t.getCause())
result.add(t.getClass());
return result;
}
@Test
public void testHtmlEscape() {
assertEquals("<br>", Util.escape("\n"));
@@ -344,6 +587,26 @@ public class UtilTest {
assertFalse(Util.isAbsoluteUri("foo/bar"));
}
@Test
@Issue("SECURITY-276")
public void testIsSafeToRedirectTo() {
assertFalse(Util.isSafeToRedirectTo("http://foobar/"));
assertFalse(Util.isSafeToRedirectTo("mailto:kk@kohsuke.org"));
assertFalse(Util.isSafeToRedirectTo("d123://test/"));
assertFalse(Util.isSafeToRedirectTo("//google.com"));
assertTrue(Util.isSafeToRedirectTo("foo/bar/abc:def"));
assertTrue(Util.isSafeToRedirectTo("foo?abc:def"));
assertTrue(Util.isSafeToRedirectTo("foo#abc:def"));
assertTrue(Util.isSafeToRedirectTo("foo/bar"));
assertTrue(Util.isSafeToRedirectTo("/"));
assertTrue(Util.isSafeToRedirectTo("/foo"));
assertTrue(Util.isSafeToRedirectTo(".."));
assertTrue(Util.isSafeToRedirectTo("../.."));
assertTrue(Util.isSafeToRedirectTo("/#foo"));
assertTrue(Util.isSafeToRedirectTo("/?foo"));
}
@Test
public void loadProperties() throws IOException {
@@ -4,6 +4,7 @@ import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
@@ -50,6 +51,7 @@ public class ListJobsCommandTest {
jenkins = mock(Jenkins.class);
mockStatic(Jenkins.class);
when(Jenkins.getInstance()).thenReturn(jenkins);
when(Jenkins.getActiveInstance()).thenReturn(jenkins);
command = mock(ListJobsCommand.class, Mockito.CALLS_REAL_METHODS);
command.stdout = new PrintStream(stdout);
command.stderr = new PrintStream(stderr);
@@ -61,9 +63,13 @@ public class ListJobsCommandTest {
when(jenkins.getView("NoSuchViewOrItemGroup")).thenReturn(null);
when(jenkins.getItemByFullName("NoSuchViewOrItemGroup")).thenReturn(null);
assertThat(runWith("NoSuchViewOrItemGroup"), equalTo(-1));
try {
runWith("NoSuchViewOrItemGroup");
fail("Exception should be thrown in the previous call.");
} catch (IllegalArgumentException e) { // Expected
assertThat(e.getMessage(), containsString("No view or item group with the given name 'NoSuchViewOrItemGroup' found."));
}
assertThat(stdout, is(empty()));
assertThat(stderr.toString(), containsString("No view or item group with the given name found"));
}
/*
@@ -27,7 +27,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import hudson.model.ViewGroup;
@@ -81,6 +80,7 @@ public class ViewOptionHandlerTest {
PowerMockito.mockStatic(Jenkins.class);
PowerMockito.when(Jenkins.getInstance()).thenReturn(jenkins);
PowerMockito.when(Jenkins.getActiveInstance()).thenReturn(jenkins);
when(jenkins.getView("outer")).thenReturn(outer);
when(jenkins.getDisplayName()).thenReturn("Jenkins");
}
@@ -117,7 +117,7 @@ public class ViewOptionHandlerTest {
assertEquals(
"No view named missing_view inside view Jenkins",
parseFailedWith(CmdLineException.class, "missing_view")
parseFailedWith(IllegalArgumentException.class, "missing_view")
);
verifyZeroInteractions(setter);
@@ -127,7 +127,7 @@ public class ViewOptionHandlerTest {
assertEquals(
"No view named missing_view inside view outer",
parseFailedWith(CmdLineException.class, "outer/missing_view")
parseFailedWith(IllegalArgumentException.class, "outer/missing_view")
);
verifyZeroInteractions(setter);
@@ -137,7 +137,7 @@ public class ViewOptionHandlerTest {
assertEquals(
"No view named missing_view inside view nested",
parseFailedWith(CmdLineException.class, "outer/nested/missing_view")
parseFailedWith(IllegalArgumentException.class, "outer/nested/missing_view")
);
verifyZeroInteractions(setter);
@@ -147,20 +147,46 @@ public class ViewOptionHandlerTest {
assertEquals(
"inner view can not contain views",
parseFailedWith(CmdLineException.class, "outer/nested/inner/missing")
parseFailedWith(IllegalStateException.class, "outer/nested/inner/missing")
);
verifyZeroInteractions(setter);
}
@Test public void reportEmptyViewNameRequestAsNull() throws Exception {
assertEquals(handler.getView(""), null);
verifyZeroInteractions(setter);
}
@Test public void reportViewSpaceNameRequestAsIAE() throws Exception {
try {
assertEquals(handler.getView(" "), null);
fail("No exception thrown. Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
assertEquals("No view named inside view Jenkins", e.getMessage());
verifyZeroInteractions(setter);
}
}
@Test public void reportNullViewAsNPE() throws Exception {
try {
handler.getView(null);
fail("No exception thrown. Expected NullPointerException");
} catch (NullPointerException e) {
verifyZeroInteractions(setter);
}
}
@Test public void refuseToReadOuterView() throws Exception {
denyAccessOn(outer);
parseFailedWith(AccessDeniedException.class, "outer/nested/inner");
assertEquals(
"Access denied for: outer",
parseFailedWith(AccessDeniedException.class, "outer/nested/inner")
);
verify(outer).checkPermission(View.READ);
verifyNoMoreInteractions(outer);
verifyZeroInteractions(nested);
verifyZeroInteractions(inner);
@@ -171,10 +197,12 @@ public class ViewOptionHandlerTest {
denyAccessOn(nested);
parseFailedWith(AccessDeniedException.class, "outer/nested/inner");
assertEquals(
"Access denied for: nested",
parseFailedWith(AccessDeniedException.class, "outer/nested/inner")
);
verify(nested).checkPermission(View.READ);
verifyNoMoreInteractions(nested);
verifyZeroInteractions(inner);
verifyZeroInteractions(setter);
@@ -184,17 +212,20 @@ public class ViewOptionHandlerTest {
denyAccessOn(inner);
parseFailedWith(AccessDeniedException.class, "outer/nested/inner");
assertEquals(
"Access denied for: inner",
parseFailedWith(AccessDeniedException.class, "outer/nested/inner")
);
verify(inner).checkPermission(View.READ);
verifyNoMoreInteractions(inner);
verifyZeroInteractions(setter);
}
private void denyAccessOn(View view) {
doThrow(new AccessDeniedException(null)).when(view).checkPermission(View.READ);
final AccessDeniedException ex = new AccessDeniedException("Access denied for: " + view.getViewName());
doThrow(ex).when(view).checkPermission(View.READ);
}
private String parseFailedWith(Class<? extends Exception> type, final String... params) throws Exception {
@@ -24,18 +24,26 @@
package hudson.model;
import java.util.ArrayList;
import java.util.Arrays;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;
import java.util.Collections;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
public class ActionableTest {
private Actionable thing = new ActionableImpl();
@SuppressWarnings("deprecation")
@Test public void replaceAction() {
Actionable thing = new Actionable() {
@Override public String getDisplayName() {return null;}
@Override public String getSearchUrl() {return null;}
};
@Test
public void replaceAction() {
CauseAction a1 = new CauseAction();
ParametersAction a2 = new ParametersAction();
thing.addAction(a1);
@@ -45,4 +53,168 @@ public class ActionableTest {
assertEquals(Arrays.asList(a2, a3), thing.getActions());
}
static class ActionableOverride extends Actionable {
ArrayList<Action> specialActions = new ArrayList<Action>();
@Override
public String getDisplayName() {
return "nope";
}
@Override
public String getSearchUrl() {
return "morenope";
}
@Override
public List<Action> getActions() {
return specialActions;
}
}
@SuppressWarnings("deprecation")
@Issue("JENKINS-39555")
@Test
public void testExtensionOverrides() throws Exception {
ActionableOverride myOverridden = new ActionableOverride();
InvisibleAction invis = new InvisibleAction() {
};
myOverridden.addAction(invis);
Assert.assertArrayEquals(new Object[]{invis}, myOverridden.specialActions.toArray());
Assert.assertArrayEquals(new Object[]{invis}, myOverridden.getActions().toArray());
myOverridden.getActions().remove(invis);
Assert.assertArrayEquals(new Object[]{}, myOverridden.specialActions.toArray());
Assert.assertArrayEquals(new Object[]{}, myOverridden.getActions().toArray());
myOverridden.addAction(invis);
myOverridden.removeAction(invis);
Assert.assertArrayEquals(new Object[]{}, myOverridden.specialActions.toArray());
Assert.assertArrayEquals(new Object[]{}, myOverridden.getActions().toArray());
InvisibleAction invis2 = new InvisibleAction() {};
myOverridden.addOrReplaceAction(invis2);
Assert.assertArrayEquals(new Object[]{invis2}, myOverridden.specialActions.toArray());
Assert.assertArrayEquals(new Object[]{invis2}, myOverridden.getActions().toArray());
myOverridden.addOrReplaceAction(invis);
myOverridden.addOrReplaceAction(invis);
Assert.assertArrayEquals(new Object[]{invis2, invis}, myOverridden.specialActions.toArray());
Assert.assertArrayEquals(new Object[]{invis2, invis}, myOverridden.getActions().toArray());
}
@SuppressWarnings("deprecation")
@Test
public void addOrReplaceAction() {
CauseAction a1 = new CauseAction();
ParametersAction a2 = new ParametersAction();
thing.addAction(a1);
thing.addAction(a2);
CauseAction a3 = new CauseAction();
assertTrue(thing.addOrReplaceAction(a3));
assertEquals(Arrays.asList(a2, a3), thing.getActions());
assertFalse(thing.addOrReplaceAction(a3));
assertEquals(Arrays.asList(a2, a3), thing.getActions());
thing.addAction(a1);
assertEquals(Arrays.asList(a2, a3, a1), thing.getActions());
assertTrue(thing.addOrReplaceAction(a3));
assertEquals(Arrays.asList(a2, a3), thing.getActions());
}
@SuppressWarnings("deprecation")
@Test
public void replaceActions() {
CauseAction a1 = new CauseAction();
ParametersAction a2 = new ParametersAction();
thing.addAction(a1);
thing.addAction(a2);
CauseAction a3 = new CauseAction();
assertTrue(thing.replaceActions(CauseAction.class, a3));
assertEquals(Arrays.asList(a2, a3), thing.getActions());
assertFalse(thing.replaceActions(CauseAction.class, a3));
assertEquals(Arrays.asList(a2, a3), thing.getActions());
}
@SuppressWarnings("deprecation")
@Test
public void removeAction() {
CauseAction a1 = new CauseAction();
ParametersAction a2 = new ParametersAction();
thing.addAction(a1);
thing.addAction(a2);
assertEquals(Arrays.asList(a1, a2), thing.getActions());
assertThat(thing.removeAction(a1), is(true));
assertEquals(Arrays.asList(a2), thing.getActions());
assertThat(thing.removeAction(a1), is(false));
assertEquals(Arrays.asList(a2), thing.getActions());
assertThat(thing.removeAction(null), is(false));
assertEquals(Arrays.asList(a2), thing.getActions());
}
@SuppressWarnings("deprecation")
@Test
public void removeActions() {
CauseAction a1 = new CauseAction();
ParametersAction a2 = new ParametersAction();
thing.addAction(a1);
thing.addAction(a2);
assertEquals(Arrays.asList(a1, a2), thing.getActions());
assertThat(thing.removeActions(CauseAction.class), is(true));
assertEquals(Arrays.asList(a2), thing.getActions());
assertThat(thing.removeActions(CauseAction.class), is(false));
assertEquals(Arrays.asList(a2), thing.getActions());
}
@SuppressWarnings("deprecation")
@Test
public void addAction() {
CauseAction a1 = new CauseAction();
ParametersAction a2 = new ParametersAction();
assertEquals(Collections.<Action>emptyList(), thing.getActions());
thing.addAction(a1);
assertEquals(Collections.singletonList(a1), thing.getActions());
thing.addAction(a2);
assertEquals(Arrays.asList(a1, a2), thing.getActions());
}
@Test(expected = IllegalArgumentException.class)
public void addAction_null() {
thing.addAction(null);
}
@Test(expected = IllegalArgumentException.class)
public void replaceAction_null() {
thing.replaceAction(null);
}
@Test(expected = IllegalArgumentException.class)
public void replaceActions_null() {
thing.replaceActions(CauseAction.class, null);
}
@Test(expected = IllegalArgumentException.class)
public void replaceActions_null_null() {
thing.replaceActions(null, null);
}
@Test(expected = IllegalArgumentException.class)
public void addOrReplaceAction_null() {
thing.addOrReplaceAction(null);
}
@Test
public void removeAction_null() {
assertFalse(thing.removeAction(null));
}
@Test(expected = IllegalArgumentException.class)
public void removeActions_null() {
thing.removeActions(null);
}
private static class ActionableImpl extends Actionable {
@Override public String getDisplayName() {return null;}
@Override public String getSearchUrl() {return null;}
}
}
@@ -1,7 +1,6 @@
package hudson.model;
import hudson.util.FormValidation;
import jenkins.model.Jenkins;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -33,7 +33,7 @@ import org.jvnet.hudson.test.Issue;
/**
* Test for {@link FileParameterValue}.
* @author Oleg Nenashev <o.v.nenashev@gmail.com>
* @author Oleg Nenashev
*/
public class FileParameterValueTest {
@@ -27,6 +27,9 @@ import hudson.Util;
import hudson.model.Fingerprint.RangeSet;
import java.io.File;
import jenkins.model.FingerprintFacet;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;
import org.junit.Rule;
import org.junit.Test;
@@ -259,4 +262,274 @@ public class FingerprintTest {
}
}
@Test public void fromString() throws Exception {
//
// Single
//
// Numbers
assertThat(RangeSet.fromString("1", true).toString(), equalTo("[1,2)"));
assertThat(RangeSet.fromString("1", false).toString(), equalTo("[1,2)"));
assertThat(RangeSet.fromString("+1", true).toString(), equalTo("[1,2)"));
assertThat(RangeSet.fromString("+1", false).toString(), equalTo("[1,2)"));
// Zero
assertThat(RangeSet.fromString("0", true).toString(), equalTo("[0,1)"));
assertThat(RangeSet.fromString("0", false).toString(), equalTo("[0,1)"));
assertThat(RangeSet.fromString("+0", true).toString(), equalTo("[0,1)"));
assertThat(RangeSet.fromString("+0", false).toString(), equalTo("[0,1)"));
// Negative number
assertThat(RangeSet.fromString("-1", true).toString(), equalTo(""));
assertThat(expectIAE("-1", "Unable to parse '-1', expected string with a range M-N"), is(true));
// Exceeded int number
assertThat(RangeSet.fromString("2147483648", true).toString(), equalTo(""));
assertThat(expectIAE("2147483648", "Unable to parse '2147483648', expected number"), is(true));
// Invalid number
assertThat(RangeSet.fromString("1a", true).toString(), equalTo(""));
assertThat(expectIAE("1a", "Unable to parse '1a', expected number"), is(true));
assertThat(RangeSet.fromString("aa", true).toString(), equalTo(""));
assertThat(expectIAE("aa", "Unable to parse 'aa', expected number"), is(true));
//Empty
assertThat(RangeSet.fromString("", true).toString(), equalTo(""));
assertThat(RangeSet.fromString("", false).toString(), equalTo(""));
//Space
assertThat(RangeSet.fromString(" ", true).toString(), equalTo(""));
assertThat(expectIAE(" ", "Unable to parse ' ', expected number"), is(true));
// Comma
assertThat(RangeSet.fromString(",", true).toString(), equalTo(""));
assertThat(RangeSet.fromString(",", false).toString(), equalTo(""));
// Hyphen
assertThat(RangeSet.fromString("-", true).toString(), equalTo(""));
assertThat(expectIAE("-", "Unable to parse '-', expected string with a range M-N"), is(true));
//
// Multiple numbers
//
// Numbers
assertThat(RangeSet.fromString("1,2", true).toString(), equalTo("[1,2),[2,3)"));
assertThat(RangeSet.fromString("1,2", false).toString(), equalTo("[1,2),[2,3)"));
assertThat(RangeSet.fromString("1,+2,5", true).toString(), equalTo("[1,2),[2,3),[5,6)"));
assertThat(RangeSet.fromString("1,+2,5", false).toString(), equalTo("[1,2),[2,3),[5,6)"));
assertThat(RangeSet.fromString("1,1", true).toString(), equalTo("[1,2),[1,2)"));
assertThat(RangeSet.fromString("1,1", false).toString(), equalTo("[1,2),[1,2)"));
// Zero
assertThat(RangeSet.fromString("0,1,2", true).toString(), equalTo("[0,1),[1,2),[2,3)"));
assertThat(RangeSet.fromString("0,1,2", false).toString(), equalTo("[0,1),[1,2),[2,3)"));
assertThat(RangeSet.fromString("1,0,2", true).toString(), equalTo("[1,2),[0,1),[2,3)"));
assertThat(RangeSet.fromString("1,0,2", false).toString(), equalTo("[1,2),[0,1),[2,3)"));
assertThat(RangeSet.fromString("1,2,0", true).toString(), equalTo("[1,2),[2,3),[0,1)"));
assertThat(RangeSet.fromString("1,2,0", false).toString(), equalTo("[1,2),[2,3),[0,1)"));
// Negative number
assertThat(RangeSet.fromString("-1,2,3", true).toString(), equalTo("[2,3),[3,4)"));
assertThat(expectIAE("-1,2,3", "Unable to parse '-1,2,3', expected string with a range M-N"), is(true));
assertThat(RangeSet.fromString("1,-2,3", true).toString(), equalTo("[1,2),[3,4)"));
assertThat(expectIAE("1,-2,3", "Unable to parse '1,-2,3', expected string with a range M-N"), is(true));
assertThat(RangeSet.fromString("1,2,-3", true).toString(), equalTo("[1,2),[2,3)"));
assertThat(expectIAE("1,2,-3", "Unable to parse '1,2,-3', expected string with a range M-N"), is(true));
// Exceeded int number
assertThat(RangeSet.fromString("2147483648,2,3", true).toString(), equalTo("[2,3),[3,4)"));
assertThat(expectIAE("2147483648,1,2", "Unable to parse '2147483648,1,2', expected number"), is(true));
assertThat(RangeSet.fromString("1,2147483648,3", true).toString(), equalTo("[1,2),[3,4)"));
assertThat(expectIAE("1,2147483648,2", "Unable to parse '1,2147483648,2', expected number"), is(true));
assertThat(RangeSet.fromString("1,2,2147483648", true).toString(), equalTo("[1,2),[2,3)"));
assertThat(expectIAE("1,2,2147483648", "Unable to parse '1,2,2147483648', expected number"), is(true));
// Invalid number
assertThat(RangeSet.fromString("1a,2,3", true).toString(), equalTo("[2,3),[3,4)"));
assertThat(expectIAE("1a,1,2", "Unable to parse '1a,1,2', expected number"), is(true));
assertThat(RangeSet.fromString("1,2a,3", true).toString(), equalTo("[1,2),[3,4)"));
assertThat(expectIAE("1,2a,2", "Unable to parse '1,2a,2', expected number"), is(true));
assertThat(RangeSet.fromString("1,2,3a", true).toString(), equalTo("[1,2),[2,3)"));
assertThat(expectIAE("1,2,3a", "Unable to parse '1,2,3a', expected number"), is(true));
assertThat(RangeSet.fromString("aa,2,3", true).toString(), equalTo("[2,3),[3,4)"));
assertThat(expectIAE("aa,1,2", "Unable to parse 'aa,1,2', expected number"), is(true));
assertThat(RangeSet.fromString("1,aa,3", true).toString(), equalTo("[1,2),[3,4)"));
assertThat(expectIAE("1,aa,2", "Unable to parse '1,aa,2', expected number"), is(true));
assertThat(RangeSet.fromString("1,2,aa", true).toString(), equalTo("[1,2),[2,3)"));
assertThat(expectIAE("1,2,aa", "Unable to parse '1,2,aa', expected number"), is(true));
//Empty
assertThat(RangeSet.fromString(",1,2", true).toString(), equalTo(""));
assertThat(expectIAE(",1,2", "Unable to parse ',1,2', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("1,,2", true).toString(), equalTo(""));
assertThat(expectIAE("1,,2", "Unable to parse '1,,2', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("1,2,", true).toString(), equalTo(""));
assertThat(expectIAE("1,2,", "Unable to parse '1,2,', expected correct notation M,N or M-N"), is(true));
// Space
assertThat(RangeSet.fromString(" ,1,2", true).toString(), equalTo("[1,2),[2,3)"));
assertThat(expectIAE(" ,1,2", "Unable to parse ' ,1,2', expected number"), is(true));
assertThat(RangeSet.fromString("1, ,2", true).toString(), equalTo("[1,2),[2,3)"));
assertThat(expectIAE("1, ,2", "Unable to parse '1, ,2', expected number"), is(true));
assertThat(RangeSet.fromString("1,2, ", true).toString(), equalTo("[1,2),[2,3)"));
assertThat(expectIAE("1,2, ", "Unable to parse '1,2, ', expected number"), is(true));
// Comma
assertThat(RangeSet.fromString(",,1,2", true).toString(), equalTo(""));
assertThat(expectIAE(",,1,2", "Unable to parse ',,1,2', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("1,,,2", true).toString(), equalTo(""));
assertThat(expectIAE("1,,,2", "Unable to parse '1,,,2', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("1,2,,", true).toString(), equalTo(""));
assertThat(expectIAE("1,2,,", "Unable to parse '1,2,,', expected correct notation M,N or M-N"), is(true));
// Hyphen
assertThat(RangeSet.fromString("-,1,2", true).toString(), equalTo("[1,2),[2,3)"));
assertThat(expectIAE("-,1,2", "Unable to parse '-,1,2', expected string with a range M-N"), is(true));
assertThat(RangeSet.fromString("1,-,2", true).toString(), equalTo("[1,2),[2,3)"));
assertThat(expectIAE("1,-,2", "Unable to parse '1,-,2', expected string with a range M-N"), is(true));
assertThat(RangeSet.fromString("1,2,-", true).toString(), equalTo("[1,2),[2,3)"));
assertThat(expectIAE("1,2,-", "Unable to parse '1,2,-', expected string with a range M-N"), is(true));
//
// Single range
//
// Numbers
assertThat(RangeSet.fromString("1-2", true).toString(), equalTo("[1,3)"));
assertThat(RangeSet.fromString("1-2", false).toString(), equalTo("[1,3)"));
assertThat(RangeSet.fromString("+1-+2", true).toString(), equalTo("[1,3)"));
assertThat(RangeSet.fromString("+1-+2", false).toString(), equalTo("[1,3)"));
assertThat(RangeSet.fromString("1-1", true).toString(), equalTo("[1,2)"));
assertThat(RangeSet.fromString("1-1", false).toString(), equalTo("[1,2)"));
assertThat(RangeSet.fromString("+1-+1", true).toString(), equalTo("[1,2)"));
assertThat(RangeSet.fromString("+1-+1", false).toString(), equalTo("[1,2)"));
assertThat(RangeSet.fromString("1-4", true).toString(), equalTo("[1,5)"));
assertThat(RangeSet.fromString("1-4", false).toString(), equalTo("[1,5)"));
assertThat(RangeSet.fromString("+1-+4", true).toString(), equalTo("[1,5)"));
assertThat(RangeSet.fromString("+1-+4", false).toString(), equalTo("[1,5)"));
//Zero
assertThat(RangeSet.fromString("0-1", true).toString(), equalTo("[0,2)"));
assertThat(RangeSet.fromString("0-1", false).toString(), equalTo("[0,2)"));
assertThat(RangeSet.fromString("+0-+1", true).toString(), equalTo("[0,2)"));
assertThat(RangeSet.fromString("+0-+1", false).toString(), equalTo("[0,2)"));
assertThat(RangeSet.fromString("0-2", true).toString(), equalTo("[0,3)"));
assertThat(RangeSet.fromString("0-2", false).toString(), equalTo("[0,3)"));
assertThat(RangeSet.fromString("+0-+2", true).toString(), equalTo("[0,3)"));
assertThat(RangeSet.fromString("+0-+2", false).toString(), equalTo("[0,3)"));
assertThat(RangeSet.fromString("0--1", true).toString(), equalTo(""));
assertThat(expectIAE("0--1", "Unable to parse '0--1', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("+0--1", true).toString(), equalTo(""));
assertThat(expectIAE("+0--1", "Unable to parse '+0--1', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("0--2", true).toString(), equalTo(""));
assertThat(expectIAE("0--2", "Unable to parse '0--2', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("+0--2", true).toString(), equalTo(""));
assertThat(expectIAE("+0--2", "Unable to parse '+0--2', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("1-0", true).toString(), equalTo(""));
assertThat(expectIAE("1-0", "Unable to parse '1-0', expected string with a range M-N where M<N"), is(true));
assertThat(RangeSet.fromString("+1-+0", true).toString(), equalTo(""));
assertThat(expectIAE("+1-+0", "Unable to parse '+1-+0', expected string with a range M-N where M<N"), is(true));
assertThat(RangeSet.fromString("2-0", true).toString(), equalTo(""));
assertThat(expectIAE("2-0", "Unable to parse '2-0', expected string with a range M-N where M<N"), is(true));
assertThat(RangeSet.fromString("+2-+0", true).toString(), equalTo(""));
assertThat(expectIAE("+2-+0", "Unable to parse '+2-+0', expected string with a range M-N where M<N"), is(true));
assertThat(RangeSet.fromString("-1-0", true).toString(), equalTo(""));
assertThat(expectIAE("-1-0", "Unable to parse '-1-0', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("-1-+0", true).toString(), equalTo(""));
assertThat(expectIAE("-1-+0", "Unable to parse '-1-+0', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("-2-0", true).toString(), equalTo(""));
assertThat(expectIAE("-2-0", "Unable to parse '-2-0', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("-2-+0", true).toString(), equalTo(""));
assertThat(expectIAE("-2-+0", "Unable to parse '-2-+0', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("0-0", true).toString(), equalTo("[0,1)"));
assertThat(RangeSet.fromString("0-0", false).toString(), equalTo("[0,1)"));
assertThat(RangeSet.fromString("+0-+0", true).toString(), equalTo("[0,1)"));
assertThat(RangeSet.fromString("+0-+0", false).toString(), equalTo("[0,1)"));
// Negative number
assertThat(RangeSet.fromString("-1-1", true).toString(), equalTo(""));
assertThat(expectIAE("-1-1", "Unable to parse '-1-1', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("-1-+1", true).toString(), equalTo(""));
assertThat(expectIAE("-1-+1", "Unable to parse '-1-+1', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("-1-2", true).toString(), equalTo(""));
assertThat(expectIAE("-1-2", "Unable to parse '-1-2', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("-1-+2", true).toString(), equalTo(""));
assertThat(expectIAE("-1-+2", "Unable to parse '-1-+2', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("1--1", true).toString(), equalTo(""));
assertThat(expectIAE("1--1", "Unable to parse '1--1', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("+1--1", true).toString(), equalTo(""));
assertThat(expectIAE("+1--1", "Unable to parse '+1--1', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("1--2", true).toString(), equalTo(""));
assertThat(expectIAE("1--2", "Unable to parse '1--2', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("+1--2", true).toString(), equalTo(""));
assertThat(expectIAE("+1--2", "Unable to parse '+1--2', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("-1--1", true).toString(), equalTo(""));
assertThat(expectIAE("-1--1", "Unable to parse '-1--1', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("-2--1", true).toString(), equalTo(""));
assertThat(expectIAE("-2--1", "Unable to parse '-2--1', expected correct notation M,N or M-N"), is(true));
// Exceeded int number
assertThat(RangeSet.fromString("0-2147483648", true).toString(), equalTo(""));
assertThat(expectIAE("0-2147483648", "Unable to parse '0-2147483648', expected number"), is(true));
assertThat(RangeSet.fromString("2147483648-0", true).toString(), equalTo(""));
assertThat(expectIAE("2147483648-0", "Unable to parse '2147483648-0', expected number"), is(true));
assertThat(RangeSet.fromString("2147483648-2147483648", true).toString(), equalTo(""));
assertThat(expectIAE("2147483648-2147483648", "Unable to parse '2147483648-2147483648', expected number"), is(true));
// Invalid number
assertThat(RangeSet.fromString("1-2a", true).toString(), equalTo(""));
assertThat(expectIAE("1-2a", "Unable to parse '1-2a', expected number"), is(true));
assertThat(RangeSet.fromString("2a-2", true).toString(), equalTo(""));
assertThat(expectIAE("2a-2", "Unable to parse '2a-2', expected number"), is(true));
assertThat(RangeSet.fromString("2a-2a", true).toString(), equalTo(""));
assertThat(expectIAE("2a-2a", "Unable to parse '2a-2a', expected number"), is(true));
assertThat(RangeSet.fromString("aa-2", true).toString(), equalTo(""));
assertThat(expectIAE("aa-2", "Unable to parse 'aa-2', expected number"), is(true));
assertThat(RangeSet.fromString("1-aa", true).toString(), equalTo(""));
assertThat(expectIAE("1-aa", "Unable to parse '1-aa', expected number"), is(true));
assertThat(RangeSet.fromString("aa-aa", true).toString(), equalTo(""));
assertThat(expectIAE("aa-aa", "Unable to parse 'aa-aa', expected number"), is(true));
// Empty
assertThat(RangeSet.fromString("-1", true).toString(), equalTo(""));
assertThat(expectIAE("-1", "Unable to parse '-1', expected string with a range M-N"), is(true));
assertThat(RangeSet.fromString("1-", true).toString(), equalTo(""));
assertThat(expectIAE("1-", "Unable to parse '1-', expected string with a range M-N"), is(true));
assertThat(RangeSet.fromString("-", true).toString(), equalTo(""));
assertThat(expectIAE("-", "Unable to parse '-', expected string with a range M-N"), is(true));
// Space
assertThat(RangeSet.fromString(" -1", true).toString(), equalTo(""));
assertThat(expectIAE(" -1", "Unable to parse ' -1', expected string with a range M-N"), is(true));
assertThat(RangeSet.fromString("1- ", true).toString(), equalTo(""));
assertThat(expectIAE("1- ", "Unable to parse '1- ', expected string with a range M-N"), is(true));
assertThat(RangeSet.fromString(" - ", true).toString(), equalTo(""));
assertThat(expectIAE(" - ", "Unable to parse ' - ', expected string with a range M-N"), is(true));
// Comma
assertThat(RangeSet.fromString(",-1", true).toString(), equalTo(""));
assertThat(expectIAE(",-1", "Unable to parse ',-1', expected string with a range M-N"), is(true));
assertThat(RangeSet.fromString("1-,", true).toString(), equalTo(""));
assertThat(expectIAE("1-,", "Unable to parse '1-,', expected string with a range M-N"), is(true));
assertThat(RangeSet.fromString(",-,", true).toString(), equalTo(""));
assertThat(expectIAE(",-,", "Unable to parse ',-,', expected string with a range M-N"), is(true));
// Hyphen
assertThat(RangeSet.fromString("--1", true).toString(), equalTo(""));
assertThat(expectIAE("--1", "Unable to parse '--1', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("1--", true).toString(), equalTo(""));
assertThat(expectIAE("1--", "Unable to parse '1--', expected correct notation M,N or M-N"), is(true));
assertThat(RangeSet.fromString("---", true).toString(), equalTo(""));
assertThat(expectIAE("---", "Unable to parse '---', expected correct notation M,N or M-N"), is(true));
// Inverse range
assertThat(RangeSet.fromString("2-1", true).toString(), equalTo(""));
assertThat(expectIAE("2-1", "Unable to parse '2-1', expected string with a range M-N where M<N"), is(true));
assertThat(RangeSet.fromString("10-1", true).toString(), equalTo(""));
assertThat(expectIAE("10-1", "Unable to parse '10-1', expected string with a range M-N where M<N"), is(true));
assertThat(RangeSet.fromString("-1--2", true).toString(), equalTo(""));
assertThat(expectIAE("-1--2", "Unable to parse '-1--2', expected correct notation M,N or M-N"), is(true));
// Invalid range
assertThat(RangeSet.fromString("1-3-", true).toString(), equalTo(""));
assertThat(expectIAE("1-3-", "Unable to parse '1-3-', expected correct notation M,N or M-N"), is(true));
//
// Multiple ranges
//
assertThat(RangeSet.fromString("1-3,3-5", true).toString(), equalTo("[1,4),[3,6)"));
assertThat(RangeSet.fromString("1-3,4-6", true).toString(), equalTo("[1,4),[4,7)"));
assertThat(RangeSet.fromString("1-3,5-7", true).toString(), equalTo("[1,4),[5,8)"));
assertThat(RangeSet.fromString("1-3,2-3", true).toString(), equalTo("[1,4),[2,4)"));
assertThat(RangeSet.fromString("1-5,2-3", true).toString(), equalTo("[1,6),[2,4)"));
}
private boolean expectIAE(final String expr, final String msg) {
try {
RangeSet.fromString(expr, false);
} catch (Throwable e) {
if (e instanceof IllegalArgumentException) {
if (e.getMessage().isEmpty()) {
return msg.isEmpty();
}
else {
return msg.isEmpty() ? false : e.getMessage().contains(msg);
}
}
}
// Exception wasn't throws or thrown Exception wasn't an instance of IllegalArgumentException
fail("Should never be here");
return false;
}
}
+23 -5
View File
@@ -3,16 +3,13 @@ package hudson.model;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.*;
/**
* @author: <a hef="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
* @author: <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
*/
public class ItemsTest {
@@ -44,6 +41,27 @@ public class ItemsTest {
assertEquals("foo/bar", Items.getCanonicalName(foo, "./bar"));
assertEquals("foo/bar/baz/qux", Items.getCanonicalName(foo_bar, "baz/qux"));
assertEquals("foo/baz/qux", Items.getCanonicalName(foo_bar, "../baz/qux"));
try {
Items.getCanonicalName(root, "..");
fail();
} catch (IllegalArgumentException ex) {
assertEquals("Illegal relative path '..' within context ''", ex.getMessage());
}
try {
Items.getCanonicalName(foo, "../..");
fail();
} catch (IllegalArgumentException ex) {
assertEquals("Illegal relative path '../..' within context 'foo'", ex.getMessage());
}
try {
Items.getCanonicalName(root, "foo/../..");
fail();
} catch (IllegalArgumentException ex) {
assertEquals("Illegal relative path 'foo/../..' within context ''", ex.getMessage());
}
}
@Test
@@ -30,7 +30,7 @@ public class ListViewTest {
mockStatic(Items.class);
mockStatic(ListViewColumn.class);
List<ListViewColumn> columns = Collections.emptyList();
when(ListViewColumn.createDefaultInitialColumnList()).thenReturn(columns);
when(ListViewColumn.createDefaultInitialColumnList(ListView.class)).thenReturn(columns);
ViewGroup owner = mock(ViewGroup.class);
ItemGroup itemGroupOwner = mock(ItemGroup.class);
when(owner.getItemGroup()).thenReturn(itemGroupOwner);
@@ -49,7 +49,7 @@ public class ListViewTest {
mockStatic(Items.class);
mockStatic(ListViewColumn.class);
List<ListViewColumn> columns = Collections.emptyList();
when(ListViewColumn.createDefaultInitialColumnList()).thenReturn(columns);
when(ListViewColumn.createDefaultInitialColumnList(ListView.class)).thenReturn(columns);
ViewGroup owner = mock(ViewGroup.class);
ItemGroup ig = mock(ItemGroup.class);
when(owner.getItemGroup()).thenReturn(ig);
@@ -0,0 +1,66 @@
/*
* The MIT License
*
* Copyright (c) 2013-2015, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.model;
import hudson.model.queue.CauseOfBlockage;
import java.util.Collections;
import java.util.List;
/**
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*/
public class MockItem extends Queue.Item {
public MockItem(long id) {
super(null, Collections.<Action>emptyList(), id, null);
}
public MockItem(Queue.Task task, List<Action> actions, long id) {
super(task, actions, id, null);
}
/**
* Override as needed.
*/
@Override
public CauseOfBlockage getCauseOfBlockage() {
return null;
}
/**
* Override as needed.
*/
@Override
void enter(Queue q) {
}
/**
* Override as needed.
*/
@Override
boolean leave(Queue q) {
return true;
}
}
@@ -89,7 +89,7 @@ public class ParametersActionTest {
@Test
@Issue("JENKINS-15094")
public void checkNullParamaterValues() {
public void checkNullParameterValues() {
SubTask subtask = mock(SubTask.class);
Build build = mock(Build.class);
+43 -1
View File
@@ -159,7 +159,7 @@ public class RunTest {
Job j = Mockito.mock(Job.class);
File tempBuildDir = tmp.newFolder();
Mockito.when(j.getBuildDir()).thenReturn(tempBuildDir);
Run r = new Run(j, 0) {};
Run<? extends Job<?, ?>, ? extends Run<?, ?>> r = new Run(j, 0) {};
File f = r.getLogFile();
f.getParentFile().mkdirs();
PrintWriter w = new PrintWriter(f, "utf-8");
@@ -169,4 +169,46 @@ public class RunTest {
assertTrue(logLines.isEmpty());
}
@Test
public void getLogReturnsAnRightOrder() throws Exception {
Job j = Mockito.mock(Job.class);
File tempBuildDir = tmp.newFolder();
Mockito.when(j.getBuildDir()).thenReturn(tempBuildDir);
Run<? extends Job<?, ?>, ? extends Run<?, ?>> r = new Run(j, 0) {};
File f = r.getLogFile();
f.getParentFile().mkdirs();
PrintWriter w = new PrintWriter(f, "utf-8");
for (int i = 0; i < 20; i++) {
w.println("dummy" + i);
}
w.close();
List<String> logLines = r.getLog(10);
assertFalse(logLines.isEmpty());
for (int i = 1; i < 10; i++) {
assertEquals("dummy" + (10+i), logLines.get(i));
}
assertEquals("[...truncated 68 B...]", logLines.get(0));
}
@Test
public void getLogReturnsAllLines() throws Exception {
Job j = Mockito.mock(Job.class);
File tempBuildDir = tmp.newFolder();
Mockito.when(j.getBuildDir()).thenReturn(tempBuildDir);
Run<? extends Job<?, ?>, ? extends Run<?, ?>> r = new Run(j, 0) {};
File f = r.getLogFile();
f.getParentFile().mkdirs();
PrintWriter w = new PrintWriter(f, "utf-8");
w.print("a1\nb2\n\nc3");
w.close();
List<String> logLines = r.getLog(10);
assertFalse(logLines.isEmpty());
assertEquals("a1", logLines.get(0));
assertEquals("b2", logLines.get(1));
assertEquals("", logLines.get(2));
assertEquals("c3", logLines.get(3));
}
}
@@ -0,0 +1,44 @@
package hudson.model;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class UpdateCenterTest {
@Test
public void toUpdateCenterCheckUrl_http_noQuery() throws Exception {
assertThat(UpdateCenter.UpdateCenterConfiguration.toUpdateCenterCheckUrl(
"http://updates.jenkins-ci.org/update-center.json").toExternalForm(),
is("http://updates.jenkins-ci.org/update-center.json?uctest"));
}
@Test
public void toUpdateCenterCheckUrl_https_noQuery() throws Exception {
assertThat(UpdateCenter.UpdateCenterConfiguration.toUpdateCenterCheckUrl(
"https://updates.jenkins-ci.org/update-center.json").toExternalForm(),
is("https://updates.jenkins-ci.org/update-center.json?uctest"));
}
@Test
public void toUpdateCenterCheckUrl_http_query() throws Exception {
assertThat(UpdateCenter.UpdateCenterConfiguration.toUpdateCenterCheckUrl(
"http://updates.jenkins-ci.org/update-center.json?version=2.7").toExternalForm(),
is("http://updates.jenkins-ci.org/update-center.json?version=2.7&uctest"));
}
@Test
public void toUpdateCenterCheckUrl_https_query() throws Exception {
assertThat(UpdateCenter.UpdateCenterConfiguration.toUpdateCenterCheckUrl(
"https://updates.jenkins-ci.org/update-center.json?version=2.7").toExternalForm(),
is("https://updates.jenkins-ci.org/update-center.json?version=2.7&uctest"));
}
@Test
public void toUpdateCenterCheckUrl_file() throws Exception {
assertThat(UpdateCenter.UpdateCenterConfiguration.toUpdateCenterCheckUrl(
"file://./foo.jar!update-center.json").toExternalForm(),
is("file://./foo.jar!update-center.json"));
}
}
@@ -0,0 +1,73 @@
package hudson.model;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
/*
* The MIT License
*
* Copyright (c) 2016 Oleg Nenashev.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Unit tests for the {@link User} class.
* @author Oleg Nenashev
*/
public class UserTest {
@Test
@Issue("JENKINS-33600")
public void blankIdsOrFullNamesShouldNotBeAllowed() {
assertThat("Null user IDs should not be allowed", User.isIdOrFullnameAllowed(null), is(false));
assertThat("Empty user IDs should not be allowed", User.isIdOrFullnameAllowed(""), is(false));
assertThat("Blank user IDs should not be allowed", User.isIdOrFullnameAllowed(" "), is(false));
}
@Test
@Issue("JENKINS-35967")
public void shoudNotAllowIllegalRestrictedNamesInWrongCase() {
assertIdOrFullNameNotAllowed("system");
assertIdOrFullNameNotAllowed("System");
assertIdOrFullNameNotAllowed("SYSTEM");
assertIdOrFullNameNotAllowed("syStem");
assertIdOrFullNameNotAllowed("sYstEm");
}
@Test
@Issue("JENKINS-35967")
public void shoudNotAllowIllegalRestrictedNamesEvenIfTrimmed() {
for (String username : User.getIllegalPersistedUsernames()) {
assertIdOrFullNameNotAllowed(username);
assertIdOrFullNameNotAllowed(" " + username);
assertIdOrFullNameNotAllowed(username + " ");
assertIdOrFullNameNotAllowed(" " + username + " ");
assertIdOrFullNameNotAllowed("\t" + username + "\t");
}
}
private void assertIdOrFullNameNotAllowed(String id) {
assertThat("User ID or full name '" + id + "' should not be allowed",
User.isIdOrFullnameAllowed(id), is(false));
}
}
@@ -14,14 +14,14 @@ import java.util.Properties;
* creating an instance.
*
* <p>
* It turns out that the bogus credential works with ServerAlive. The protocol specification
* <http://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-DCOM%5D.pdf>
* It turns out that the bogus credential works with ServerAlive. The
* <a href="http://download.microsoft.com/download/a/e/6/ae6e4142-aa58-45c6-8dcf-a657e5900cd3/%5BMS-DCOM%5D.pdf">protocol specification</a>
* explicitly says this RPC must not check the credential.
*
* <p>
* The feature in question of Windows is called "ForceGuest", and it's recorded in the registry at
* HKLM\SYSTEM\CurrentControlSet\Control\LSA\forceguest (0=classic, 1=forceguest).
* <http://support.microsoft.com/kb/290403>
* <a href="http://support.microsoft.com/kb/290403">KB 290403</a>
*
* @author Kohsuke Kawaguchi
*/
@@ -1,6 +1,5 @@
package hudson.os;
import hudson.remoting.Callable;
import hudson.util.StreamTaskListener;
import jenkins.security.MasterToSlaveCallable;
@@ -27,7 +27,6 @@ import antlr.ANTLRException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.GregorianCalendar;
import java.util.Locale;
@@ -0,0 +1,26 @@
package hudson.slaves;
import static org.junit.Assert.*;
import hudson.model.Computer;
import hudson.security.Permission;
import hudson.security.SidACL;
import jenkins.model.Jenkins;
import org.acegisecurity.acls.sid.Sid;
import org.junit.Test;
public class CloudTest {
@Test
public void provisionPermissionShouldBeIndependentFromAdminister() throws Exception {
SidACL acl = new SidACL() {
@Override protected Boolean hasPermission(Sid p, Permission permission) {
return permission == Cloud.PROVISION;
}
};
assertTrue(acl.hasPermission(Jenkins.ANONYMOUS, Cloud.PROVISION));
assertFalse(acl.hasPermission(Jenkins.ANONYMOUS, Jenkins.ADMINISTER));
assertEquals(Cloud.PROVISION, Computer.PERMISSIONS.find("Provision"));
}
}
@@ -24,17 +24,16 @@
package hudson.slaves;
import edu.umd.cs.findbugs.annotations.SuppressWarnings;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.StringReader;
import org.apache.commons.io.output.NullOutputStream;
import org.junit.Test;
import static org.junit.Assert.*;
@SuppressWarnings("DM_DEFAULT_ENCODING")
public class ComputerLauncherTest {
@Test public void jdk7() throws IOException {
@@ -0,0 +1,71 @@
package hudson.slaves;
import hudson.DescriptorExtensionList;
import hudson.model.Descriptor;
import jenkins.model.Jenkins;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.util.ArrayList;
import static org.junit.Assert.*;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;
/**
* @author peppelan
*/
@RunWith(PowerMockRunner.class)
public class DelegatingComputerLauncherTest {
public static class DummyOne extends DelegatingComputerLauncher {
public DummyOne() {
super(null);
}
public static class DummyOneDescriptor extends DescriptorImpl {
}
}
public static class DummyTwo extends DelegatingComputerLauncher {
public DummyTwo() {
super(null);
}
public static class DummyTwoDescriptor extends DescriptorImpl {
}
}
// Ensure that by default a DelegatingComputerLauncher subclass doesn't advertise the option to delegate another
// DelegatingComputerLauncher
@Test
@PrepareForTest(Jenkins.class)
public void testRecursionAvoidance() {
PowerMockito.mockStatic(Jenkins.class);
Jenkins mockJenkins = mock(Jenkins.class);
PowerMockito.when(Jenkins.getInstance()).thenReturn(mockJenkins);
DescriptorExtensionList<ComputerLauncher, Descriptor<ComputerLauncher>> mockList =
mock(DescriptorExtensionList.class);
doReturn(mockList).when(mockJenkins).getDescriptorList(eq(ComputerLauncher.class));
ArrayList<Descriptor<ComputerLauncher>> returnedList = new ArrayList<>();
returnedList.add(new DummyOne.DummyOneDescriptor());
returnedList.add(new DummyTwo.DummyTwoDescriptor());
when(mockList.iterator()).thenReturn(returnedList.iterator());
assertTrue("DelegatingComputerLauncher should filter out other DelegatingComputerLauncher instances " +
"from its descriptor's getApplicableDescriptors() method",
new DummyTwo.DummyTwoDescriptor().applicableDescriptors(null, new DumbSlave.DescriptorImpl()).isEmpty());
}
}
@@ -0,0 +1,42 @@
/*
* The MIT License
*
* Copyright (c) 2015 Kanstantsin Shautsou
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.triggers;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
/**
* @author Kanstantsin Shautsou
*/
public class SCMTriggerTest {
@Issue({"JENKINS-29790", "JENKINS-29945"})
@Test
public void testNoNPE() throws Exception {
final SCMTrigger scmTrigger = new SCMTrigger("");
scmTrigger.run();
scmTrigger.run(null);
scmTrigger.getProjectActions();
}
}
@@ -0,0 +1,39 @@
/*
* The MIT License
*
* Copyright (c) 2015 Kanstantsin Shautsou
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.triggers;
import antlr.ANTLRException;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
/**
* @author Kanstantsin Shautsou
*/
public class TimerTriggerTest {
@Issue("JENKINS-29790")
@Test
public void testNoNPE() throws ANTLRException {
new TimerTrigger("").run();
}
}
@@ -31,7 +31,10 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.junit.Ignore;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
public class ArgumentListBuilderTest {
@@ -41,7 +44,7 @@ public class ArgumentListBuilderTest {
builder.add("arg");
builder.add("other", "arguments");
assertFalse("There shouldnt be any masked arguments", builder.hasMaskedArguments());
assertFalse("There should not be any masked arguments", builder.hasMaskedArguments());
boolean[] array = builder.toMaskArray();
assertNotNull("The mask array should not be null", array);
assertThat("The mask array was incorrect", array, is(new boolean[] { false, false, false }));
@@ -101,28 +104,51 @@ public class ArgumentListBuilderTest {
@Test
public void testToWindowsCommand() {
ArgumentListBuilder builder = new ArgumentListBuilder(
"ant.bat", "-Dfoo1=abc", // nothing special, no quotes
"-Dfoo2=foo bar", "-Dfoo3=/u*r", "-Dfoo4=/us?", // add quotes
"-Dfoo10=bar,baz",
"-Dfoo5=foo;bar^baz", "-Dfoo6=<xml>&here;</xml>", // add quotes
"-Dfoo7=foo|bar\"baz", // add quotes and "" for "
"-Dfoo8=% %QED% %comspec% %-%(%.%", // add quotes, and extra quotes for %Q and %c
"-Dfoo9=%'''%%@%"); // no quotes as none of the % are followed by a letter
ArgumentListBuilder builder = new ArgumentListBuilder().
add("ant.bat").add("-Dfoo1=abc"). // nothing special, no quotes
add("-Dfoo2=foo bar").add("-Dfoo3=/u*r").add("-Dfoo4=/us?"). // add quotes
add("-Dfoo10=bar,baz").
add("-Dfoo5=foo;bar^baz").add("-Dfoo6=<xml>&here;</xml>"). // add quotes
add("-Dfoo7=foo|bar\"baz"). // add quotes and "" for "
add("-Dfoo8=% %QED% %comspec% %-%(%.%"). // add quotes, and extra quotes for %Q and %c
add("-Dfoo9=%'''%%@%"); // no quotes as none of the % are followed by a letter
// By default, does not escape %VAR%
assertThat(builder.toWindowsCommand().toCommandArray(), is(new String[] { "cmd.exe", "/C",
"\"ant.bat -Dfoo1=abc \"-Dfoo2=foo bar\""
+ " \"-Dfoo3=/u*r\" \"-Dfoo4=/us?\" \"-Dfoo10=bar,baz\" \"-Dfoo5=foo;bar^baz\""
+ " \"-Dfoo6=<xml>&here;</xml>\" \"-Dfoo7=foo|bar\"\"baz\""
+ " \"-Dfoo8=% %QED% %comspec% %-%(%.%\""
+ " -Dfoo9=%'''%%@% && exit %%ERRORLEVEL%%\"" }));
"\"ant.bat", "-Dfoo1=abc", "\"-Dfoo2=foo bar\"", "\"-Dfoo3=/u*r\"", "\"-Dfoo4=/us?\"",
"\"-Dfoo10=bar,baz\"", "\"-Dfoo5=foo;bar^baz\"", "\"-Dfoo6=<xml>&here;</xml>\"",
"\"-Dfoo7=foo|bar\"\"baz\"", "\"-Dfoo8=% %QED% %comspec% %-%(%.%\"",
"-Dfoo9=%'''%%@%", "&&", "exit", "%%ERRORLEVEL%%\"" }));
// Pass flag to escape %VAR%
assertThat(builder.toWindowsCommand(true).toCommandArray(), is(new String[] { "cmd.exe", "/C",
"\"ant.bat -Dfoo1=abc \"-Dfoo2=foo bar\""
+ " \"-Dfoo3=/u*r\" \"-Dfoo4=/us?\" \"-Dfoo10=bar,baz\" \"-Dfoo5=foo;bar^baz\""
+ " \"-Dfoo6=<xml>&here;</xml>\" \"-Dfoo7=foo|bar\"\"baz\""
+ " \"-Dfoo8=% %\"Q\"ED% %\"c\"omspec% %-%(%.%\""
+ " -Dfoo9=%'''%%@% && exit %%ERRORLEVEL%%\"" }));
"\"ant.bat", "-Dfoo1=abc", "\"-Dfoo2=foo bar\"", "\"-Dfoo3=/u*r\"", "\"-Dfoo4=/us?\"",
"\"-Dfoo10=bar,baz\"", "\"-Dfoo5=foo;bar^baz\"", "\"-Dfoo6=<xml>&here;</xml>\"",
"\"-Dfoo7=foo|bar\"\"baz\"", "\"-Dfoo8=% %\"Q\"ED% %\"c\"omspec% %-%(%.%\"",
"-Dfoo9=%'''%%@%", "&&", "exit", "%%ERRORLEVEL%%\"" }));
// Try to hide password
builder.add("-Dpassword=hidden", true);
// By default, does not escape %VAR%
assertThat(builder.toWindowsCommand().toString(), is("cmd.exe /C \"ant.bat -Dfoo1=abc \"\"-Dfoo2=foo bar\"\" \"-Dfoo3=/u*r\" \"-Dfoo4=/us?\" \"-Dfoo10=bar,baz\" \"-Dfoo5=foo;bar^baz\" \"-Dfoo6=<xml>&here;</xml>\" \"-Dfoo7=foo|bar\"\"baz\" \"\"-Dfoo8=% %QED% %comspec% %-%(%.%\"\" -Dfoo9=%'''%%@% ****** && exit %%ERRORLEVEL%%\"" ));
// Pass flag to escape %VAR%
assertThat(builder.toWindowsCommand(true).toString(), is("cmd.exe /C \"ant.bat -Dfoo1=abc \"\"-Dfoo2=foo bar\"\" \"-Dfoo3=/u*r\" \"-Dfoo4=/us?\" \"-Dfoo10=bar,baz\" \"-Dfoo5=foo;bar^baz\" \"-Dfoo6=<xml>&here;</xml>\" \"-Dfoo7=foo|bar\"\"baz\" \"\"-Dfoo8=% %\"Q\"ED% %\"c\"omspec% %-%(%.%\"\" -Dfoo9=%'''%%@% ****** && exit %%ERRORLEVEL%%\""));
}
@Test
@Ignore("It's only for reproduce JENKINS-28790 issue. It's added to testToWindowsCommand")
@Issue("JENKINS-28790")
public void testToWindowsCommandMasked() {
ArgumentListBuilder builder = new ArgumentListBuilder().
add("ant.bat").add("-Dfoo1=abc"). // nothing special, no quotes
add("-Dfoo2=foo bar").add("-Dfoo3=/u*r").add("-Dfoo4=/us?"). // add quotes
add("-Dfoo10=bar,baz").
add("-Dfoo5=foo;bar^baz").add("-Dfoo6=<xml>&here;</xml>"). // add quotes
add("-Dfoo7=foo|bar\"baz"). // add quotes and "" for "
add("-Dfoo8=% %QED% %comspec% %-%(%.%"). // add quotes, and extra quotes for %Q and %c
add("-Dfoo9=%'''%%@%"). // no quotes as none of the % are followed by a letter
add("-Dpassword=hidden", true);
// By default, does not escape %VAR%
assertThat(builder.toWindowsCommand().toString(), is("cmd.exe /C \"ant.bat -Dfoo1=abc \"\"-Dfoo2=foo bar\"\" \"-Dfoo3=/u*r\" \"-Dfoo4=/us?\" \"-Dfoo10=bar,baz\" \"-Dfoo5=foo;bar^baz\" \"-Dfoo6=<xml>&here;</xml>\" \"-Dfoo7=foo|bar\"\"baz\" \"\"-Dfoo8=% %QED% %comspec% %-%(%.%\"\" -Dfoo9=%'''%%@% ****** && exit %%ERRORLEVEL%%\"" ));
// Pass flag to escape %VAR%
assertThat(builder.toWindowsCommand(true).toString(), is("cmd.exe /C \"ant.bat -Dfoo1=abc \"\"-Dfoo2=foo bar\"\" \"-Dfoo3=/u*r\" \"-Dfoo4=/us?\" \"-Dfoo10=bar,baz\" \"-Dfoo5=foo;bar^baz\" \"-Dfoo6=<xml>&here;</xml>\" \"-Dfoo7=foo|bar\"\"baz\" \"\"-Dfoo8=% %\"Q\"ED% %\"c\"omspec% %-%(%.%\"\" -Dfoo9=%'''%%@% ****** && exit %%ERRORLEVEL%%\""));
}
@Test
@@ -166,7 +192,7 @@ public class ArgumentListBuilderTest {
ArgumentListBuilder builder = new ArgumentListBuilder();
builder.addKeyValuePairs(null, KEY_VALUES);
assertFalse("There shouldnt be any masked arguments", builder.hasMaskedArguments());
assertFalse("There should not be any masked arguments", builder.hasMaskedArguments());
boolean[] array = builder.toMaskArray();
assertNotNull("The mask array should not be null", array);
assertThat("The mask array was incorrect", array, is(new boolean[] { false, false, false }));
@@ -0,0 +1,80 @@
/*
* The MIT License
*
* Copyright (c) 2015, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.util;
import org.junit.Test;
import static org.junit.Assert.*;
import hudson.Util;
/**
* Test for {@link Util.isOverridden} method.
*/
public class IsOverriddenTest {
/**
* Test that a method is found by isOverridden even when it is inherited from an intermediate class.
*/
@Test
public void isOverriddenTest() {
assertTrue(Util.isOverridden(Base.class, Derived.class, "method"));
assertTrue(Util.isOverridden(Base.class, Intermediate.class, "method"));
assertFalse(Util.isOverridden(Base.class, Base.class, "method"));
assertTrue(Util.isOverridden(Base.class, Intermediate.class, "setX", Object.class));
assertTrue(Util.isOverridden(Base.class, Intermediate.class, "getX"));
}
/**
* Negative test.
* Trying to check for a method which does not exist in the hierarchy,
*/
@Test(expected = IllegalArgumentException.class)
public void isOverriddenNegativeTest() {
Util.isOverridden(Base.class, Derived.class, "method2");
}
/**
* Do not inspect private methods.
*/
@Test(expected = IllegalArgumentException.class)
public void avoidPrivateMethodsInspection() {
Util.isOverridden(Base.class, Intermediate.class, "aPrivateMethod");
}
public abstract class Base<T> {
protected abstract void method();
private void aPrivateMethod() {}
public void setX(T t) {}
public T getX() { return null; }
}
public abstract class Intermediate extends Base<Integer> {
protected void method() {}
private void aPrivateMethod() {}
public void setX(Integer i) {}
public Integer getX() { return 0; }
}
public class Derived extends Intermediate {}
}
@@ -0,0 +1,56 @@
/*
* The MIT License
*
* Copyright (c) 2015, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.util;
import net.sf.json.JSONObject;
import org.junit.Assert;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
/**
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*/
public class JSONObjectResponseTest {
@Test
public void test() {
Map<String, String> data = new HashMap<>();
data.put("val_1", "1");
HttpResponses.JSONObjectResponse response = new HttpResponses.JSONObjectResponse(data);
JSONObject payload = response.getJsonObject();
Assert.assertEquals("ok", payload.getString("status"));
JSONObject payloadData = payload.getJSONObject("data");
Assert.assertEquals("1", payloadData.getString("val_1"));
// change it to an error
response.error("a message");
Assert.assertEquals("error", payload.getString("status"));
Assert.assertEquals("a message", payload.getString("message"));
}
}
@@ -0,0 +1,43 @@
/*
* The MIT License
*
* Copyright (c) 2015, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.util;
import org.junit.Assert;
import org.junit.Test;
/**
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*/
public class MultipartFormDataParserTest {
@Test
public void testIsMultipart() throws Exception {
Assert.assertFalse("Wrongly identified \"multipart/form-data\"", MultipartFormDataParser.isMultiPartForm(null));
Assert.assertFalse("Wrongly identified \"multipart/form-data\"", MultipartFormDataParser.isMultiPartForm("blah"));
Assert.assertTrue("Failed to identify \"multipart/form-data\"", MultipartFormDataParser.isMultiPartForm("multipart/form-data"));
Assert.assertTrue("Failed to identify \"multipart/form-data\"", MultipartFormDataParser.isMultiPartForm("multipart/form-data;"));
Assert.assertTrue("Failed to identify \"multipart/form-data\"", MultipartFormDataParser.isMultiPartForm("multipart/form-data; boundary=----WebKitFormBoundary8OOwv1Xp4c5XkBmD"));
}
}
@@ -8,6 +8,8 @@ import java.io.IOException;
import java.io.Serializable;
import jenkins.security.MasterToSlaveCallable;
import static org.junit.Assert.*;
import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
@@ -26,9 +28,7 @@ public class ProcessTreeTest {
}
@Test public void remoting() throws Exception {
// on some platforms where we fail to list any processes, this test will just not work
if (ProcessTree.get()==ProcessTree.DEFAULT)
return;
Assume.assumeFalse("on some platforms where we fail to list any processes", ProcessTree.get()==ProcessTree.DEFAULT);
Tag t = channels.french.call(new MyCallable());
@@ -272,37 +272,6 @@ public class XStream2Test {
ConcurrentHashMap<String,String> m = new ConcurrentHashMap<String,String>();
}
/**
* Tests that ConcurrentHashMap is serialized into a more compact format,
* but still can deserialize to older, verbose format.
*/
@Test
public void concurrentHashMapSerialization() throws Exception {
Foo2 foo = new Foo2();
foo.m.put("abc","def");
foo.m.put("ghi","jkl");
File v = File.createTempFile("hashmap", "xml");
try {
new XmlFile(v).write(foo);
// should serialize like map
String xml = FileUtils.readFileToString(v);
assertFalse(xml.contains("java.util.concurrent"));
//System.out.println(xml);
Foo2 deserialized = (Foo2) new XStream2().fromXML(xml);
assertEquals(2,deserialized.m.size());
assertEquals("def", deserialized.m.get("abc"));
assertEquals("jkl", deserialized.m.get("ghi"));
} finally {
v.delete();
}
// should be able to read in old data just fine
Foo2 map = (Foo2) new XStream2().fromXML(getClass().getResourceAsStream("old-concurrentHashMap.xml"));
assertEquals(1,map.m.size());
assertEquals("def",map.m.get("abc"));
}
@Issue("SECURITY-105")
@Test
public void dynamicProxyBlocked() {
@@ -32,7 +32,10 @@ import hudson.util.NullStream;
import hudson.util.StreamTaskListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import static org.junit.Assert.*;
import org.junit.Assume;
import static org.junit.Assume.*;
import org.junit.Rule;
import org.junit.Test;
@@ -76,7 +79,7 @@ public class TarArchiverTest {
e.mkdirs();
// extract via the tar command
assertEquals(0, new LocalLauncher(new StreamTaskListener(System.out)).launch().cmds("tar", "xvpf", tar.getAbsolutePath()).pwd(e).join());
run(e, "tar", "xvpf", tar.getAbsolutePath());
assertEquals(0100755,e.child("a.txt").mode());
assertEquals(dirMode,e.child("subdir").mode());
@@ -85,7 +88,7 @@ public class TarArchiverTest {
// extract via the zip command
e.deleteContents();
assertEquals(0, new LocalLauncher(new StreamTaskListener(System.out)).launch().cmds("unzip", zip.getAbsolutePath()).pwd(e).join());
run(e, "unzip", zip.getAbsolutePath());
e = e.listDirectories().get(0);
assertEquals(0100755, e.child("a.txt").mode());
@@ -98,6 +101,14 @@ public class TarArchiverTest {
}
}
private static void run(FilePath dir, String... cmds) throws InterruptedException {
try {
assertEquals(0, new LocalLauncher(StreamTaskListener.fromStdout()).launch().cmds(cmds).pwd(dir).join());
} catch (IOException x) { // perhaps restrict to x.message.contains("Cannot run program")? or "error=2, No such file or directory"?
Assume.assumeNoException("failed to run " + Arrays.toString(cmds), x);
}
}
@Issue("JENKINS-14922")
@Test public void brokenSymlinks() throws Exception {
assumeTrue(!Functions.isWindows());
@@ -105,5 +116,56 @@ public class TarArchiverTest {
Util.createSymlink(dir, "nonexistent", "link", TaskListener.NULL);
new FilePath(dir).tar(new NullStream(), "**");
}
/**
* Test backing up an open file
*/
@Issue("JENKINS-20187")
@Test public void growingFileTar() throws Exception {
File file=new File(tmp.getRoot(),"growing.file");
GrowingFileRunnable runnable1 = new GrowingFileRunnable(file);
Thread t1 = new Thread(runnable1);
t1.start();
new FilePath(tmp.getRoot()).tar(new NullStream(), "**");
runnable1.doFinish();
t1.join();
}
private class GrowingFileRunnable implements Runnable {
private boolean finish = false;
private Exception ex = null;
private File file;
public GrowingFileRunnable(File file) {
this.file = file;
}
@Override
public void run() {
File openFile = file;
try {
openFile.createNewFile();
FileOutputStream fos = new FileOutputStream(openFile);
for (int i = 0; !finish && i < 5000000; i++) { // limit the max size, just in case.
fos.write(0);
// Thread.sleep(5);
}
fos.close();
} catch (Exception e) {
ex = e;
}
}
public void doFinish() throws Exception {
finish = true;
if (ex != null) {
throw ex;
}
}
};
}
@@ -0,0 +1,57 @@
/*
* The MIT License
*
* Copyright (c) 2014
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package jenkins.model;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import hudson.model.JDK;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
public class JDKNameTest {
@Test
public void nullIsDefaultName() {
assertThat(JDK.isDefaultName(null), is(true));
}
@Test
public void recognizeOldDefaultName() {
// DEFAULT_NAME took this value prior to 1.598.
assertThat(JDK.isDefaultName("(Default)"), is(true));
}
@Test
public void recognizeDefaultName() {
assertThat(JDK.isDefaultName(JDK.DEFAULT_NAME), is(true));
}
@Test
public void othernameNotDefault() {
assertThat(JDK.isDefaultName("I'm a customized name"), is(false));
}
}
@@ -23,17 +23,14 @@
*/
package jenkins.model;
import java.io.IOException;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;
/**
* Tests for {@link JenkinsLocationConfiguration}.
@@ -52,6 +52,7 @@ public class RunIdMigratorTest {
TimeZone.setDefault(TimeZone.getTimeZone("EST"));
}
// TODO could use LoggerRule only if it were extracted to an independent library
@BeforeClass public static void logging() {
RunIdMigrator.LOGGER.setLevel(Level.ALL);
Handler handler = new ConsoleHandler();
@@ -128,6 +129,26 @@ public class RunIdMigratorTest {
assertEquals("{1=→2014-01-02_03-04-05, 2014-01-02_03-04-05={build.xml='<?xml version='1.0' encoding='UTF-8'?>\n<run>\n <stuff>ok</stuff>\n <number>1</number>\n <otherstuff>ok</otherstuff>\n</run>'}}", summarize());
}
@Test public void reverseMatrixAfterNewBuilds() throws Exception {
File root = dir;
dir = new File(dir, "jobs/someproject/Environment=prod/builds");
write("1/build.xml", "<?xml version='1.0' encoding='UTF-8'?>\n<run>\n <stuff>ok</stuff>\n <timestamp>1388649845000</timestamp>\n <otherstuff>ok</otherstuff>\n</run>");
write("legacyIds", "");
assertEquals("{1={build.xml='<?xml version='1.0' encoding='UTF-8'?>\n<run>\n <stuff>ok</stuff>\n <timestamp>1388649845000</timestamp>\n <otherstuff>ok</otherstuff>\n</run>'}, legacyIds=''}", summarize());
RunIdMigrator.main(root.getAbsolutePath());
assertEquals("{1=→2014-01-02_03-04-05, 2014-01-02_03-04-05={build.xml='<?xml version='1.0' encoding='UTF-8'?>\n<run>\n <stuff>ok</stuff>\n <number>1</number>\n <otherstuff>ok</otherstuff>\n</run>'}}", summarize());
}
@Test public void reverseMavenAfterNewBuilds() throws Exception {
File root = dir;
dir = new File(dir, "jobs/someproject/test$test/builds");
write("1/build.xml", "<?xml version='1.0' encoding='UTF-8'?>\n<run>\n <stuff>ok</stuff>\n <timestamp>1388649845000</timestamp>\n <otherstuff>ok</otherstuff>\n</run>");
write("legacyIds", "");
assertEquals("{1={build.xml='<?xml version='1.0' encoding='UTF-8'?>\n<run>\n <stuff>ok</stuff>\n <timestamp>1388649845000</timestamp>\n <otherstuff>ok</otherstuff>\n</run>'}, legacyIds=''}", summarize());
RunIdMigrator.main(root.getAbsolutePath());
assertEquals("{1=→2014-01-02_03-04-05, 2014-01-02_03-04-05={build.xml='<?xml version='1.0' encoding='UTF-8'?>\n<run>\n <stuff>ok</stuff>\n <number>1</number>\n <otherstuff>ok</otherstuff>\n</run>'}}", summarize());
}
// TODO test sane recovery from various error conditions
private void write(String file, String text) throws Exception {
@@ -23,6 +23,7 @@
*/
package jenkins.model.lazy;
import java.io.File;
import static org.junit.Assert.*;
import jenkins.model.lazy.AbstractLazyLoadRunMap.Direction;
@@ -31,13 +32,19 @@ import org.junit.Rule;
import org.junit.Test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import jenkins.util.Timer;
import org.junit.BeforeClass;
import org.jvnet.hudson.test.Issue;
@@ -72,6 +79,29 @@ public class AbstractLazyLoadRunMapTest {
}
};
private final Map<Integer,Semaphore> slowBuilderStartSemaphores = new HashMap<>();
private final Map<Integer,Semaphore> slowBuilderEndSemaphores = new HashMap<>();
private final Map<Integer,AtomicInteger> slowBuilderLoadCount = new HashMap<>();
@Rule
public FakeMapBuilder slowBuilder = new FakeMapBuilder() {
@Override
public FakeMap make() {
return new FakeMap(getDir()) {
@Override
protected Build retrieve(File dir) throws IOException {
Build b = super.retrieve(dir);
slowBuilderStartSemaphores.get(b.n).release();
try {
slowBuilderEndSemaphores.get(b.n).acquire();
} catch (InterruptedException x) {
throw new IOException(x);
}
slowBuilderLoadCount.get(b.n).incrementAndGet();
return b;
}
};
}
};
@BeforeClass
public static void setUpClass() {
@@ -358,4 +388,36 @@ public class AbstractLazyLoadRunMapTest {
assertTrue(a.entrySet().contains(e));
}
}
@Issue("JENKINS-22767")
@Test
public void slowRetrieve() throws Exception {
for (int i = 1; i <= 3; i++) {
slowBuilder.add(i);
slowBuilderStartSemaphores.put(i, new Semaphore(0));
slowBuilderEndSemaphores.put(i, new Semaphore(0));
slowBuilderLoadCount.put(i, new AtomicInteger());
}
final FakeMap m = slowBuilder.make();
Future<Build> firstLoad = Timer.get().submit(new Callable<Build>() {
@Override
public Build call() throws Exception {
return m.getByNumber(2);
}
});
Future<Build> secondLoad = Timer.get().submit(new Callable<Build>() {
@Override
public Build call() throws Exception {
return m.getByNumber(2);
}
});
slowBuilderStartSemaphores.get(2).acquire(1);
// now one of them is inside retrieve(…); the other is waiting for the lock
slowBuilderEndSemaphores.get(2).release(2); // allow both to proceed
Build first = firstLoad.get();
Build second = secondLoad.get();
assertEquals(1, slowBuilderLoadCount.get(2).get());
assertSame(second, first);
}
}
@@ -34,4 +34,15 @@ public class SortedIntListTest {
assertFalse(l.isInRange(3));
}
@Test public void max() {
SortedIntList l = new SortedIntList(5);
assertEquals(0, l.max());
l.add(1);
assertEquals(1, l.max());
l.add(5);
assertEquals(5, l.max());
l.add(10);
assertEquals(10, l.max());
}
}
@@ -1,142 +0,0 @@
package jenkins.slaves;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import hudson.TcpSlaveAgentListener.ConnectionFromCurrentPeer;
import hudson.remoting.Channel;
import hudson.slaves.SlaveComputer;
import jenkins.model.Jenkins;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(Jenkins.class)
public class DefaultJnlpSlaveReceiverTest {
@Mock private Jenkins mockJenkins;
@Mock private SlaveComputer mockComputer;
@Mock private Channel mockChannel;
@Mock private JnlpSlaveAgentProtocol2.Handler mockHandshake;
@Mock private Future mockFuture;
private DefaultJnlpSlaveReceiver receiver;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockStatic(Jenkins.class);
when(Jenkins.getInstance()).thenReturn(mockJenkins);
receiver = new DefaultJnlpSlaveReceiver();
}
@Test
public void testHandle() throws Exception {
when(mockJenkins.getComputer("node")).thenReturn(mockComputer);
when(mockComputer.getChannel()).thenReturn(null);
when(mockChannel.getProperty(any(String.class))).thenReturn("some cookie");
when(mockHandshake.jnlpConnect(mockComputer)).thenReturn(mockChannel);
assertTrue(receiver.handle("node", mockHandshake));
verify(mockHandshake).success(any(Properties.class));
verify(mockChannel).setProperty(any(String.class), any(String.class));
}
@Test
public void testHandleWithInvalidNode() throws Exception {
when(mockJenkins.getComputer("bogus-node")).thenReturn(null);
assertFalse(receiver.handle("bogus-node", mockHandshake));
}
@Test
public void testHandleTakeover() throws Exception {
when(mockJenkins.getComputer("node")).thenReturn(mockComputer);
when(mockComputer.getChannel()).thenReturn(mockChannel);
when(mockHandshake.getRequestProperty(any(String.class))).thenReturn("some cookie");
when(mockChannel.getProperty(any(String.class))).thenReturn("some cookie");
when(mockComputer.disconnect(any(ConnectionFromCurrentPeer.class))).thenReturn(mockFuture);
when(mockHandshake.jnlpConnect(mockComputer)).thenReturn(mockChannel);
assertTrue(receiver.handle("node", mockHandshake));
verify(mockFuture).get(15, TimeUnit.SECONDS);
verify(mockHandshake).success(any(Properties.class));
verify(mockChannel).setProperty(any(String.class), any(String.class));
}
@Test
public void testHandleTakeoverFailedDisconnect() throws Exception {
when(mockJenkins.getComputer("node")).thenReturn(mockComputer);
when(mockComputer.getChannel()).thenReturn(mockChannel);
when(mockHandshake.getRequestProperty(any(String.class))).thenReturn("some cookie");
when(mockChannel.getProperty(any(String.class))).thenReturn("some cookie");
when(mockComputer.disconnect(any(ConnectionFromCurrentPeer.class))).thenReturn(mockFuture);
when(mockFuture.get(15, TimeUnit.SECONDS)).thenThrow(new ExecutionException(null));
try {
receiver.handle("node", mockHandshake);
fail();
} catch (IOException e) {
// good
}
}
@Test
public void testHandleTakeoverTimedOut() throws Exception {
when(mockJenkins.getComputer("node")).thenReturn(mockComputer);
when(mockComputer.getChannel()).thenReturn(mockChannel);
when(mockHandshake.getRequestProperty(any(String.class))).thenReturn("some cookie");
when(mockChannel.getProperty(any(String.class))).thenReturn("some cookie");
when(mockComputer.disconnect(any(ConnectionFromCurrentPeer.class))).thenReturn(mockFuture);
when(mockFuture.get(15, TimeUnit.SECONDS)).thenThrow(new TimeoutException());
try {
receiver.handle("node", mockHandshake);
fail();
} catch (IOException e) {
// good
}
}
@Test
public void testHandleAttemptTakeoverWithNullCookie() throws Exception {
when(mockJenkins.getComputer("node")).thenReturn(mockComputer);
when(mockComputer.getChannel()).thenReturn(mockChannel);
when(mockHandshake.getRequestProperty(any(String.class))).thenReturn(null);
when(mockChannel.getProperty(any(String.class))).thenReturn("some cookie");
assertTrue(receiver.handle("node", mockHandshake));
verify(mockHandshake).error(any(String.class));
}
@Test
public void testHandleAttemptTakeoverWithInvalidCookie() throws Exception {
when(mockJenkins.getComputer("node")).thenReturn(mockComputer);
when(mockComputer.getChannel()).thenReturn(mockChannel);
when(mockHandshake.getRequestProperty(any(String.class))).thenReturn("bogus cookie");
when(mockChannel.getProperty(any(String.class))).thenReturn("some cookie");
assertTrue(receiver.handle("node", mockHandshake));
verify(mockHandshake).error(any(String.class));
}
}
@@ -0,0 +1,40 @@
package jenkins.triggers;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.jvnet.hudson.test.Issue;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import hudson.model.Item;
import hudson.model.SCMedItem;
import hudson.model.TaskListener;
import jenkins.scm.SCMDecisionHandler;
@SuppressWarnings("deprecation")
@RunWith(PowerMockRunner.class)
public class SCMTriggerItemTest {
@Test
@Issue("JENKINS-36232")
@PrepareForTest(SCMDecisionHandler.class)
public void noVetoDelegatesPollingToAnSCMedItem() {
// given
PowerMockito.mockStatic(SCMDecisionHandler.class);
PowerMockito.when(SCMDecisionHandler.firstShouldPollVeto(any(Item.class))).thenReturn(null);
SCMedItem scMedItem = Mockito.mock(SCMedItem.class);
TaskListener listener = Mockito.mock(TaskListener.class);
// when
SCMTriggerItem.SCMTriggerItems.asSCMTriggerItem(scMedItem).poll(listener);
// then
verify(scMedItem).poll(listener);
}
}
@@ -0,0 +1,36 @@
package jenkins.util;
import org.junit.Test;
public class JenkinsJVMTest {
@Test
public void checkNotJenkinsJVM_WhenNotInAJenkinsJVM() {
JenkinsJVM.checkNotJenkinsJVM();
}
@Test(expected = IllegalStateException.class)
public void checkJenkinsJVM_WhenNotInAJenkinsJVM() {
JenkinsJVM.checkJenkinsJVM();
}
@Test(expected = IllegalStateException.class)
public void checkNotJenkinsJVM_WhenInAJenkinsJVM() {
JenkinsJVM.setJenkinsJVM(true);
try {
JenkinsJVM.checkNotJenkinsJVM();
} finally {
JenkinsJVM.setJenkinsJVM(false);
}
}
@Test
public void checkJenkinsJVM_WhenInAJenkinsJVM() {
JenkinsJVM.setJenkinsJVM(true);
try {
JenkinsJVM.checkJenkinsJVM();
} finally {
JenkinsJVM.setJenkinsJVM(false);
}
}
}
@@ -0,0 +1,69 @@
/*
* The MIT License
*
* Copyright (c) 2015, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package jenkins.util;
import net.sf.json.JSONObject;
import org.junit.Assert;
import org.junit.Test;
import java.util.Locale;
import java.util.MissingResourceException;
/**
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*/
public class ResourceBundleUtilTest {
/**
* Test resource bundle loading for a defined locale.
*/
@Test
public void test_known_locale() {
JSONObject bundle = ResourceBundleUtil.getBundle("hudson.logging.Messages", Locale.GERMAN);
Assert.assertEquals("Initialisiere Log-Rekorder", bundle.getString("LogRecorderManager.init"));
bundle = ResourceBundleUtil.getBundle("hudson.logging.Messages", new Locale("pt"));
Assert.assertEquals("Inicializando registros de log", bundle.getString("LogRecorderManager.init"));
// Test caching - should get the same bundle instance back...
Assert.assertTrue(ResourceBundleUtil.getBundle("hudson.logging.Messages", new Locale("pt")) == bundle);
}
/**
* Test that we get the "default" bundle for an unknown locale.
*/
@Test
public void test_unknown_locale() {
JSONObject bundle = ResourceBundleUtil.getBundle("hudson.logging.Messages", new Locale("kok")); // konkani
Assert.assertEquals("Initialing log recorders", bundle.getString("LogRecorderManager.init"));
}
/**
* Test unknown bundle.
*/
@Test(expected = MissingResourceException.class)
public void test_unknown_bundle() {
ResourceBundleUtil.getBundle("hudson.blah.Whatever");
}
}
@@ -83,12 +83,9 @@ public class XStreamDOMTest {
@Test
public void testUnmarshal() throws Exception {
InputStream is = XStreamDOMTest.class.getResourceAsStream("XStreamDOMTest.data1.xml");
Foo foo;
try {
try (InputStream is = XStreamDOMTest.class.getResourceAsStream("XStreamDOMTest.data1.xml")) {
foo = (Foo) xs.fromXML(is);
} finally {
is.close();
}
assertEquals("test1",foo.bar.getTagName());
assertEquals("value",foo.bar.getAttribute("key"));
@@ -0,0 +1,376 @@
/*
* The MIT License
*
* Copyright (c) 2013-2014, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package jenkins.widgets;
import hudson.model.Job;
import hudson.model.MockItem;
import hudson.model.ModelObject;
import hudson.model.Queue;
import hudson.model.Result;
import hudson.model.Run;
import jenkins.widgets.HistoryPageEntry;
import jenkins.widgets.HistoryPageFilter;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*/
public class HistoryPageFilterTest {
/**
* No items.
*/
@Test
public void test_latest_empty_page() {
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, null, null);
List<ModelObject> itemList = new ArrayList<>();
historyPageFilter.add(itemList);
Assert.assertEquals(false, historyPageFilter.hasUpPage);
Assert.assertEquals(false, historyPageFilter.hasDownPage);
Assert.assertEquals(true, historyPageFilter.queueItems.isEmpty());
Assert.assertEquals(true, historyPageFilter.runs.isEmpty());
}
/**
* Latest/top page where total number of items less than the max page size.
*/
@Test
public void test_latest_partial_page() throws IOException {
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, null, null);
List<ModelObject> runs = newRuns(1, 2);
List<Queue.Item> queueItems = newQueueItems(3, 4);
historyPageFilter.add(runs, queueItems);
Assert.assertEquals(false, historyPageFilter.hasUpPage);
Assert.assertEquals(false, historyPageFilter.hasDownPage);
Assert.assertEquals(2, historyPageFilter.queueItems.size());
Assert.assertEquals(2, historyPageFilter.runs.size());
Assert.assertEquals(4, historyPageFilter.queueItems.get(0).getEntryId());
Assert.assertEquals(4, historyPageFilter.newestOnPage);
Assert.assertEquals(3, historyPageFilter.queueItems.get(1).getEntryId());
Assert.assertEquals(HistoryPageEntry.getEntryId(2), historyPageFilter.runs.get(0).getEntryId());
Assert.assertEquals(HistoryPageEntry.getEntryId(1), historyPageFilter.runs.get(1).getEntryId());
Assert.assertEquals(HistoryPageEntry.getEntryId(1), historyPageFilter.oldestOnPage);
}
/**
* Latest/top page where total number of items greater than the max page size.
*/
@Test
public void test_latest_longer_list() throws IOException {
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, null, null);
List<ModelObject> runs = newRuns(1, 10);
List<Queue.Item> queueItems = newQueueItems(11, 12);
historyPageFilter.add(runs, queueItems);
Assert.assertEquals(false, historyPageFilter.hasUpPage);
Assert.assertEquals(true, historyPageFilter.hasDownPage);
Assert.assertEquals(2, historyPageFilter.queueItems.size());
Assert.assertEquals(3, historyPageFilter.runs.size());
Assert.assertEquals(12, historyPageFilter.queueItems.get(0).getEntryId());
Assert.assertEquals(12, historyPageFilter.newestOnPage);
Assert.assertEquals(HistoryPageEntry.getEntryId(10), historyPageFilter.runs.get(0).getEntryId());
}
/**
* Test olderThan (page down) when set to id greater than newest (should never happen). Should be same as not
* specifying newerThan/olderThan.
*/
@Test
public void test_olderThan_gt_newest() throws IOException {
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, null, 11L);
List<ModelObject> itemList = newRuns(1, 10);
historyPageFilter.add(itemList);
Assert.assertEquals(false, historyPageFilter.hasUpPage);
Assert.assertEquals(true, historyPageFilter.hasDownPage);
Assert.assertEquals(5, historyPageFilter.runs.size());
Assert.assertEquals(HistoryPageEntry.getEntryId(10), historyPageFilter.newestOnPage);
Assert.assertEquals(HistoryPageEntry.getEntryId(6), historyPageFilter.oldestOnPage);
}
/**
* Test olderThan (page down) when set to id less than the oldest (should never happen). Should just give an
* empty list of builds.
*/
@Test
public void test_olderThan_lt_oldest() throws IOException {
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, null, 0L);
List<ModelObject> itemList = newRuns(1, 10);
historyPageFilter.add(itemList);
Assert.assertEquals(true, historyPageFilter.hasUpPage);
Assert.assertEquals(false, historyPageFilter.hasDownPage);
Assert.assertEquals(0, historyPageFilter.runs.size());
}
/**
* Test olderThan (page down) when set to an id close to the oldest in the list (where
* there's less than a full page older than the supplied olderThan arg).
*/
@Test
public void test_olderThan_leaving_part_page() throws IOException {
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, null, 4L);
List<ModelObject> itemList = newRuns(1, 10);
historyPageFilter.add(itemList);
Assert.assertEquals(true, historyPageFilter.hasUpPage);
Assert.assertEquals(false, historyPageFilter.hasDownPage);
// Should only be 3 runs on the page (oldest 3)
Assert.assertEquals(3, historyPageFilter.runs.size());
Assert.assertEquals(HistoryPageEntry.getEntryId(3), historyPageFilter.newestOnPage);
Assert.assertEquals(HistoryPageEntry.getEntryId(1), historyPageFilter.oldestOnPage);
}
/**
* Test olderThan (page down) when set to an id in the middle. Should be a page up and a page down.
*/
@Test
public void test_olderThan_mid_page() throws IOException {
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, null, 8L);
List<ModelObject> itemList = newRuns(1, 10);
historyPageFilter.add(itemList);
Assert.assertEquals(true, historyPageFilter.hasUpPage);
Assert.assertEquals(true, historyPageFilter.hasDownPage);
Assert.assertEquals(5, historyPageFilter.runs.size());
Assert.assertEquals(HistoryPageEntry.getEntryId(7), historyPageFilter.newestOnPage);
Assert.assertEquals(HistoryPageEntry.getEntryId(3), historyPageFilter.oldestOnPage);
}
/**
* Test newerThan (page up) when set to id greater than newest (should never happen). Should be an empty list.
*/
@Test
public void test_newerThan_gt_newest() throws IOException {
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, 11L, null);
List<ModelObject> itemList = newRuns(1, 10);
historyPageFilter.add(itemList);
Assert.assertEquals(false, historyPageFilter.hasUpPage);
Assert.assertEquals(true, historyPageFilter.hasDownPage);
Assert.assertEquals(0, historyPageFilter.runs.size());
}
/**
* Test newerThan (page up) when set to id less than the oldest (should never happen). Should give the oldest
* set of builds.
*/
@Test
public void test_newerThan_lt_oldest() throws IOException {
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, 0L, null);
List<ModelObject> itemList = newRuns(1, 10);
historyPageFilter.add(itemList);
Assert.assertEquals(true, historyPageFilter.hasUpPage);
Assert.assertEquals(false, historyPageFilter.hasDownPage);
Assert.assertEquals(5, historyPageFilter.runs.size());
Assert.assertEquals(HistoryPageEntry.getEntryId(5), historyPageFilter.newestOnPage);
Assert.assertEquals(HistoryPageEntry.getEntryId(1), historyPageFilter.oldestOnPage);
}
/**
* Test newerThan (page up) mid range nearer the oldest build in the list.
*/
@Test
public void test_newerThan_near_oldest() throws IOException {
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, 3L, null);
List<ModelObject> itemList = newRuns(1, 10);
historyPageFilter.add(itemList);
Assert.assertEquals(true, historyPageFilter.hasUpPage);
Assert.assertEquals(true, historyPageFilter.hasDownPage);
Assert.assertEquals(5, historyPageFilter.runs.size());
Assert.assertEquals(HistoryPageEntry.getEntryId(8), historyPageFilter.newestOnPage);
Assert.assertEquals(HistoryPageEntry.getEntryId(4), historyPageFilter.oldestOnPage);
}
/**
* Test newerThan (page up) mid range nearer the newest build in the list. This works a little different
* in that it will put the 2 builds newer than newerThan on the page and then fill the remaining slots on the
* page with builds equal to and older i.e. it return the newest/latest builds.
*/
@Test
public void test_newerThan_near_newest() throws IOException {
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, 8L, null);
List<ModelObject> itemList = newRuns(1, 10);
historyPageFilter.add(itemList);
Assert.assertEquals(false, historyPageFilter.hasUpPage);
Assert.assertEquals(true, historyPageFilter.hasDownPage);
Assert.assertEquals(5, historyPageFilter.runs.size());
Assert.assertEquals(HistoryPageEntry.getEntryId(10), historyPageFilter.newestOnPage);
Assert.assertEquals(HistoryPageEntry.getEntryId(6), historyPageFilter.oldestOnPage);
}
/**
* Test newerThan (page up) mid range when there are queued builds that are new enough to
* not show up.
*/
@Test
public void test_newerThan_doesntIncludeQueuedItems() throws IOException {
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, 5L, null);
List<ModelObject> runs = newRuns(1, 10);
List<Queue.Item> queueItems = newQueueItems(11, 12);
historyPageFilter.add(runs, queueItems);
Assert.assertEquals(true, historyPageFilter.hasUpPage);
Assert.assertEquals(true, historyPageFilter.hasDownPage);
Assert.assertEquals(0, historyPageFilter.queueItems.size());
Assert.assertEquals(5, historyPageFilter.runs.size());
Assert.assertEquals(HistoryPageEntry.getEntryId(10), historyPageFilter.runs.get(0).getEntryId());
Assert.assertEquals(HistoryPageEntry.getEntryId(10), historyPageFilter.newestOnPage);
Assert.assertEquals(HistoryPageEntry.getEntryId(6), historyPageFilter.oldestOnPage);
}
/**
* Test that later items in the list that are not needed for display are not evaluated at all (for performance).
*/
@Test
public void test_laterItemsNotEvaluated() throws IOException {
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, null, null);
List<ModelObject> itemList = newRuns(6, 10);
for (int queueId = 5; queueId >= 1; queueId--) {
itemList.add(new ExplodingMockRun(queueId));
}
historyPageFilter.add(itemList);
Assert.assertEquals(false, historyPageFilter.hasUpPage);
Assert.assertEquals(true, historyPageFilter.hasDownPage);
Assert.assertEquals(5, historyPageFilter.runs.size());
Assert.assertEquals(HistoryPageEntry.getEntryId(10), historyPageFilter.newestOnPage);
Assert.assertEquals(HistoryPageEntry.getEntryId(6), historyPageFilter.oldestOnPage);
}
private List<Queue.Item> newQueueItems(long startId, long endId) {
List<Queue.Item> items = new ArrayList<>();
for (long queueId = startId; queueId <= endId; queueId++) {
items.add(new MockItem(queueId));
}
return items;
}
private List<ModelObject> newRuns(long startId, long endId) throws IOException {
// Runs should be in reverse order, newest first.
List<ModelObject> runs = new ArrayList<>();
for (long queueId = endId; queueId >= startId; queueId--) {
runs.add(new MockRun(queueId));
}
return runs;
}
private HistoryPageFilter<ModelObject> newPage(int maxEntries, Long newerThan, Long olderThan) {
HistoryPageFilter<ModelObject> pageFilter = new HistoryPageFilter<>(maxEntries);
if (newerThan != null) {
pageFilter.setNewerThan(HistoryPageEntry.getEntryId(newerThan));
} else if (olderThan != null) {
pageFilter.setOlderThan(HistoryPageEntry.getEntryId(olderThan));
}
return pageFilter;
}
@SuppressWarnings("unchecked")
private static class MockRun extends Run {
private final long queueId;
public MockRun(long queueId) throws IOException {
super(Mockito.mock(Job.class));
this.queueId = queueId;
}
@Override
public int compareTo(Run o) {
return 0;
}
@Override
public Result getResult() {
return result;
}
@Override
public boolean isBuilding() {
return false;
}
@Override
public long getQueueId() {
return queueId;
}
@Override
public int getNumber() {
return (int) queueId;
}
}
// A version of MockRun that will throw an exception if getQueueId or getNumber is called
private static class ExplodingMockRun extends MockRun {
public ExplodingMockRun(long queueId) throws IOException {
super(queueId);
}
@Override
public long getQueueId() {
Assert.fail("Should not get called");
return super.getQueueId();
}
@Override
public int getNumber() {
Assert.fail("Should not get called");
return super.getNumber();
}
}
}
@@ -26,17 +26,23 @@ package jenkins.xml;
import jenkins.util.xml.XMLUtils;
import org.junit.Assert;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URL;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.xpath.XPathExpressionException;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertThat;
import org.jvnet.hudson.test.Issue;
import org.xml.sax.SAXException;
public class XMLUtilsTest {
@@ -97,4 +103,33 @@ public class XMLUtilsTest {
assertThat(stringWriter.toString(), containsString("<description>&amp;</description>"));
}
/**
* Tests getValue() directly. Tests the parse methods too (indirectly - yeah, a purest would have
* tests for each).
*/
@Test
public void testGetValue() throws XPathExpressionException, SAXException, IOException {
URL configUrl = getClass().getResource("/jenkins/xml/config.xml");
File configFile = new File(configUrl.getFile());
Assert.assertEquals("1.480.1", XMLUtils.getValue("/hudson/version", configFile));
Assert.assertEquals("", XMLUtils.getValue("/hudson/unknown-element", configFile));
}
@Test
public void testParse_with_XXE() throws IOException, XPathExpressionException {
try {
final String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<!DOCTYPE foo [\n" +
" <!ELEMENT foo ANY >\n" +
" <!ENTITY xxe SYSTEM \"http://abc.com/temp/test.jsp\" >]> " +
"<foo>&xxe;</foo>";
StringReader stringReader = new StringReader(xml);
XMLUtils.parse(stringReader);
Assert.fail("Expecting SAXException for XXE.");
} catch (SAXException e) {
assertThat(e.getMessage(), containsString("\"http://apache.org/xml/features/disallow-doctype-decl\""));
}
}
}