/* * The MIT License * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi * * 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.search; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import hudson.model.FreeStyleProject; import hudson.model.ListView; import java.net.URL; import java.util.ArrayList; import java.util.List; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import net.sf.json.JSONSerializer; 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 com.gargoylesoftware.htmlunit.AlertHandler; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.Page; /** * @author Kohsuke Kawaguchi */ public class SearchTest { @Rule public JenkinsRule j = new JenkinsRule(); /** * No exact match should result in a failure status code. */ @Test public void testFailure() throws Exception { try { j.search("no-such-thing"); fail("404 expected"); } catch (FailingHttpStatusCodeException e) { assertEquals(404,e.getResponse().getStatusCode()); } } /** * Makes sure the script doesn't execute. */ @Issue("JENKINS-3415") @Test public void testXSS() throws Exception { try { WebClient wc = j.createWebClient(); wc.setAlertHandler(new AlertHandler() { public void handleAlert(Page page, String message) { throw new AssertionError(); } }); wc.search("<script>alert('script');</script>"); fail("404 expected"); } catch (FailingHttpStatusCodeException e) { assertEquals(404,e.getResponse().getStatusCode()); } } @Test public void testSearchByProjectName() throws Exception { final String projectName = "testSearchByProjectName"; j.createFreeStyleProject(projectName); Page result = j.search(projectName); assertNotNull(result); j.assertGoodStatus(result); // make sure we've fetched the testSearchByDisplayName project page String contents = result.getWebResponse().getContentAsString(); assertTrue(contents.contains(String.format("<title>%s [Jenkins]</title>", projectName))); } @Issue("JENKINS-24433") @Test public void testSearchByProjectNameBehindAFolder() throws Exception { FreeStyleProject myFreeStyleProject = j.createFreeStyleProject("testSearchByProjectName"); MockFolder myMockFolder = j.createFolder("my-folder-1"); Page result = j.createWebClient().goTo(myMockFolder.getUrl() + "search?q="+ myFreeStyleProject.getName()); assertNotNull(result); j.assertGoodStatus(result); URL resultUrl = result.getUrl(); assertTrue(resultUrl.toString().equals(j.getInstance().getRootUrl() + myFreeStyleProject.getUrl())); } @Issue("JENKINS-24433") @Test public void testSearchByProjectNameInAFolder() throws Exception { MockFolder myMockFolder = j.createFolder("my-folder-1"); FreeStyleProject myFreeStyleProject = myMockFolder.createProject(FreeStyleProject.class, "my-job-1"); Page result = j.createWebClient().goTo(myMockFolder.getUrl() + "search?q=" + myFreeStyleProject.getFullName()); assertNotNull(result); j.assertGoodStatus(result); URL resultUrl = result.getUrl(); assertTrue(resultUrl.toString().equals(j.getInstance().getRootUrl() + myFreeStyleProject.getUrl())); } @Test public void testSearchByDisplayName() throws Exception { final String displayName = "displayName9999999"; FreeStyleProject project = j.createFreeStyleProject("testSearchByDisplayName"); project.setDisplayName(displayName); Page result = j.search(displayName); assertNotNull(result); j.assertGoodStatus(result); // make sure we've fetched the testSearchByDisplayName project page String contents = result.getWebResponse().getContentAsString(); assertTrue(contents.contains(String.format("<title>%s [Jenkins]</title>", displayName))); } @Test public void testSearch2ProjectsWithSameDisplayName() throws Exception { // create 2 freestyle projects with the same display name final String projectName1 = "projectName1"; final String projectName2 = "projectName2"; final String projectName3 = "projectName3"; final String displayName = "displayNameFoo"; final String otherDisplayName = "otherDisplayName"; FreeStyleProject project1 = j.createFreeStyleProject(projectName1); project1.setDisplayName(displayName); FreeStyleProject project2 = j.createFreeStyleProject(projectName2); project2.setDisplayName(displayName); FreeStyleProject project3 = j.createFreeStyleProject(projectName3); project3.setDisplayName(otherDisplayName); // make sure that on search we get back one of the projects, it doesn't // matter which one as long as the one that is returned has displayName // as the display name Page result = j.search(displayName); assertNotNull(result); j.assertGoodStatus(result); // make sure we've fetched the testSearchByDisplayName project page String contents = result.getWebResponse().getContentAsString(); assertTrue(contents.contains(String.format("<title>%s [Jenkins]</title>", displayName))); assertFalse(contents.contains(otherDisplayName)); } @Test public void testProjectNamePrecedesDisplayName() throws Exception { final String project1Name = "foo"; final String project1DisplayName = "project1DisplayName"; final String project2Name = "project2Name"; final String project2DisplayName = project1Name; final String project3Name = "project3Name"; final String project3DisplayName = "project3DisplayName"; // create 1 freestyle project with the name foo FreeStyleProject project1 = j.createFreeStyleProject(project1Name); project1.setDisplayName(project1DisplayName); // create another with the display name foo FreeStyleProject project2 = j.createFreeStyleProject(project2Name); project2.setDisplayName(project2DisplayName); // create a third project and make sure it's not picked up by search FreeStyleProject project3 = j.createFreeStyleProject(project3Name); project3.setDisplayName(project3DisplayName); // search for foo Page result = j.search(project1Name); assertNotNull(result); j.assertGoodStatus(result); // make sure we get the project with the name foo String contents = result.getWebResponse().getContentAsString(); assertTrue(contents.contains(String.format("<title>%s [Jenkins]</title>", project1DisplayName))); // make sure projects 2 and 3 were not picked up assertFalse(contents.contains(project2Name)); assertFalse(contents.contains(project3Name)); assertFalse(contents.contains(project3DisplayName)); } @Test public void testGetSuggestionsHasBothNamesAndDisplayNames() throws Exception { final String projectName = "project name"; final String displayName = "display name"; FreeStyleProject project1 = j.createFreeStyleProject(projectName); project1.setDisplayName(displayName); WebClient wc = j.createWebClient(); Page result = wc.goTo("search/suggest?query=name", "application/json"); assertNotNull(result); j.assertGoodStatus(result); String content = result.getWebResponse().getContentAsString(); System.out.println(content); JSONObject jsonContent = (JSONObject)JSONSerializer.toJSON(content); assertNotNull(jsonContent); JSONArray jsonArray = jsonContent.getJSONArray("suggestions"); assertNotNull(jsonArray); assertEquals(2, jsonArray.size()); boolean foundProjectName = false; boolean foundDispayName = false; for(Object suggestion : jsonArray) { JSONObject jsonSuggestion = (JSONObject)suggestion; String name = (String)jsonSuggestion.get("name"); if(projectName.equals(name)) { foundProjectName = true; } else if(displayName.equals(name)) { foundDispayName = true; } } assertTrue(foundProjectName); assertTrue(foundDispayName); } @Issue("JENKINS-24433") @Test public void testProjectNameBehindAFolderDisplayName() throws Exception { final String projectName1 = "job-1"; final String displayName1 = "job-1 display"; final String projectName2 = "job-2"; final String displayName2 = "job-2 display"; FreeStyleProject project1 = j.createFreeStyleProject(projectName1); project1.setDisplayName(displayName1); MockFolder myMockFolder = j.createFolder("my-folder-1"); FreeStyleProject project2 = myMockFolder.createProject(FreeStyleProject.class, projectName2); project2.setDisplayName(displayName2); WebClient wc = j.createWebClient(); Page result = wc.goTo(myMockFolder.getUrl() + "search/suggest?query=" + projectName1, "application/json"); assertNotNull(result); j.assertGoodStatus(result); String content = result.getWebResponse().getContentAsString(); JSONObject jsonContent = (JSONObject)JSONSerializer.toJSON(content); assertNotNull(jsonContent); JSONArray jsonArray = jsonContent.getJSONArray("suggestions"); assertNotNull(jsonArray); assertEquals(2, jsonArray.size()); boolean foundDisplayName = false; for(Object suggestion : jsonArray) { JSONObject jsonSuggestion = (JSONObject)suggestion; String name = (String)jsonSuggestion.get("name"); if(projectName1.equals(name)) { foundDisplayName = true; } } assertTrue(foundDisplayName); } @Issue("JENKINS-24433") @Test public void testProjectNameInAFolderDisplayName() throws Exception { final String projectName1 = "job-1"; final String displayName1 = "job-1 display"; final String projectName2 = "job-2"; final String displayName2 = "my-folder-1 job-2"; FreeStyleProject project1 = j.createFreeStyleProject(projectName1); project1.setDisplayName(displayName1); MockFolder myMockFolder = j.createFolder("my-folder-1"); FreeStyleProject project2 = myMockFolder.createProject(FreeStyleProject.class, projectName2); project2.setDisplayName(displayName2); WebClient wc = j.createWebClient(); Page result = wc.goTo(myMockFolder.getUrl() + "search/suggest?query=" + projectName2, "application/json"); assertNotNull(result); j.assertGoodStatus(result); String content = result.getWebResponse().getContentAsString(); JSONObject jsonContent = (JSONObject)JSONSerializer.toJSON(content); assertNotNull(jsonContent); JSONArray jsonArray = jsonContent.getJSONArray("suggestions"); assertNotNull(jsonArray); assertEquals(1, jsonArray.size()); boolean foundDisplayName = false; for(Object suggestion : jsonArray) { JSONObject jsonSuggestion = (JSONObject)suggestion; String name = (String)jsonSuggestion.get("name"); if(displayName2.equals(name)) { foundDisplayName = true; } } assertTrue(foundDisplayName); } /** * Disable/enable status shouldn't affect the search */ @Issue("JENKINS-13148") @Test public void testDisabledJobShouldBeSearchable() throws Exception { FreeStyleProject p = j.createFreeStyleProject("foo-bar"); assertTrue(suggest(j.jenkins.getSearchIndex(), "foo").contains(p)); p.disable(); assertTrue(suggest(j.jenkins.getSearchIndex(), "foo").contains(p)); } /** * All top-level jobs should be searchable, not just jobs in the current view. */ @Issue("JENKINS-13148") @Test public void testCompletionOutsideView() throws Exception { FreeStyleProject p = j.createFreeStyleProject("foo-bar"); ListView v = new ListView("empty1",j.jenkins); ListView w = new ListView("empty2",j.jenkins); j.jenkins.addView(v); j.jenkins.addView(w); j.jenkins.setPrimaryView(w); // new view should be empty assertFalse(v.contains(p)); assertFalse(w.contains(p)); assertFalse(j.jenkins.getPrimaryView().contains(p)); assertTrue(suggest(j.jenkins.getSearchIndex(),"foo").contains(p)); } @Test public void testSearchWithinFolders() throws Exception { MockFolder folder1 = j.createFolder("folder1"); FreeStyleProject p1 = folder1.createProject(FreeStyleProject.class, "myjob"); MockFolder folder2 = j.createFolder("folder2"); FreeStyleProject p2 = folder2.createProject(FreeStyleProject.class, "myjob"); List<SearchItem> suggest = suggest(j.jenkins.getSearchIndex(), "myjob"); assertTrue(suggest.contains(p1)); assertTrue(suggest.contains(p2)); } private List<SearchItem> suggest(SearchIndex index, String term) { List<SearchItem> result = new ArrayList<SearchItem>(); index.suggest(term, result); return result; } }