Merge changes from topic 'rc-cleanup' * changes: Use refsByChange Multimap to build changeRefsById in ReceiveCommits Lazily load the changes byKey map in autoCloseChanges Simplify autoCloseCommits() handling of exact SHA-1 matches Cache reused values in autoCloseChanges Simplify parseBody call when looking at changes to close Refactor auto close change filtering in ReceiveCommits
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java index 655f07e..fcc8680 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -17,11 +17,16 @@ import static com.google.gerrit.acceptance.GitUtil.cloneProject; import static com.google.gerrit.acceptance.GitUtil.createProject; import static com.google.gerrit.acceptance.GitUtil.initSsh; +import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS; +import static com.google.gerrit.server.project.Util.block; import static org.junit.Assert.assertEquals; import com.google.common.base.Joiner; import com.google.common.primitives.Chars; import com.google.gerrit.acceptance.AcceptanceTestRequestScope.Context; +import com.google.gerrit.common.data.AccessSection; +import com.google.gerrit.common.data.Permission; +import com.google.gerrit.common.data.PermissionRule; import com.google.gerrit.extensions.api.GerritApi; import com.google.gerrit.extensions.api.changes.RevisionApi; import com.google.gerrit.extensions.common.ChangeInfo; @@ -32,6 +37,7 @@ import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.OutputFormat; +import com.google.gerrit.server.account.GroupCache; import com.google.gerrit.server.change.ChangeJson; import com.google.gerrit.server.config.AllProjectsName; import com.google.gerrit.server.git.MetaDataUpdate; @@ -48,6 +54,8 @@ import org.apache.http.HttpStatus; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.lib.Config; import org.junit.Rule; import org.junit.rules.TestRule; @@ -93,6 +101,9 @@ @Inject protected ProjectCache projectCache; + @Inject + protected GroupCache groupCache; + protected Git git; protected GerritServer server; protected TestAccount admin; @@ -266,4 +277,29 @@ } projectCache.evict(cfg.getProject()); } + + protected void grant(String permission, Project.NameKey project, String ref) + throws RepositoryNotFoundException, IOException, ConfigInvalidException { + MetaDataUpdate md = metaDataUpdateFactory.create(project); + md.setMessage(String.format("Grant %s on %s", permission, ref)); + ProjectConfig config = ProjectConfig.read(md); + AccessSection s = config.getAccessSection(ref, true); + Permission p = s.getPermission(permission, true); + AccountGroup adminGroup = groupCache.get(new AccountGroup.NameKey("Administrators")); + p.add(new PermissionRule(config.resolve(adminGroup))); + config.commit(md); + projectCache.evict(config.getProject()); + } + + protected void blockRead(Project.NameKey project, String ref) throws Exception { + ProjectConfig cfg = projectCache.checkedGet(project).getConfig(); + block(cfg, Permission.READ, REGISTERED_USERS, ref); + saveProjectConfig(project, cfg); + } + + protected PushOneCommit.Result pushTo(String ref) throws GitAPIException, + IOException { + PushOneCommit push = pushFactory.create(db, admin.getIdent()); + return push.to(git, ref); + } }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java index a96e721..5dbf366 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -278,10 +278,4 @@ PushOneCommit.Result r = pushTo("refs/for/master%hashtag=tag1"); r.assertErrorStatus("cannot add hashtags; noteDb is disabled"); } - - private PushOneCommit.Result pushTo(String ref) throws GitAPIException, - IOException { - PushOneCommit push = pushFactory.create(db, admin.getIdent()); - return push.to(git, ref); - } }
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/DraftChangeBlockedIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/DraftChangeBlockedIT.java index 2e0dfbd..6f13c17 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/DraftChangeBlockedIT.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/DraftChangeBlockedIT.java
@@ -58,12 +58,6 @@ r.assertErrorStatus("cannot upload drafts"); } - private PushOneCommit.Result pushTo(String ref) throws GitAPIException, - IOException { - PushOneCommit push = pushFactory.create(db, admin.getIdent()); - return push.to(git, ref); - } - private void saveProjectConfig(ProjectConfig cfg) throws IOException { MetaDataUpdate md = metaDataUpdateFactory.create(allProjects); try {
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java index b2e1b3f..cdd3740 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java
@@ -22,28 +22,21 @@ import com.google.gerrit.acceptance.AbstractDaemonTest; import com.google.gerrit.acceptance.NoHttpd; import com.google.gerrit.acceptance.PushOneCommit; -import com.google.gerrit.common.data.AccessSection; import com.google.gerrit.common.data.Permission; -import com.google.gerrit.common.data.PermissionRule; -import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSetApproval; import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.server.ApprovalsUtil; import com.google.gerrit.server.GerritPersonIdent; -import com.google.gerrit.server.account.GroupCache; import com.google.gerrit.server.git.CommitMergeStatus; import com.google.gerrit.server.git.GitRepositoryManager; -import com.google.gerrit.server.git.MetaDataUpdate; -import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.notedb.ChangeNotes; import com.google.gwtorm.server.OrmException; import com.google.inject.Inject; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.errors.ConfigInvalidException; -import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Repository; @@ -63,9 +56,6 @@ private ApprovalsUtil approvalsUtil; @Inject - private GroupCache groupCache; - - @Inject private ChangeNotes.Factory changeNotesFactory; @Inject @@ -217,19 +207,6 @@ assertEquals(Change.Status.MERGED, c.getStatus()); } - private void grant(String permission, Project.NameKey project, String ref) - throws RepositoryNotFoundException, IOException, ConfigInvalidException { - MetaDataUpdate md = metaDataUpdateFactory.create(project); - md.setMessage(String.format("Grant %s on %s", permission, ref)); - ProjectConfig config = ProjectConfig.read(md); - AccessSection s = config.getAccessSection(ref, true); - Permission p = s.getPermission(permission, true); - AccountGroup adminGroup = groupCache.get(new AccountGroup.NameKey("Administrators")); - p.add(new PermissionRule(config.resolve(adminGroup))); - config.commit(md); - projectCache.evict(config.getProject()); - } - private PatchSetApproval getSubmitter(PatchSet.Id patchSetId) throws OrmException { Change c = db.changes().get(patchSetId.getParentKey()); @@ -291,12 +268,6 @@ } } - private PushOneCommit.Result pushTo(String ref) throws GitAPIException, - IOException { - PushOneCommit push = pushFactory.create(db, admin.getIdent()); - return push.to(git, ref); - } - private PushOneCommit.Result push(String ref, String subject, String fileName, String content) throws GitAPIException, IOException { PushOneCommit push =
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java index b51a4e2..2e28655 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/ListBranchesIT.java
@@ -16,17 +16,12 @@ import static com.google.gerrit.acceptance.GitUtil.createProject; import static com.google.gerrit.acceptance.rest.project.BranchAssert.assertBranches; -import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS; -import static com.google.gerrit.server.project.Util.block; import static org.junit.Assert.assertEquals; import com.google.common.collect.Lists; import com.google.gerrit.acceptance.AbstractDaemonTest; -import com.google.gerrit.acceptance.PushOneCommit; import com.google.gerrit.acceptance.RestResponse; -import com.google.gerrit.common.data.Permission; import com.google.gerrit.reviewdb.client.Project; -import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.project.ListBranches.BranchInfo; import com.google.gson.reflect.TypeToken; @@ -123,12 +118,6 @@ return adminSession.get(endpoint); } - private void blockRead(Project.NameKey project, String ref) throws Exception { - ProjectConfig cfg = projectCache.checkedGet(project).getConfig(); - block(cfg, Permission.READ, REGISTERED_USERS, ref); - saveProjectConfig(project, cfg); - } - private static List<BranchInfo> toBranchInfoList(RestResponse r) throws IOException { List<BranchInfo> result = @@ -136,10 +125,4 @@ new TypeToken<List<BranchInfo>>() {}.getType()); return result; } - - private PushOneCommit.Result pushTo(String ref) throws GitAPIException, - IOException { - PushOneCommit push = pushFactory.create(db, admin.getIdent()); - return push.to(git, ref); - } }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/RequestUtil.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/RequestUtil.java new file mode 100644 index 0000000..c47ca30 --- /dev/null +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/RequestUtil.java
@@ -0,0 +1,48 @@ +// 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.httpd; + +import javax.servlet.http.HttpServletRequest; + +/** Utilities for manipulating HTTP request objects. */ +public class RequestUtil { + /** + * @return the same value as {@link HttpServletRequest#getPathInfo()}, but + * without decoding URL-encoded characters. + */ + public static String getEncodedPathInfo(HttpServletRequest req) { + // Based on com.google.guice.ServletDefinition$1#getPathInfo() from: + // https://github.com/google/guice/blob/41c126f99d6309886a0ded2ac729033d755e1593/extensions/servlet/src/com/google/inject/servlet/ServletDefinition.java + String servletPath = req.getServletPath(); + int servletPathLength = servletPath.length(); + String requestUri = req.getRequestURI(); + String pathInfo = requestUri.substring(req.getContextPath().length()) + .replaceAll("[/]{2,}", "/"); + if (pathInfo.startsWith(servletPath)) { + pathInfo = pathInfo.substring(servletPathLength); + // Corner case: when servlet path & request path match exactly (without + // trailing '/'), then pathinfo is null. + if (pathInfo.isEmpty() && servletPathLength > 0) { + pathInfo = null; + } + } else { + pathInfo = null; + } + return pathInfo; + } + + private RequestUtil() { + } +}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java index 90ce894..286f61b 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
@@ -26,6 +26,7 @@ import com.google.common.collect.Maps; import com.google.common.net.HttpHeaders; import com.google.gerrit.extensions.registration.RegistrationHandle; +import com.google.gerrit.httpd.RequestUtil; import com.google.gerrit.httpd.resources.Resource; import com.google.gerrit.httpd.resources.ResourceKey; import com.google.gerrit.httpd.resources.SmallResource; @@ -208,7 +209,7 @@ throws IOException, ServletException { List<String> parts = Lists.newArrayList( Splitter.on('/').limit(3).omitEmptyStrings() - .split(Strings.nullToEmpty(req.getPathInfo()))); + .split(Strings.nullToEmpty(RequestUtil.getEncodedPathInfo(req)))); if (isApiCall(req, parts)) { managerApi.service(req, res); @@ -255,7 +256,7 @@ return; } - String pathInfo = req.getPathInfo(); + String pathInfo = RequestUtil.getEncodedPathInfo(req); if (pathInfo.length() < 1) { Resource.NOT_FOUND.send(req, res); return;
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java index 0d62392..979990a 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -74,6 +74,7 @@ import com.google.gerrit.extensions.restapi.RestView; import com.google.gerrit.extensions.restapi.TopLevelResource; import com.google.gerrit.extensions.restapi.UnprocessableEntityException; +import com.google.gerrit.httpd.RequestUtil; import com.google.gerrit.httpd.WebSession; import com.google.gerrit.server.AccessPath; import com.google.gerrit.server.AnonymousUser; @@ -871,7 +872,7 @@ } private static List<IdString> splitPath(HttpServletRequest req) { - String path = req.getPathInfo(); + String path = RequestUtil.getEncodedPathInfo(req); if (Strings.isNullOrEmpty(path)) { return Collections.emptyList(); }
diff --git a/gerrit-httpd/src/test/java/com/google/gerrit/httpd/RequestUtilTest.java b/gerrit-httpd/src/test/java/com/google/gerrit/httpd/RequestUtilTest.java new file mode 100644 index 0000000..71a43bf --- /dev/null +++ b/gerrit-httpd/src/test/java/com/google/gerrit/httpd/RequestUtilTest.java
@@ -0,0 +1,91 @@ +// 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.httpd; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.junit.Assert.assertEquals; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +public class RequestUtilTest { + private List<Object> mocks; + + @Before + public void setUp() { + mocks = Collections.synchronizedList(new ArrayList<>()); + } + + @After + public void tearDown() { + for (Object mock : mocks) { + verify(mock); + } + } + + @Test + public void emptyContextPath() { + assertEquals("/foo/bar", RequestUtil.getEncodedPathInfo( + mockRequest("/s/foo/bar", "", "/s"))); + assertEquals("/foo%2Fbar", RequestUtil.getEncodedPathInfo( + mockRequest("/s/foo%2Fbar", "", "/s"))); + } + + @Test + public void emptyServletPath() { + assertEquals("/foo/bar", RequestUtil.getEncodedPathInfo( + mockRequest("/c/foo/bar", "/c", ""))); + assertEquals("/foo%2Fbar", RequestUtil.getEncodedPathInfo( + mockRequest("/c/foo%2Fbar", "/c", ""))); + } + + @Test + public void trailingSlashes() { + assertEquals("/foo/bar/", RequestUtil.getEncodedPathInfo( + mockRequest("/c/s/foo/bar/", "/c", "/s"))); + assertEquals("/foo/bar/", RequestUtil.getEncodedPathInfo( + mockRequest("/c/s/foo/bar///", "/c", "/s"))); + assertEquals("/foo%2Fbar/", RequestUtil.getEncodedPathInfo( + mockRequest("/c/s/foo%2Fbar/", "/c", "/s"))); + assertEquals("/foo%2Fbar/", RequestUtil.getEncodedPathInfo( + mockRequest("/c/s/foo%2Fbar///", "/c", "/s"))); + } + + @Test + public void servletPathMatchesRequestPath() { + assertEquals(null, RequestUtil.getEncodedPathInfo( + mockRequest("/c/s", "/c", "/s"))); + } + + private HttpServletRequest mockRequest(String uri, String contextPath, String servletPath) { + HttpServletRequest req = createMock(HttpServletRequest.class); + expect(req.getRequestURI()).andStubReturn(uri); + expect(req.getContextPath()).andStubReturn(contextPath); + expect(req.getServletPath()).andStubReturn(servletPath); + replay(req); + mocks.add(req); + return req; + } +}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/AutoRegisterModules.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/AutoRegisterModules.java index 759700e..0eaddb3 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/AutoRegisterModules.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/AutoRegisterModules.java
@@ -65,32 +65,28 @@ this.env = env; this.scanner = scanner; this.classLoader = classLoader; - this.sshGen = env.hasSshModule() ? env.newSshModuleGenerator() : null; - this.httpGen = env.hasHttpModule() ? env.newHttpModuleGenerator() : null; + this.sshGen = env.hasSshModule() + ? env.newSshModuleGenerator() + : new ModuleGenerator.NOP(); + this.httpGen = env.hasHttpModule() + ? env.newHttpModuleGenerator() + : new HttpModuleGenerator.NOP(); } AutoRegisterModules discover() throws InvalidPluginException { sysSingletons = Sets.newHashSet(); sysListen = LinkedListMultimap.create(); - if (sshGen != null) { - sshGen.setPluginName(pluginName); - } - if (httpGen != null) { - httpGen.setPluginName(pluginName); - } + sshGen.setPluginName(pluginName); + httpGen.setPluginName(pluginName); scan(); if (!sysSingletons.isEmpty() || !sysListen.isEmpty()) { sysModule = makeSystemModule(); } - if (sshGen != null) { - sshModule = sshGen.create(); - } - if (httpGen != null) { - httpModule = httpGen.create(); - } + sshModule = sshGen.create(); + httpModule = httpGen.create(); return this; } @@ -158,14 +154,10 @@ } if (is("org.apache.sshd.server.Command", clazz)) { - if (sshGen != null) { - sshGen.export(export, clazz); - } + sshGen.export(export, clazz); } else if (is("javax.servlet.http.HttpServlet", clazz)) { - if (httpGen != null) { - httpGen.export(export, clazz); - listen(clazz, clazz); - } + httpGen.export(export, clazz); + listen(clazz, clazz); } else { int cnt = sysListen.size(); listen(clazz, clazz);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/HttpModuleGenerator.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/HttpModuleGenerator.java index 44b2434..dd0ce67 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/HttpModuleGenerator.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/HttpModuleGenerator.java
@@ -14,6 +14,15 @@ package com.google.gerrit.server.plugins; + public interface HttpModuleGenerator extends ModuleGenerator { void export(String javascript); + + static class NOP extends ModuleGenerator.NOP + implements HttpModuleGenerator { + @Override + public void export(String javascript) { + // do nothing + } + } }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ModuleGenerator.java b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ModuleGenerator.java index 2011e9d..ae8bb0c 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ModuleGenerator.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/plugins/ModuleGenerator.java
@@ -26,4 +26,27 @@ void listen(TypeLiteral<?> tl, Class<?> clazz); Module create() throws InvalidPluginException; + + static class NOP implements ModuleGenerator { + + @Override + public void setPluginName(String name) { + // do nothing + } + + @Override + public void listen(TypeLiteral<?> tl, Class<?> clazz) { + // do nothing + } + + @Override + public void export(Export export, Class<?> type) { + // do nothing + } + + @Override + public Module create() throws InvalidPluginException { + return null; + } + } }