mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-11-15 13:02:19 +00:00
Merge branch 'master' into printStackTrace-JDK-6507809
This commit is contained in:
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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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>&</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\""));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user