blob: 7189a03c6d291bf1917ef710cbebd16e0d53e83a [file] [log] [blame]
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.acceptance.rest.project;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.rest.project.ProjectAssert.assertThatNameList;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static java.util.stream.Collectors.toList;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.GerritConfig;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.Sandboxed;
import com.google.gerrit.acceptance.TestProjectInput;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.extensions.api.projects.ConfigInfo;
import com.google.gerrit.extensions.api.projects.ConfigInput;
import com.google.gerrit.extensions.api.projects.Projects.ListRequest;
import com.google.gerrit.extensions.api.projects.Projects.ListRequest.FilterType;
import com.google.gerrit.extensions.client.ProjectState;
import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.OutputFormat;
import com.google.gerrit.server.project.ProjectCacheImpl;
import com.google.gerrit.server.project.testing.Util;
import com.google.gerrit.server.restapi.project.ListProjects;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.inject.Inject;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.IntStream;
import org.junit.Test;
@NoHttpd
@Sandboxed
public class ListProjectsIT extends AbstractDaemonTest {
@Inject private ListProjects listProjects;
@Test
public void listProjects() throws Exception {
Project.NameKey someProject = createProject("some-project");
assertThatNameList(filter(gApi.projects().list().get()))
.containsExactly(allProjects, allUsers, project, someProject)
.inOrder();
}
@Test
public void listProjectsFiltersInvisibleProjects() throws Exception {
setApiUser(user);
assertThatNameList(gApi.projects().list().get()).contains(project);
try (ProjectConfigUpdate u = updateProject(project)) {
Util.block(u.getConfig(), Permission.READ, REGISTERED_USERS, "refs/*");
u.save();
}
assertThatNameList(filter(gApi.projects().list().get())).doesNotContain(project);
}
@Test
public void listProjectsWithBranch() throws Exception {
Map<String, ProjectInfo> result = gApi.projects().list().addShowBranch("master").getAsMap();
assertThat(result).containsKey(project.get());
ProjectInfo info = result.get(project.get());
assertThat(info.branches).isNotNull();
assertThat(info.branches).hasSize(1);
assertThat(info.branches.get("master")).isNotNull();
}
@Test
@TestProjectInput(description = "Description of some-project")
public void listProjectWithDescription() throws Exception {
// description not be included in the results by default.
Map<String, ProjectInfo> result = gApi.projects().list().getAsMap();
assertThat(result).containsKey(project.get());
assertThat(result.get(project.get()).description).isNull();
result = gApi.projects().list().withDescription(true).getAsMap();
assertThat(result).containsKey(project.get());
assertThat(result.get(project.get()).description).isEqualTo("Description of some-project");
}
@Test
public void listProjectsWithLimit() throws Exception {
ProjectCacheImpl projectCacheImpl = (ProjectCacheImpl) projectCache;
for (int i = 0; i < 5; i++) {
createProject("someProject" + i);
}
String p = name("");
// 5, plus p which was automatically created.
int n = 6;
projectCacheImpl.evictAllByName();
for (int i = 1; i <= n + 2; i++) {
assertThatNameList(gApi.projects().list().withPrefix(p).withLimit(i).get())
.hasSize(Math.min(i, n));
assertThat(projectCacheImpl.sizeAllByName())
.isAtMost((long) (i + 2)); // 2 = AllProjects + AllUsers
}
}
@Test
@GerritConfig(name = "gerrit.listProjectsFromIndex", value = "true")
public void listProjectsFromIndexShouldBeLimitedTo500() throws Exception {
int numTestProjects = 501;
assertThat(createProjects("foo", numTestProjects)).hasSize(numTestProjects);
assertThat(gApi.projects().list().get()).hasSize(500);
}
@Test
public void listProjectsShouldNotBeLimitedByDefault() throws Exception {
int numTestProjects = 501;
assertThat(createProjects("foo", numTestProjects)).hasSize(numTestProjects);
assertThat(gApi.projects().list().get().size()).isAtLeast(numTestProjects);
}
@Test
public void listProjectsToOutputStream() throws Exception {
int numInitialProjects = gApi.projects().list().get().size();
int numTestProjects = 5;
List<String> testProjects = createProjects("zzz_testProject", numTestProjects);
try (ByteArrayOutputStream displayOut = new ByteArrayOutputStream()) {
listProjects.setStart(numInitialProjects);
listProjects.displayToStream(displayOut);
List<String> lines =
Splitter.on("\n").omitEmptyStrings().splitToList(new String(displayOut.toByteArray()));
assertThat(lines).isEqualTo(testProjects);
}
}
@Test
public void listProjectsAsJsonMultilineToOutputStream() throws Exception {
listProjectsAsJsonToOutputStream(OutputFormat.JSON);
}
@Test
public void listProjectsAsJsonCompactToOutputStream() throws Exception {
String jsonOutput = listProjectsAsJsonToOutputStream(OutputFormat.JSON_COMPACT).trim();
assertThat(jsonOutput).doesNotContain("\n");
}
private String listProjectsAsJsonToOutputStream(OutputFormat jsonFormat) throws Exception {
assertThat(jsonFormat.isJson()).isTrue();
int numInitialProjects = gApi.projects().list().get().size();
int numTestProjects = 5;
Set<String> testProjects =
ImmutableSet.copyOf(createProjects("zzz_testProject", numTestProjects));
try (ByteArrayOutputStream displayOut = new ByteArrayOutputStream()) {
listProjects.setStart(numInitialProjects);
listProjects.setFormat(jsonFormat);
listProjects.displayToStream(displayOut);
String projectsJsonOutput = new String(displayOut.toByteArray());
Gson gson = jsonFormat.newGson();
Set<String> projectsJsonNames = gson.fromJson(projectsJsonOutput, JsonObject.class).keySet();
assertThat(projectsJsonNames).isEqualTo(testProjects);
return projectsJsonOutput;
}
}
private List<String> createProjects(String prefix, int numProjects) {
return IntStream.range(0, numProjects)
.mapToObj(
i -> {
String projectName = prefix + i;
try {
return createProject(projectName);
} catch (RestApiException e) {
throw new IllegalStateException("Unable to create project " + projectName, e);
}
})
.map(Project.NameKey::get)
.collect(toList());
}
@Test
public void listProjectsWithPrefix() throws Exception {
Project.NameKey someProject = createProject("some-project");
Project.NameKey someOtherProject = createProject("some-other-project");
createProject("project-awesome");
String p = name("some");
assertBadRequest(gApi.projects().list().withPrefix(p).withRegex(".*"));
assertBadRequest(gApi.projects().list().withPrefix(p).withSubstring(p));
assertThatNameList(filter(gApi.projects().list().withPrefix(p).get()))
.containsExactly(someOtherProject, someProject)
.inOrder();
p = name("SOME");
assertThatNameList(filter(gApi.projects().list().withPrefix(p).get())).isEmpty();
}
@Test
public void listProjectsWithRegex() throws Exception {
Project.NameKey someProject = createProject("some-project");
Project.NameKey someOtherProject = createProject("some-other-project");
Project.NameKey projectAwesome = createProject("project-awesome");
assertBadRequest(gApi.projects().list().withRegex("[.*"));
assertBadRequest(gApi.projects().list().withRegex(".*").withPrefix("p"));
assertBadRequest(gApi.projects().list().withRegex(".*").withSubstring("p"));
assertThatNameList(filter(gApi.projects().list().withRegex(".*some").get()))
.containsExactly(projectAwesome);
String r = name("some-project$").replace(".", "\\.");
assertThatNameList(filter(gApi.projects().list().withRegex(r).get()))
.containsExactly(someProject);
assertThatNameList(filter(gApi.projects().list().withRegex(".*").get()))
.containsExactly(
allProjects, allUsers, project, projectAwesome, someOtherProject, someProject)
.inOrder();
}
@Test
public void listProjectsWithStart() throws Exception {
for (int i = 0; i < 5; i++) {
createProject(new Project.NameKey("someProject" + i).get());
}
String p = name("");
List<ProjectInfo> all = gApi.projects().list().withPrefix(p).get();
// 5, plus p which was automatically created.
int n = 6;
assertThat(all).hasSize(n);
assertThatNameList(gApi.projects().list().withPrefix(p).withStart(n - 1).get())
.containsExactly(new Project.NameKey(Iterables.getLast(all).name));
}
@Test
public void listProjectsWithSubstring() throws Exception {
Project.NameKey someProject = createProject("some-project");
Project.NameKey someOtherProject = createProject("some-other-project");
Project.NameKey projectAwesome = createProject("project-awesome");
assertBadRequest(gApi.projects().list().withSubstring("some").withRegex(".*"));
assertBadRequest(gApi.projects().list().withSubstring("some").withPrefix("some"));
assertThatNameList(filter(gApi.projects().list().withSubstring("some").get()))
.containsExactly(projectAwesome, someOtherProject, someProject)
.inOrder();
assertThatNameList(filter(gApi.projects().list().withSubstring("SOME").get()))
.containsExactly(projectAwesome, someOtherProject, someProject)
.inOrder();
}
@Test
public void listProjectsWithTree() throws Exception {
Project.NameKey someParentProject = createProject("some-parent-project");
Project.NameKey someChildProject = createProject("some-child-project", someParentProject);
Map<String, ProjectInfo> result = gApi.projects().list().withTree(true).getAsMap();
assertThat(result).containsKey(someChildProject.get());
assertThat(result.get(someChildProject.get()).parent).isEqualTo(someParentProject.get());
}
@Test
public void listProjectWithType() throws Exception {
Map<String, ProjectInfo> result =
gApi.projects().list().withType(FilterType.PERMISSIONS).getAsMap();
assertThat(result.keySet()).containsExactly(allProjects.get(), allUsers.get());
assertThatNameList(filter(gApi.projects().list().withType(FilterType.ALL).get()))
.containsExactly(allProjects, allUsers, project)
.inOrder();
}
@Test
public void listParentCandidates() throws Exception {
Map<String, ProjectInfo> result =
gApi.projects().list().withType(FilterType.PARENT_CANDIDATES).getAsMap();
assertThat(result).hasSize(1);
assertThat(result).containsKey(allProjects.get());
// Create a new project with 'project' as parent
Project.NameKey testProject = createProject(name("test"), project);
// Parent candidates are All-Projects and 'project'
assertThatNameList(filter(gApi.projects().list().withType(FilterType.PARENT_CANDIDATES).get()))
.containsExactly(allProjects, project)
.inOrder();
// All projects are listed
assertThatNameList(filter(gApi.projects().list().get()))
.containsExactly(allProjects, allUsers, testProject, project)
.inOrder();
}
@Test
public void listWithHiddenAndReadonlyProjects() throws Exception {
Project.NameKey hidden = createProject("project-to-hide");
Project.NameKey readonly = createProject("project-to-read");
// Set project read-only
ConfigInput input = new ConfigInput();
input.state = ProjectState.READ_ONLY;
ConfigInfo info = gApi.projects().name(readonly.get()).config(input);
assertThat(info.state).isEqualTo(input.state);
// The hidden project is included because it was not hidden yet.
// The read-only project is included.
assertThatNameList(gApi.projects().list().get())
.containsExactly(allProjects, allUsers, project, hidden, readonly)
.inOrder();
// Hide the project
input.state = ProjectState.HIDDEN;
info = gApi.projects().name(hidden.get()).config(input);
assertThat(info.state).isEqualTo(input.state);
// Project is still accessible directly
gApi.projects().name(hidden.get()).get();
// Hidden project is not included in the list
assertThatNameList(gApi.projects().list().get())
.containsExactly(allProjects, allUsers, project, readonly)
.inOrder();
// ALL filter applies to type, and doesn't include hidden state
assertThatNameList(gApi.projects().list().withType(FilterType.ALL).get())
.containsExactly(allProjects, allUsers, project, readonly)
.inOrder();
// "All" boolean option causes hidden projects to be included
assertThatNameList(gApi.projects().list().withAll(true).get())
.containsExactly(allProjects, allUsers, project, hidden, readonly)
.inOrder();
// "State" option causes only the projects in that state to be included
assertThatNameList(gApi.projects().list().withState(ProjectState.HIDDEN).get())
.containsExactly(hidden);
assertThatNameList(gApi.projects().list().withState(ProjectState.READ_ONLY).get())
.containsExactly(readonly);
assertThatNameList(gApi.projects().list().withState(ProjectState.ACTIVE).get())
.containsExactly(allProjects, allUsers, project)
.inOrder();
// Cannot use "all" and "state" together
assertBadRequest(gApi.projects().list().withAll(true).withState(ProjectState.ACTIVE));
}
private void assertBadRequest(ListRequest req) throws Exception {
try {
req.get();
fail("Expected BadRequestException");
} catch (BadRequestException expected) {
// Expected.
}
}
private Iterable<ProjectInfo> filter(Iterable<ProjectInfo> infos) {
String prefix = name("");
return Iterables.filter(
infos,
p -> {
return p.name != null
&& (p.name.equals(allProjects.get())
|| p.name.equals(allUsers.get())
|| p.name.startsWith(prefix));
});
}
}