/*
* The MIT License
*
* Copyright 2013 Jesse Glick.
*
* 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 com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import hudson.Functions;
import hudson.matrix.AxisList;
import hudson.matrix.MatrixProject;
import hudson.matrix.TextAxis;
import hudson.security.ACL;
import hudson.security.ACLContext;
import hudson.security.AuthorizationStrategy;
import hudson.security.Permission;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import org.acegisecurity.Authentication;
import static org.junit.Assert.*;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsRule.WebClient;
import org.jvnet.hudson.test.MockFolder;
import org.jvnet.hudson.test.recipes.LocalData;
import org.xml.sax.SAXException;
public class ListViewTest {
@Rule public JenkinsRule j = new JenkinsRule();
@Issue("JENKINS-15309")
@LocalData
@Test public void nullJobNames() throws Exception {
assertTrue(j.jenkins.getView("v").getItems().isEmpty());
}
@Test
public void testJobLinksAreValid() throws Exception {
/*
* jenkins
* + -- folder1
* |-- job1
* +-- folder2
* +-- job2
*/
MockFolder folder1 = j.jenkins.createProject(MockFolder.class, "folder1");
FreeStyleProject job1 = folder1.createProject(FreeStyleProject.class, "job1");
MockFolder folder2 = folder1.createProject(MockFolder.class, "folder2");
FreeStyleProject job2 = folder2.createProject(FreeStyleProject.class, "job2");
ListView lv = new ListView("myview");
lv.setRecurse(true);
lv.setIncludeRegex(".*");
j.jenkins.addView(lv);
WebClient webClient = j.createWebClient();
checkLinkFromViewExistsAndIsValid(folder1, j.jenkins, lv, webClient);
checkLinkFromViewExistsAndIsValid(job1, j.jenkins, lv, webClient);
checkLinkFromViewExistsAndIsValid(folder2, j.jenkins, lv, webClient);
checkLinkFromViewExistsAndIsValid(job2, j.jenkins, lv, webClient);
ListView lv2 = new ListView("myview", folder1);
lv2.setRecurse(true);
lv2.setIncludeRegex(".*");
folder1.addView(lv2);
checkLinkFromItemExistsAndIsValid(job1, folder1, folder1, webClient);
checkLinkFromItemExistsAndIsValid(folder2, folder1, folder1, webClient);
checkLinkFromViewExistsAndIsValid(job2, folder1, lv2, webClient);
}
private void checkLinkFromViewExistsAndIsValid(Item item, ItemGroup ig, View view, WebClient webClient) throws IOException, SAXException {
HtmlPage page = webClient.goTo(view.getUrl());
HtmlAnchor link = page.getAnchorByText(Functions.getRelativeDisplayNameFrom(item, ig));
webClient.getPage(view, link.getHrefAttribute());
}
private void checkLinkFromItemExistsAndIsValid(Item item, ItemGroup ig, Item top, WebClient webClient) throws IOException, SAXException {
HtmlPage page = webClient.goTo(top.getUrl());
HtmlAnchor link = page.getAnchorByText(Functions.getRelativeDisplayNameFrom(item, ig));
webClient.getPage(top, link.getHrefAttribute());
}
@Issue("JENKINS-20415")
@Test public void nonTopLevelItemGroup() throws Exception {
MatrixProject mp = j.jenkins.createProject(MatrixProject.class, "mp");
mp.setAxes(new AxisList(new TextAxis("axis", "one", "two")));
assertEquals(2, mp.getItems().size());
ListView v = new ListView("v");
j.jenkins.addView(v);
v.setIncludeRegex(".*");
v.setRecurse(true);
// Note: did not manage to reproduce CCE until I changed expand to use ‘for (TopLevelItem item : items)’ rather than ‘for (Item item : items)’; perhaps a compiler-specific issue?
assertEquals(Collections.singletonList(mp), v.getItems());
}
@Issue("JENKINS-18680")
@Test public void renamesMovesAndDeletes() throws Exception {
MockFolder top = j.createFolder("top");
MockFolder sub = top.createProject(MockFolder.class, "sub");
FreeStyleProject p1 = top.createProject(FreeStyleProject.class, "p1");
FreeStyleProject p2 = sub.createProject(FreeStyleProject.class, "p2");
FreeStyleProject p3 = top.createProject(FreeStyleProject.class, "p3");
ListView v = new ListView("v");
v.setRecurse(true);
top.addView(v);
v.add(p1);
v.add(p2);
v.add(p3);
assertEquals(new HashSet<TopLevelItem>(Arrays.asList(p1, p2, p3)), new HashSet<TopLevelItem>(v.getItems()));
sub.renameTo("lower");
MockFolder stuff = top.createProject(MockFolder.class, "stuff");
Items.move(p1, stuff);
p3.delete();
top.createProject(FreeStyleProject.class, "p3");
assertEquals(new HashSet<TopLevelItem>(Arrays.asList(p1, p2)), new HashSet<TopLevelItem>(v.getItems()));
top.renameTo("upper");
assertEquals(new HashSet<TopLevelItem>(Arrays.asList(p1, p2)), new HashSet<TopLevelItem>(v.getItems()));
}
@Issue("JENKINS-23893")
@Test public void renameJobContainedInTopLevelView() throws Exception {
ListView view = new ListView("view", j.jenkins);
j.jenkins.addView(view);
FreeStyleProject job = j.createFreeStyleProject("old_name");
view.add(job);
assertTrue(view.contains(job));
assertTrue(view.jobNamesContains(job));
job.renameTo("new_name");
assertFalse("old job name is still contained: " + view.jobNames, view.jobNames.contains("old_name"));
assertTrue(view.contains(job));
assertTrue(view.jobNamesContains(job));
}
@Test public void renameContainedJob() throws Exception {
MockFolder folder = j.createFolder("folder");
ListView view = new ListView("view", folder);
folder.addView(view);
FreeStyleProject job = folder.createProject(FreeStyleProject.class, "old_name");
view.add(job);
assertTrue(view.contains(job));
assertTrue(view.jobNamesContains(job));
job.renameTo("new_name");
assertFalse("old job name is still contained", view.jobNames.contains("old_name"));
assertTrue(view.contains(job));
assertTrue(view.jobNamesContains(job));
}
@Issue("JENKINS-23893")
@Test public void deleteJobContainedInTopLevelView() throws Exception {
ListView view = new ListView("view", j.jenkins);
j.jenkins.addView(view);
FreeStyleProject job = j.createFreeStyleProject("project");
view.add(job);
assertTrue(view.contains(job));
assertTrue(view.jobNamesContains(job));
job.delete();
assertFalse(view.contains(job));
assertFalse(view.jobNamesContains(job));
}
@Test public void deleteContainedJob() throws Exception {
MockFolder folder = j.createFolder("folder");
ListView view = new ListView("view", folder);
folder.addView(view);
FreeStyleProject job = folder.createProject(FreeStyleProject.class, "project");
view.add(job);
assertTrue(view.contains(job));
assertTrue(view.jobNamesContains(job));
job.delete();
assertFalse(view.contains(job));
assertFalse(view.jobNamesContains(job));
}
@Issue("JENKINS-22769")
@Test public void renameJobInViewYouCannotSee() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new AllButViewsAuthorizationStrategy());
final FreeStyleProject p = j.createFreeStyleProject("p1");
ListView v = new ListView("v", j.jenkins);
v.add(p);
j.jenkins.addView(v);
try (ACLContext _ = ACL.as(User.get("alice"))) {
p.renameTo("p2");
}
assertEquals(Collections.singletonList(p), v.getItems());
}
private static class AllButViewsAuthorizationStrategy extends AuthorizationStrategy {
@Override public ACL getRootACL() {
return UNSECURED.getRootACL();
}
@Override public Collection<String> getGroups() {
return Collections.emptyList();
}
@Override public ACL getACL(View item) {
return new ACL() {
@Override public boolean hasPermission(Authentication a, Permission permission) {
return a.equals(SYSTEM);
}
};
}
}
}