diff options
Diffstat (limited to 'javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java')
-rw-r--r-- | javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java b/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java new file mode 100644 index 0000000000..7872b444a4 --- /dev/null +++ b/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java @@ -0,0 +1,481 @@ +// Copyright (C) 2017 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.server.query.project; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.TruthJUnit.assume; +import static java.util.stream.Collectors.toList; + +import com.google.common.base.CharMatcher; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.gerrit.extensions.api.GerritApi; +import com.google.gerrit.extensions.api.access.AccessSectionInfo; +import com.google.gerrit.extensions.api.access.PermissionInfo; +import com.google.gerrit.extensions.api.access.PermissionRuleInfo; +import com.google.gerrit.extensions.api.access.ProjectAccessInput; +import com.google.gerrit.extensions.api.projects.ConfigInput; +import com.google.gerrit.extensions.api.projects.ProjectInput; +import com.google.gerrit.extensions.api.projects.Projects.QueryRequest; +import com.google.gerrit.extensions.client.ProjectState; +import com.google.gerrit.extensions.common.AccountInfo; +import com.google.gerrit.extensions.common.ProjectInfo; +import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.index.Schema; +import com.google.gerrit.index.project.ProjectData; +import com.google.gerrit.index.project.ProjectIndexCollection; +import com.google.gerrit.lifecycle.LifecycleManager; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.Project; +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.AnonymousUser; +import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.IdentifiedUser; +import com.google.gerrit.server.ServerInitiated; +import com.google.gerrit.server.account.AccountCache; +import com.google.gerrit.server.account.AccountManager; +import com.google.gerrit.server.account.Accounts; +import com.google.gerrit.server.account.AccountsUpdate; +import com.google.gerrit.server.account.AuthRequest; +import com.google.gerrit.server.config.AllProjectsName; +import com.google.gerrit.server.config.AllUsersName; +import com.google.gerrit.server.group.SystemGroupBackend; +import com.google.gerrit.server.schema.SchemaCreator; +import com.google.gerrit.server.util.ManualRequestContext; +import com.google.gerrit.server.util.OneOffRequestContext; +import com.google.gerrit.server.util.RequestContext; +import com.google.gerrit.server.util.ThreadLocalRequestContext; +import com.google.gerrit.testing.GerritServerTests; +import com.google.gerrit.testing.InMemoryDatabase; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.Provider; +import com.google.inject.util.Providers; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +@Ignore +public abstract class AbstractQueryProjectsTest extends GerritServerTests { + @Inject protected Accounts accounts; + + @Inject @ServerInitiated protected Provider<AccountsUpdate> accountsUpdate; + + @Inject protected AccountCache accountCache; + + @Inject protected AccountManager accountManager; + + @Inject protected GerritApi gApi; + + @Inject protected IdentifiedUser.GenericFactory userFactory; + + @Inject private Provider<AnonymousUser> anonymousUser; + + @Inject protected InMemoryDatabase schemaFactory; + + @Inject protected SchemaCreator schemaCreator; + + @Inject protected ThreadLocalRequestContext requestContext; + + @Inject protected OneOffRequestContext oneOffRequestContext; + + @Inject protected ProjectIndexCollection indexes; + + @Inject protected AllProjectsName allProjects; + + @Inject protected AllUsersName allUsers; + + protected LifecycleManager lifecycle; + protected Injector injector; + protected ReviewDb db; + protected AccountInfo currentUserInfo; + protected CurrentUser user; + + protected abstract Injector createInjector(); + + @Before + public void setUpInjector() throws Exception { + lifecycle = new LifecycleManager(); + injector = createInjector(); + lifecycle.add(injector); + injector.injectMembers(this); + lifecycle.start(); + initAfterLifecycleStart(); + setUpDatabase(); + } + + @After + public void cleanUp() { + lifecycle.stop(); + db.close(); + } + + protected void setUpDatabase() throws Exception { + db = schemaFactory.open(); + schemaCreator.create(db); + + Account.Id userId = createAccount("user", "User", "user@example.com", true); + user = userFactory.create(userId); + requestContext.setContext(newRequestContext(userId)); + currentUserInfo = gApi.accounts().id(userId.get()).get(); + } + + protected void initAfterLifecycleStart() throws Exception {} + + protected RequestContext newRequestContext(Account.Id requestUserId) { + final CurrentUser requestUser = userFactory.create(requestUserId); + return new RequestContext() { + @Override + public CurrentUser getUser() { + return requestUser; + } + + @Override + public Provider<ReviewDb> getReviewDbProvider() { + return Providers.of(db); + } + }; + } + + protected void setAnonymous() { + requestContext.setContext( + new RequestContext() { + @Override + public CurrentUser getUser() { + return anonymousUser.get(); + } + + @Override + public Provider<ReviewDb> getReviewDbProvider() { + return Providers.of(db); + } + }); + } + + @After + public void tearDownInjector() { + if (lifecycle != null) { + lifecycle.stop(); + } + requestContext.setContext(null); + if (db != null) { + db.close(); + } + InMemoryDatabase.drop(schemaFactory); + } + + @Test + public void byName() throws Exception { + assertQuery("name:project"); + assertQuery("name:non-existing"); + + ProjectInfo project = createProject(name("project")); + + assertQuery("name:" + project.name, project); + + // only exact match + ProjectInfo projectWithHyphen = createProject(name("project-with-hyphen")); + createProject(name("project-no-match-with-hyphen")); + assertQuery("name:" + projectWithHyphen.name, projectWithHyphen); + } + + @Test + public void byParent() throws Exception { + assertQuery("parent:project"); + ProjectInfo parent = createProject(name("parent")); + assertQuery("parent:" + parent.name); + ProjectInfo child = createProject(name("child"), parent.name); + assertQuery("parent:" + parent.name, child); + } + + @Test + public void byParentOfAllProjects() throws Exception { + Set<String> excludedProjects = ImmutableSet.of(allProjects.get(), allUsers.get()); + ProjectInfo[] projects = + gApi.projects().list().get().stream() + .filter(p -> !excludedProjects.contains(p.name)) + .toArray(s -> new ProjectInfo[s]); + assertQuery("parent:" + allProjects.get(), projects); + } + + @Test + public void byInname() throws Exception { + String namePart = getSanitizedMethodName(); + namePart = CharMatcher.is('_').removeFrom(namePart); + + ProjectInfo project1 = createProject(name("project1-" + namePart)); + ProjectInfo project2 = createProject(name("project2-" + namePart + "-foo")); + ProjectInfo project3 = createProject(name("project3-" + namePart + "foo")); + + assertQuery("inname:" + namePart, project1, project2, project3); + assertQuery("inname:" + namePart.toUpperCase(Locale.US), project1, project2, project3); + assertQuery("inname:" + namePart.toLowerCase(Locale.US), project1, project2, project3); + } + + @Test + public void byDescription() throws Exception { + ProjectInfo project1 = + createProjectWithDescription(name("project1"), "This is a test project."); + ProjectInfo project2 = createProjectWithDescription(name("project2"), "ANOTHER TEST PROJECT."); + createProjectWithDescription(name("project3"), "Maintainers of project foo."); + assertQuery("description:test", project1, project2); + + assertQuery("description:non-existing"); + + exception.expect(BadRequestException.class); + exception.expectMessage("description operator requires a value"); + assertQuery("description:\"\""); + } + + @Test + public void byState() throws Exception { + assume().that(getSchemaVersion() >= 2).isTrue(); + + ProjectInfo project1 = createProjectWithState(name("project1"), ProjectState.ACTIVE); + ProjectInfo project2 = createProjectWithState(name("project2"), ProjectState.READ_ONLY); + assertQuery("state:active", project1); + assertQuery("state:read-only", project2); + } + + @Test + public void byState_emptyQuery() throws Exception { + exception.expect(BadRequestException.class); + exception.expectMessage("state operator requires a value"); + assertQuery("state:\"\""); + } + + @Test + public void byState_badQuery() throws Exception { + exception.expect(BadRequestException.class); + exception.expectMessage("state operator must be either 'active' or 'read-only'"); + assertQuery("state:bla"); + } + + @Test + public void byDefaultField() throws Exception { + ProjectInfo project1 = createProject(name("foo-project")); + ProjectInfo project2 = createProject(name("project2")); + ProjectInfo project3 = + createProjectWithDescription( + name("project3"), + "decription that contains foo and the UUID of project2: " + project2.id); + + assertQuery("non-existing"); + assertQuery("foo", project1, project3); + assertQuery(project2.id, project2, project3); + } + + @Test + public void withLimit() throws Exception { + ProjectInfo project1 = createProject(name("project1")); + ProjectInfo project2 = createProject(name("project2")); + ProjectInfo project3 = createProject(name("project3")); + + String query = + "name:" + project1.name + " OR name:" + project2.name + " OR name:" + project3.name; + List<ProjectInfo> result = assertQuery(query, project1, project2, project3); + + assertQuery(newQuery(query).withLimit(2), result.subList(0, 2)); + } + + @Test + public void withStart() throws Exception { + ProjectInfo project1 = createProject(name("project1")); + ProjectInfo project2 = createProject(name("project2")); + ProjectInfo project3 = createProject(name("project3")); + + String query = + "name:" + project1.name + " OR name:" + project2.name + " OR name:" + project3.name; + List<ProjectInfo> result = assertQuery(query, project1, project2, project3); + + assertQuery(newQuery(query).withStart(1), result.subList(1, 3)); + } + + @Test + public void sortedByName() throws Exception { + ProjectInfo projectFoo = createProject("foo-" + name("project1")); + ProjectInfo projectBar = createProject("bar-" + name("project2")); + ProjectInfo projectBaz = createProject("baz-" + name("project3")); + + String query = + "name:" + projectFoo.name + " OR name:" + projectBar.name + " OR name:" + projectBaz.name; + assertQuery(newQuery(query), projectBar, projectBaz, projectFoo); + } + + @Test + public void asAnonymous() throws Exception { + ProjectInfo project = createProjectRestrictedToRegisteredUsers(name("project")); + + setAnonymous(); + assertQuery("name:" + project.name); + } + + private Account.Id createAccount(String username, String fullName, String email, boolean active) + throws Exception { + try (ManualRequestContext ctx = oneOffRequestContext.open()) { + Account.Id id = accountManager.authenticate(AuthRequest.forUser(username)).getAccountId(); + if (email != null) { + accountManager.link(id, AuthRequest.forEmail(email)); + } + accountsUpdate + .get() + .update( + "Update Test Account", + id, + u -> { + u.setFullName(fullName).setPreferredEmail(email).setActive(active); + }); + return id; + } + } + + protected ProjectInfo createProject(String name) throws Exception { + ProjectInput in = new ProjectInput(); + in.name = name; + return gApi.projects().create(in).get(); + } + + protected ProjectInfo createProject(String name, String parent) throws Exception { + ProjectInput in = new ProjectInput(); + in.name = name; + in.parent = parent; + return gApi.projects().create(in).get(); + } + + protected ProjectInfo createProjectWithDescription(String name, String description) + throws Exception { + ProjectInput in = new ProjectInput(); + in.name = name; + in.description = description; + return gApi.projects().create(in).get(); + } + + protected ProjectInfo createProjectWithState(String name, ProjectState state) throws Exception { + ProjectInfo info = createProject(name); + ConfigInput config = new ConfigInput(); + config.state = state; + gApi.projects().name(info.name).config(config); + return info; + } + + protected ProjectInfo createProjectRestrictedToRegisteredUsers(String name) throws Exception { + createProject(name); + + ProjectAccessInput accessInput = new ProjectAccessInput(); + AccessSectionInfo accessSection = new AccessSectionInfo(); + PermissionInfo read = new PermissionInfo(null, null); + PermissionRuleInfo pri = new PermissionRuleInfo(PermissionRuleInfo.Action.BLOCK, false); + read.rules = ImmutableMap.of(SystemGroupBackend.ANONYMOUS_USERS.get(), pri); + accessSection.permissions = ImmutableMap.of("read", read); + accessInput.add = ImmutableMap.of("refs/*", accessSection); + gApi.projects().name(name).access(accessInput); + + return gApi.projects().name(name).get(); + } + + protected ProjectInfo getProject(Project.NameKey nameKey) throws Exception { + return gApi.projects().name(nameKey.get()).get(); + } + + protected List<ProjectInfo> assertQuery(Object query, ProjectInfo... projects) throws Exception { + return assertQuery(newQuery(query), projects); + } + + protected List<ProjectInfo> assertQuery(QueryRequest query, ProjectInfo... projects) + throws Exception { + return assertQuery(query, Arrays.asList(projects)); + } + + protected List<ProjectInfo> assertQuery(QueryRequest query, List<ProjectInfo> projects) + throws Exception { + List<ProjectInfo> result = query.get(); + Iterable<String> names = names(result); + assertThat(names) + .named(format(query, result, projects)) + .containsExactlyElementsIn(names(projects)) + .inOrder(); + return result; + } + + protected QueryRequest newQuery(Object query) { + return gApi.projects().query(query.toString()); + } + + protected String format( + QueryRequest query, List<ProjectInfo> actualProjects, List<ProjectInfo> expectedProjects) { + StringBuilder b = new StringBuilder(); + b.append("query '").append(query.getQuery()).append("' with expected projects "); + b.append(format(expectedProjects)); + b.append(" and result "); + b.append(format(actualProjects)); + return b.toString(); + } + + protected String format(Iterable<ProjectInfo> projects) { + StringBuilder b = new StringBuilder(); + b.append("["); + Iterator<ProjectInfo> it = projects.iterator(); + while (it.hasNext()) { + ProjectInfo p = it.next(); + b.append("{") + .append(p.id) + .append(", ") + .append("name=") + .append(p.name) + .append(", ") + .append("parent=") + .append(p.parent) + .append(", ") + .append("description=") + .append(p.description) + .append("}"); + if (it.hasNext()) { + b.append(", "); + } + } + b.append("]"); + return b.toString(); + } + + protected int getSchemaVersion() { + return getSchema().getVersion(); + } + + protected Schema<ProjectData> getSchema() { + return indexes.getSearchIndex().getSchema(); + } + + protected static Iterable<String> names(ProjectInfo... projects) { + return names(Arrays.asList(projects)); + } + + protected static Iterable<String> names(List<ProjectInfo> projects) { + return projects.stream().map(p -> p.name).collect(toList()); + } + + protected String name(String name) { + if (name == null) { + return null; + } + + return name + "_" + getSanitizedMethodName(); + } +} |