summaryrefslogtreecommitdiffstats
path: root/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java')
-rw-r--r--gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java300
1 files changed, 300 insertions, 0 deletions
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
new file mode 100644
index 0000000000..fa85927d8e
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/SubmitOnPushIT.java
@@ -0,0 +1,300 @@
+// Copyright (C) 2013 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.git;
+
+import static com.google.gerrit.acceptance.git.GitUtil.cloneProject;
+import static com.google.gerrit.acceptance.git.GitUtil.createProject;
+import static com.google.gerrit.acceptance.git.GitUtil.initSsh;
+import static org.junit.Assert.assertEquals;
+
+import com.google.common.collect.Iterables;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.AccountCreator;
+import com.google.gerrit.acceptance.SshSession;
+import com.google.gerrit.acceptance.TestAccount;
+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.reviewdb.server.ReviewDb;
+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.project.ProjectCache;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.inject.Inject;
+
+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.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.RefSpec;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+public class SubmitOnPushIT extends AbstractDaemonTest {
+
+ @Inject
+ private AccountCreator accounts;
+
+ @Inject
+ private SchemaFactory<ReviewDb> reviewDbProvider;
+
+ @Inject
+ private GitRepositoryManager repoManager;
+
+ @Inject
+ private MetaDataUpdate.Server metaDataUpdateFactory;
+
+ @Inject
+ private ProjectCache projectCache;
+
+ @Inject
+ private GroupCache groupCache;
+
+ @Inject
+ private @GerritPersonIdent PersonIdent serverIdent;
+
+ private TestAccount admin;
+ private Project.NameKey project;
+ private Git git;
+ private ReviewDb db;
+
+ @Before
+ public void setUp() throws Exception {
+ admin =
+ accounts.create("admin", "admin@example.com", "Administrator",
+ "Administrators");
+
+ project = new Project.NameKey("p");
+ initSsh(admin);
+ SshSession sshSession = new SshSession(admin);
+ createProject(sshSession, project.get());
+ git = cloneProject(sshSession.getUrl() + "/" + project.get());
+ sshSession.close();
+
+ db = reviewDbProvider.open();
+ }
+
+ @After
+ public void cleanup() {
+ db.close();
+ }
+
+ @Test
+ public void submitOnPush() throws GitAPIException, OrmException,
+ IOException, ConfigInvalidException {
+ grantSubmit(project, "refs/for/refs/heads/master");
+ PushOneCommit.Result r = pushTo("refs/for/master%submit");
+ r.assertOkStatus();
+ r.assertChange(Change.Status.MERGED, null, admin);
+ assertSubmitApproval(r.getPatchSetId());
+ assertCommit(project, "refs/heads/master");
+ }
+
+ @Test
+ public void submitOnPushToRefsMetaConfig() throws GitAPIException,
+ OrmException, IOException, ConfigInvalidException {
+ grantSubmit(project, "refs/for/refs/meta/config");
+
+ git.fetch().setRefSpecs(new RefSpec("refs/meta/config:refs/meta/config")).call();
+ ObjectId objectId = git.getRepository().getRef("refs/meta/config").getObjectId();
+ git.checkout().setName(objectId.getName()).call();
+
+ PushOneCommit.Result r = pushTo("refs/for/refs/meta/config%submit");
+ r.assertOkStatus();
+ r.assertChange(Change.Status.MERGED, null, admin);
+ assertSubmitApproval(r.getPatchSetId());
+ assertCommit(project, "refs/meta/config");
+ }
+
+ @Test
+ public void submitOnPushMergeConflict() throws GitAPIException, OrmException,
+ IOException, ConfigInvalidException {
+ String master = "refs/heads/master";
+ ObjectId objectId = git.getRepository().getRef(master).getObjectId();
+ push(master, "one change", "a.txt", "some content");
+ git.checkout().setName(objectId.getName()).call();
+
+ grantSubmit(project, "refs/for/refs/heads/master");
+ PushOneCommit.Result r =
+ push("refs/for/master%submit", "other change", "a.txt", "other content");
+ r.assertOkStatus();
+ r.assertChange(Change.Status.NEW, null, admin);
+ r.assertMessage(CommitMergeStatus.PATH_CONFLICT.getMessage());
+ }
+
+ @Test
+ public void submitOnPushSuccessfulMerge() throws GitAPIException, OrmException,
+ IOException, ConfigInvalidException {
+ String master = "refs/heads/master";
+ ObjectId objectId = git.getRepository().getRef(master).getObjectId();
+ push(master, "one change", "a.txt", "some content");
+ git.checkout().setName(objectId.getName()).call();
+
+ grantSubmit(project, "refs/for/refs/heads/master");
+ PushOneCommit.Result r =
+ push("refs/for/master%submit", "other change", "b.txt", "other content");
+ r.assertOkStatus();
+ r.assertChange(Change.Status.MERGED, null, admin);
+ assertMergeCommit(master, "other change");
+ }
+
+ @Test
+ public void submitOnPushNewPatchSet() throws GitAPIException,
+ OrmException, IOException, ConfigInvalidException {
+ PushOneCommit.Result r =
+ push("refs/for/master", PushOneCommit.SUBJECT, "a.txt", "some content");
+
+ grantSubmit(project, "refs/for/refs/heads/master");
+ r = push("refs/for/master%submit", PushOneCommit.SUBJECT, "a.txt",
+ "other content", r.getChangeId());
+ r.assertOkStatus();
+ r.assertChange(Change.Status.MERGED, null, admin);
+ Change c = Iterables.getOnlyElement(db.changes().byKey(
+ new Change.Key(r.getChangeId())).toList());
+ assertEquals(2, db.patchSets().byChange(c.getId()).toList().size());
+ assertSubmitApproval(r.getPatchSetId());
+ assertCommit(project, "refs/heads/master");
+ }
+
+ @Test
+ public void submitOnPushNotAllowed_Error() throws GitAPIException,
+ OrmException, IOException {
+ PushOneCommit.Result r = pushTo("refs/for/master%submit");
+ r.assertErrorStatus("submit not allowed");
+ }
+
+ @Test
+ public void submitOnPushNewPatchSetNotAllowed_Error() throws GitAPIException,
+ OrmException, IOException, ConfigInvalidException {
+ PushOneCommit.Result r =
+ push("refs/for/master", PushOneCommit.SUBJECT, "a.txt", "some content");
+
+ r = push("refs/for/master%submit", PushOneCommit.SUBJECT, "a.txt",
+ "other content", r.getChangeId());
+ r.assertErrorStatus("submit not allowed");
+ }
+
+ @Test
+ public void submitOnPushingDraft_Error() throws GitAPIException,
+ OrmException, IOException {
+ PushOneCommit.Result r = pushTo("refs/for/master%draft,submit");
+ r.assertErrorStatus("cannot submit draft");
+ }
+
+ @Test
+ public void submitOnPushToNonExistingBranch_Error() throws GitAPIException,
+ OrmException, IOException {
+ String branchName = "non-existing";
+ PushOneCommit.Result r = pushTo("refs/for/" + branchName + "%submit");
+ r.assertErrorStatus("branch " + branchName + " not found");
+ }
+
+ private void grantSubmit(Project.NameKey project, String ref)
+ throws RepositoryNotFoundException, IOException, ConfigInvalidException {
+ MetaDataUpdate md = metaDataUpdateFactory.create(project);
+ md.setMessage("Grant submit on " + ref);
+ ProjectConfig config = ProjectConfig.read(md);
+ AccessSection s = config.getAccessSection(ref, true);
+ Permission p = s.getPermission(Permission.SUBMIT, true);
+ AccountGroup adminGroup = groupCache.get(new AccountGroup.NameKey("Administrators"));
+ p.add(new PermissionRule(config.resolve(adminGroup)));
+ config.commit(md);
+ projectCache.evict(config.getProject());
+ }
+
+ private void assertSubmitApproval(PatchSet.Id patchSetId) throws OrmException {
+ List<PatchSetApproval> approvals = db.patchSetApprovals().byPatchSet(patchSetId).toList();
+ assertEquals(1, approvals.size());
+ PatchSetApproval a = approvals.get(0);
+ assertEquals(PatchSetApproval.LabelId.SUBMIT.get(), a.getLabel());
+ assertEquals(1, a.getValue());
+ assertEquals(admin.id, a.getAccountId());
+ }
+
+ private void assertCommit(Project.NameKey project, String branch) throws IOException {
+ Repository r = repoManager.openRepository(project);
+ try {
+ RevWalk rw = new RevWalk(r);
+ try {
+ RevCommit c = rw.parseCommit(r.getRef(branch).getObjectId());
+ assertEquals(PushOneCommit.SUBJECT, c.getShortMessage());
+ assertEquals(admin.email, c.getAuthorIdent().getEmailAddress());
+ assertEquals(admin.email, c.getCommitterIdent().getEmailAddress());
+ } finally {
+ rw.release();
+ }
+ } finally {
+ r.close();
+ }
+ }
+
+ private void assertMergeCommit(String branch, String subject) throws IOException {
+ Repository r = repoManager.openRepository(project);
+ try {
+ RevWalk rw = new RevWalk(r);
+ try {
+ RevCommit c = rw.parseCommit(r.getRef(branch).getObjectId());
+ assertEquals(2, c.getParentCount());
+ assertEquals("Merge \"" + subject + "\"", c.getShortMessage());
+ assertEquals(admin.email, c.getAuthorIdent().getEmailAddress());
+ assertEquals(serverIdent.getEmailAddress(), c.getCommitterIdent().getEmailAddress());
+ } finally {
+ rw.release();
+ }
+ } finally {
+ r.close();
+ }
+ }
+
+ private PushOneCommit.Result pushTo(String ref) throws GitAPIException,
+ IOException {
+ PushOneCommit push = new PushOneCommit(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 =
+ new PushOneCommit(db, admin.getIdent(), subject, fileName, content);
+ return push.to(git, ref);
+ }
+
+ private PushOneCommit.Result push(String ref, String subject,
+ String fileName, String content, String changeId) throws GitAPIException,
+ IOException {
+ PushOneCommit push = new PushOneCommit(db, admin.getIdent(), subject,
+ fileName, content, changeId);
+ return push.to(git, ref);
+ }
+}