提交 62adfa88 编写于 作者: D Daniel Beck 提交者: GitHub

Merge pull request #2683 from szpak/feature/JENKINS-40718-searchByBuildParams

[JENKINS-40718] Search by build params in build history widget
......@@ -25,9 +25,13 @@ package jenkins.widgets;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import hudson.model.AbstractBuild;
import hudson.model.Job;
import hudson.model.ParameterValue;
import hudson.model.ParametersAction;
import hudson.model.Queue;
import hudson.model.Run;
import hudson.search.UserSearchProperty;
import hudson.widgets.HistoryWidget;
import javax.annotation.Nonnull;
......@@ -37,6 +41,7 @@ import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* History page filter.
......@@ -52,8 +57,8 @@ public class HistoryPageFilter<T> {
// Need to use different Lists for Queue.Items and Runs because
// we need access to them separately in the jelly files for rendering.
public final List<HistoryPageEntry<Queue.Item>> queueItems = new ArrayList<HistoryPageEntry<Queue.Item>>();
public final List<HistoryPageEntry<Run>> runs = new ArrayList<HistoryPageEntry<Run>>();
public final List<HistoryPageEntry<Queue.Item>> queueItems = new ArrayList<>();
public final List<HistoryPageEntry<Run>> runs = new ArrayList<>();
public boolean hasUpPage = false; // there are newer builds than on this page
public boolean hasDownPage = false; // there are older builds than on this page
......@@ -343,6 +348,13 @@ public class HistoryPageFilter<T> {
return true;
} else if (fitsSearchString(run.getResult())) {
return true;
} else if (run instanceof AbstractBuild && fitsSearchBuildVariables((AbstractBuild) run)) {
return true;
} else {
ParametersAction parametersAction = run.getAction(ParametersAction.class);
if (parametersAction != null && fitsSearchBuildParameters(parametersAction)) {
return true;
}
}
// Non of the fuzzy matches "liked" the search term.
......@@ -354,14 +366,38 @@ public class HistoryPageFilter<T> {
return true;
}
if (data != null) {
if (data instanceof Number) {
return data.toString().equals(searchString);
if (data == null) {
return false;
}
if (data instanceof Number) {
return data.toString().equals(searchString);
} else {
if (UserSearchProperty.isCaseInsensitive()) {
return data.toString().toLowerCase().contains(searchString.toLowerCase());
} else {
return data.toString().toLowerCase().contains(searchString);
return data.toString().contains(searchString);
}
}
}
private boolean fitsSearchBuildVariables(AbstractBuild<?, ?> runAsBuild) {
Map<String, String> buildVariables = runAsBuild.getBuildVariables();
for (String paramsValues : buildVariables.values()) {
if (fitsSearchString(paramsValues)) {
return true;
}
}
return false;
}
}
private boolean fitsSearchBuildParameters(ParametersAction parametersAction) {
List<ParameterValue> parameters = parametersAction.getParameters();
for (ParameterValue parameter : parameters) {
if (!parameter.isSensitive() && fitsSearchString(parameter.getValue())) {
return true;
}
}
return false;
}
}
......@@ -23,24 +23,39 @@
*/
package jenkins.widgets;
import hudson.model.Build;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Job;
import hudson.model.MockItem;
import hudson.model.ModelObject;
import hudson.model.ParameterValue;
import hudson.model.ParametersAction;
import hudson.model.Queue;
import hudson.model.Result;
import hudson.model.Run;
import jenkins.widgets.HistoryPageEntry;
import jenkins.widgets.HistoryPageFilter;
import hudson.model.StringParameterValue;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mockito;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
/**
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*
* See also HistoryPageFilterInsensitiveSearchTest integration test.
*/
public class HistoryPageFilterTest {
......@@ -293,6 +308,80 @@ public class HistoryPageFilterTest {
Assert.assertEquals(HistoryPageEntry.getEntryId(6), historyPageFilter.oldestOnPage);
}
@Test
public void test_search_runs_by_build_number() throws IOException {
//given
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, null, null);
List<ModelObject> runs = newRuns(23, 24);
List<Queue.Item> queueItems = newQueueItems(25, 26);
//and
historyPageFilter.setSearchString("23");
//when
historyPageFilter.add(runs, queueItems);
//then
Assert.assertEquals(1, historyPageFilter.runs.size());
Assert.assertEquals(HistoryPageEntry.getEntryId(23), historyPageFilter.runs.get(0).getEntryId());
}
@Test
public void test_search_should_be_case_sensitive_for_anonymous_user() throws IOException {
//given
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, null, null);
//and
historyPageFilter.setSearchString("failure");
//and
List<ModelObject> runs = Lists.<ModelObject>newArrayList(new MockRun(2, Result.FAILURE), new MockRun(1, Result.SUCCESS));
List<Queue.Item> queueItems = newQueueItems(3, 4);
//when
historyPageFilter.add(runs, queueItems);
//then
Assert.assertEquals(0, historyPageFilter.runs.size());
}
@Test
public void test_search_builds_by_build_variables() throws IOException {
List<ModelObject> runs = ImmutableList.<ModelObject>of(
new MockBuild(2).withBuildVariables(ImmutableMap.of("env", "dummyEnv")),
new MockBuild(1).withBuildVariables(ImmutableMap.of("env", "otherEnv")));
assertOneMatchingBuildForGivenSearchStringAndRunItems("dummyEnv", runs);
}
@Test
public void test_search_builds_by_build_params() throws IOException {
List<ModelObject> runs = ImmutableList.<ModelObject>of(
new MockBuild(2).withBuildParameters(ImmutableMap.of("env", "dummyEnv")),
new MockBuild(1).withBuildParameters(ImmutableMap.of("env", "otherEnv")));
assertOneMatchingBuildForGivenSearchStringAndRunItems("dummyEnv", runs);
}
@Test
public void test_ignore_sensitive_parameters_in_search_builds_by_build_params() throws IOException {
List<ModelObject> runs = ImmutableList.<ModelObject>of(
new MockBuild(2).withBuildParameters(ImmutableMap.of("plainPassword", "pass1plain")),
new MockBuild(1).withSensitiveBuildParameters("password", "pass1"));
assertOneMatchingBuildForGivenSearchStringAndRunItems("pass1", runs);
}
private void assertOneMatchingBuildForGivenSearchStringAndRunItems(String searchString, List<ModelObject> runs) {
//given
HistoryPageFilter<ModelObject> historyPageFilter = newPage(5, null, null);
//and
historyPageFilter.setSearchString(searchString);
//and
List<Queue.Item> queueItems = newQueueItems(3, 4);
//when
historyPageFilter.add(runs, queueItems);
//then
Assert.assertEquals(1, historyPageFilter.runs.size());
Assert.assertEquals(HistoryPageEntry.getEntryId(2), historyPageFilter.runs.get(0).getEntryId());
}
private List<Queue.Item> newQueueItems(long startId, long endId) {
List<Queue.Item> items = new ArrayList<>();
for (long queueId = startId; queueId <= endId; queueId++) {
......@@ -329,6 +418,11 @@ public class HistoryPageFilterTest {
this.queueId = queueId;
}
public MockRun(long queueId, Result result) throws IOException {
this(queueId);
this.result = result;
}
@Override
public int compareTo(Run o) {
return 0;
......@@ -373,4 +467,60 @@ public class HistoryPageFilterTest {
return super.getNumber();
}
}
private static class MockBuild extends Build<FreeStyleProject, FreeStyleBuild> {
private final int buildNumber;
private Map<String, String> buildVariables = Collections.emptyMap();
private MockBuild(int buildNumber) {
super(Mockito.mock(FreeStyleProject.class), Mockito.mock(Calendar.class));
this.buildNumber = buildNumber;
}
@Override
public int getNumber() {
return buildNumber;
}
@Override
public Map<String, String> getBuildVariables() {
return buildVariables;
}
MockBuild withBuildVariables(Map<String, String> buildVariables) {
this.buildVariables = buildVariables;
return this;
}
MockBuild withBuildParameters(Map<String, String> buildParametersAsMap) throws IOException {
addAction(new ParametersAction(buildPropertiesMapToParameterValues(buildParametersAsMap), buildParametersAsMap.keySet()));
return this;
}
//TODO: Rewrite in functional style when Java 8 is available
private List<ParameterValue> buildPropertiesMapToParameterValues(Map<String, String> buildParametersAsMap) {
List<ParameterValue> parameterValues = new ArrayList<>();
for (Map.Entry<String, String> parameter : buildParametersAsMap.entrySet()) {
parameterValues.add(new StringParameterValue(parameter.getKey(), parameter.getValue()));
}
return parameterValues;
}
MockBuild withSensitiveBuildParameters(String paramName, String paramValue) throws IOException {
addAction(new ParametersAction(ImmutableList.<ParameterValue>of(createSensitiveStringParameterValue(paramName, paramValue)),
ImmutableList.of(paramName)));
return this;
}
private StringParameterValue createSensitiveStringParameterValue(final String paramName, final String paramValue) {
return new StringParameterValue(paramName, paramValue) {
@Override
public boolean isSensitive() {
return true;
}
};
}
}
}
package jenkins.widgets;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
import org.mockito.Mockito;
import com.google.common.collect.ImmutableList;
import hudson.model.Job;
import hudson.model.ModelObject;
import hudson.model.Queue;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.User;
import hudson.search.UserSearchProperty;
import hudson.security.ACL;
import hudson.security.ACLContext;
import hudson.security.AuthorizationStrategy;
/**
* TODO: Code partially duplicated with HistoryPageFilterTest in core
*/
public class HistoryPageFilterInsensitiveSearchTest {
private static final String TEST_USER_NAME = "testUser";
@Rule
public JenkinsRule j = new JenkinsRule();
@Test
public void should_search_insensitively_when_enabled_for_user() throws IOException {
setUserContextAndAssertCaseInsensitivitySearchForGivenSearchString("failure");
}
@Test
public void should_also_lower_search_query_in_insensitive_search_enabled() throws IOException {
setUserContextAndAssertCaseInsensitivitySearchForGivenSearchString("FAILure");
}
private void setUserContextAndAssertCaseInsensitivitySearchForGivenSearchString(final String searchString) throws IOException {
AuthorizationStrategy.Unsecured strategy = new AuthorizationStrategy.Unsecured();
j.jenkins.setAuthorizationStrategy(strategy);
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
UsernamePasswordAuthenticationToken testUserAuthentication = new UsernamePasswordAuthenticationToken(TEST_USER_NAME, "any");
try (ACLContext acl = ACL.as(testUserAuthentication)) {
User.get(TEST_USER_NAME).addProperty(new UserSearchProperty(true));
//test logic
List<ModelObject> runs = ImmutableList.<ModelObject>of(new MockRun(2, Result.FAILURE), new MockRun(1, Result.SUCCESS));
assertOneMatchingBuildForGivenSearchStringAndRunItems(searchString, runs);
}
}
private void assertOneMatchingBuildForGivenSearchStringAndRunItems(String searchString, List<ModelObject> runs) {
//given
HistoryPageFilter<ModelObject> historyPageFilter = new HistoryPageFilter<>(5);
//and
historyPageFilter.setSearchString(searchString);
//when
historyPageFilter.add(runs, Collections.<Queue.Item>emptyList());
//then
Assert.assertEquals(1, historyPageFilter.runs.size());
Assert.assertEquals(HistoryPageEntry.getEntryId(2), historyPageFilter.runs.get(0).getEntryId());
}
@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;
}
public MockRun(long queueId, Result result) throws IOException {
this(queueId);
this.result = result;
}
@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;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册