LCOV - code coverage report
Current view: top level - acceptance/testsuite/change - ChangeKindCreator.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 141 145 97.2 %
Date: 2022-11-19 15:00:39 Functions: 17 17 100.0 %

          Line data    Source code
       1             : // Copyright (C) 2021 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.acceptance.testsuite.change;
      16             : 
      17             : import static com.google.common.truth.Truth.assertThat;
      18             : import static com.google.common.truth.Truth.assertWithMessage;
      19             : import static org.eclipse.jgit.lib.Constants.HEAD;
      20             : 
      21             : import com.google.common.collect.ImmutableList;
      22             : import com.google.gerrit.acceptance.GitUtil;
      23             : import com.google.gerrit.acceptance.PushOneCommit;
      24             : import com.google.gerrit.acceptance.TestAccount;
      25             : import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
      26             : import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
      27             : import com.google.gerrit.entities.LabelId;
      28             : import com.google.gerrit.entities.Project;
      29             : import com.google.gerrit.extensions.api.GerritApi;
      30             : import com.google.gerrit.extensions.api.changes.CherryPickInput;
      31             : import com.google.gerrit.extensions.api.changes.ReviewInput;
      32             : import com.google.gerrit.extensions.api.changes.RevisionApi;
      33             : import com.google.gerrit.extensions.client.ChangeKind;
      34             : import com.google.gerrit.extensions.client.ListChangesOption;
      35             : import com.google.gerrit.extensions.common.ChangeInfo;
      36             : import com.google.gerrit.extensions.common.CommitInfo;
      37             : import com.google.inject.Inject;
      38             : import java.util.List;
      39             : import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
      40             : import org.eclipse.jgit.junit.TestRepository;
      41             : import org.eclipse.jgit.lib.ObjectId;
      42             : import org.eclipse.jgit.lib.PersonIdent;
      43             : import org.eclipse.jgit.revwalk.RevCommit;
      44             : 
      45             : /** Helper to create changes of a certain {@link ChangeKind}. */
      46             : public class ChangeKindCreator {
      47             :   private GerritApi gApi;
      48             :   private PushOneCommit.Factory pushFactory;
      49             :   private RequestScopeOperations requestScopeOperations;
      50             :   private ProjectOperations projectOperations;
      51             : 
      52             :   @Inject
      53             :   private ChangeKindCreator(
      54             :       GerritApi gApi,
      55             :       PushOneCommit.Factory pushFactory,
      56             :       RequestScopeOperations requestScopeOperations,
      57           2 :       ProjectOperations projectOperations) {
      58           2 :     this.gApi = gApi;
      59           2 :     this.pushFactory = pushFactory;
      60           2 :     this.requestScopeOperations = requestScopeOperations;
      61           2 :     this.projectOperations = projectOperations;
      62           2 :   }
      63             : 
      64             :   /** Creates a change with the given {@link ChangeKind} and returns the change id. */
      65             :   public String createChange(
      66             :       ChangeKind kind, TestRepository<InMemoryRepository> testRepo, TestAccount user)
      67             :       throws Exception {
      68           2 :     switch (kind) {
      69             :       case NO_CODE_CHANGE:
      70             :       case REWORK:
      71             :       case TRIVIAL_REBASE:
      72             :       case NO_CHANGE:
      73           2 :         return createChange(testRepo, user).getChangeId();
      74             :       case MERGE_FIRST_PARENT_UPDATE:
      75           1 :         return createChangeForMergeCommit(testRepo, user);
      76             :       default:
      77           0 :         throw new IllegalStateException("unexpected change kind: " + kind);
      78             :     }
      79             :   }
      80             : 
      81             :   /** Updates a change with the given {@link ChangeKind}. */
      82             :   public void updateChange(
      83             :       String changeId,
      84             :       ChangeKind changeKind,
      85             :       TestRepository<InMemoryRepository> testRepo,
      86             :       TestAccount user,
      87             :       Project.NameKey project)
      88             :       throws Exception {
      89           2 :     switch (changeKind) {
      90             :       case NO_CODE_CHANGE:
      91           2 :         noCodeChange(changeId, testRepo, user);
      92           2 :         return;
      93             :       case REWORK:
      94           2 :         rework(changeId, testRepo, user);
      95           2 :         return;
      96             :       case TRIVIAL_REBASE:
      97           2 :         trivialRebase(changeId, testRepo, user, project);
      98           2 :         return;
      99             :       case MERGE_FIRST_PARENT_UPDATE:
     100           1 :         updateFirstParent(changeId, testRepo, user);
     101           1 :         return;
     102             :       case NO_CHANGE:
     103           1 :         noChange(changeId, testRepo, user);
     104           1 :         return;
     105             :       default:
     106           0 :         assertWithMessage("unexpected change kind: " + changeKind).fail();
     107             :     }
     108           0 :   }
     109             : 
     110             :   /**
     111             :    * Creates a cherry pick of the provided change with the given {@link ChangeKind} and returns the
     112             :    * change id.
     113             :    */
     114             :   public String cherryPick(
     115             :       String changeId,
     116             :       ChangeKind changeKind,
     117             :       TestRepository<InMemoryRepository> testRepo,
     118             :       TestAccount user,
     119             :       Project.NameKey project)
     120             :       throws Exception {
     121           1 :     switch (changeKind) {
     122             :       case REWORK:
     123             :       case TRIVIAL_REBASE:
     124           1 :         break;
     125             :       case NO_CODE_CHANGE:
     126             :       case NO_CHANGE:
     127             :       case MERGE_FIRST_PARENT_UPDATE:
     128             :       default:
     129           0 :         assertWithMessage("unexpected change kind: " + changeKind).fail();
     130             :     }
     131             : 
     132           1 :     testRepo.reset(projectOperations.project(project).getHead("master"));
     133           1 :     PushOneCommit.Result r =
     134             :         pushFactory
     135           1 :             .create(
     136           1 :                 user.newIdent(),
     137             :                 testRepo,
     138             :                 PushOneCommit.SUBJECT,
     139             :                 "other.txt",
     140           1 :                 "new content " + System.nanoTime())
     141           1 :             .to("refs/for/master");
     142           1 :     r.assertOkStatus();
     143           1 :     vote(user, r.getChangeId(), 2, 1);
     144           1 :     merge(r);
     145             : 
     146             :     String subject =
     147           1 :         ChangeKind.TRIVIAL_REBASE.equals(changeKind)
     148           1 :             ? PushOneCommit.SUBJECT
     149           1 :             : "Reworked change " + System.nanoTime();
     150           1 :     CherryPickInput in = new CherryPickInput();
     151           1 :     in.destination = "master";
     152           1 :     in.message = String.format("%s\n\nChange-Id: %s", subject, changeId);
     153           1 :     ChangeInfo c = gApi.changes().id(changeId).current().cherryPick(in).get();
     154           1 :     return c.changeId;
     155             :   }
     156             : 
     157             :   /** Creates a change that is a merge {@link ChangeKind} and returns the change id. */
     158             :   public String createChangeForMergeCommit(
     159             :       TestRepository<InMemoryRepository> testRepo, TestAccount user) throws Exception {
     160           1 :     ObjectId initial = testRepo.getRepository().exactRef(HEAD).getLeaf().getObjectId();
     161             : 
     162           1 :     PushOneCommit.Result parent1 = createChange("parent 1", "p1.txt", "content 1", testRepo, user);
     163             : 
     164           1 :     testRepo.reset(initial);
     165           1 :     PushOneCommit.Result parent2 = createChange("parent 2", "p2.txt", "content 2", testRepo, user);
     166             : 
     167           1 :     testRepo.reset(parent1.getCommit());
     168             : 
     169           1 :     PushOneCommit merge = pushFactory.create(user.newIdent(), testRepo);
     170           1 :     merge.setParents(ImmutableList.of(parent1.getCommit(), parent2.getCommit()));
     171           1 :     PushOneCommit.Result result = merge.to("refs/for/master");
     172           1 :     result.assertOkStatus();
     173           1 :     return result.getChangeId();
     174             :   }
     175             : 
     176             :   /** Update the first parent of a merge. */
     177             :   public void updateFirstParent(
     178             :       String changeId, TestRepository<InMemoryRepository> testRepo, TestAccount user)
     179             :       throws Exception {
     180           1 :     ChangeInfo c = detailedChange(changeId);
     181           1 :     List<CommitInfo> parents = c.revisions.get(c.currentRevision).commit.parents;
     182           1 :     String parent1 = parents.get(0).commit;
     183           1 :     String parent2 = parents.get(1).commit;
     184           1 :     RevCommit commitParent2 = testRepo.getRevWalk().parseCommit(ObjectId.fromString(parent2));
     185             : 
     186           1 :     testRepo.reset(parent1);
     187           1 :     PushOneCommit.Result newParent1 =
     188           1 :         createChange("new parent 1", "p1-1.txt", "content 1-1", testRepo, user);
     189             : 
     190           1 :     PushOneCommit merge = pushFactory.create(user.newIdent(), testRepo, changeId);
     191           1 :     merge.setParents(ImmutableList.of(newParent1.getCommit(), commitParent2));
     192           1 :     PushOneCommit.Result result = merge.to("refs/for/master");
     193           1 :     result.assertOkStatus();
     194             : 
     195           1 :     assertThat(getChangeKind(changeId)).isEqualTo(ChangeKind.MERGE_FIRST_PARENT_UPDATE);
     196           1 :   }
     197             : 
     198             :   /** Update the second parent of a merge. */
     199             :   public void updateSecondParent(
     200             :       String changeId, TestRepository<InMemoryRepository> testRepo, TestAccount user)
     201             :       throws Exception {
     202           1 :     ChangeInfo c = detailedChange(changeId);
     203           1 :     List<CommitInfo> parents = c.revisions.get(c.currentRevision).commit.parents;
     204           1 :     String parent1 = parents.get(0).commit;
     205           1 :     String parent2 = parents.get(1).commit;
     206           1 :     RevCommit commitParent1 = testRepo.getRevWalk().parseCommit(ObjectId.fromString(parent1));
     207             : 
     208           1 :     testRepo.reset(parent2);
     209           1 :     PushOneCommit.Result newParent2 =
     210           1 :         createChange("new parent 2", "p2-2.txt", "content 2-2", testRepo, user);
     211             : 
     212           1 :     PushOneCommit merge = pushFactory.create(user.newIdent(), testRepo, changeId);
     213           1 :     merge.setParents(ImmutableList.of(commitParent1, newParent2.getCommit()));
     214           1 :     PushOneCommit.Result result = merge.to("refs/for/master");
     215           1 :     result.assertOkStatus();
     216             : 
     217           1 :     assertThat(getChangeKind(changeId)).isEqualTo(ChangeKind.REWORK);
     218           1 :   }
     219             : 
     220             :   private void noCodeChange(
     221             :       String changeId, TestRepository<InMemoryRepository> testRepo, TestAccount user)
     222             :       throws Exception {
     223           2 :     TestRepository<?>.CommitBuilder commitBuilder =
     224           2 :         testRepo.amendRef("HEAD").insertChangeId(changeId.substring(1));
     225           2 :     commitBuilder
     226           2 :         .message("New subject " + System.nanoTime())
     227           2 :         .author(user.newIdent())
     228           2 :         .committer(new PersonIdent(user.newIdent(), testRepo.getDate()));
     229           2 :     commitBuilder.create();
     230           2 :     GitUtil.pushHead(testRepo, "refs/for/master", false);
     231           2 :     assertThat(getChangeKind(changeId)).isEqualTo(ChangeKind.NO_CODE_CHANGE);
     232           2 :   }
     233             : 
     234             :   private void noChange(
     235             :       String changeId, TestRepository<InMemoryRepository> testRepo, TestAccount user)
     236             :       throws Exception {
     237           1 :     ChangeInfo change = gApi.changes().id(changeId).get();
     238           1 :     String commitMessage = change.revisions.get(change.currentRevision).commit.message;
     239             : 
     240           1 :     TestRepository<?>.CommitBuilder commitBuilder =
     241           1 :         testRepo.amendRef("HEAD").insertChangeId(changeId.substring(1));
     242           1 :     commitBuilder
     243           1 :         .message(commitMessage)
     244           1 :         .author(user.newIdent())
     245           1 :         .committer(new PersonIdent(user.newIdent(), testRepo.getDate()));
     246           1 :     commitBuilder.create();
     247           1 :     GitUtil.pushHead(testRepo, "refs/for/master", false);
     248           1 :     assertThat(getChangeKind(changeId)).isEqualTo(ChangeKind.NO_CHANGE);
     249           1 :   }
     250             : 
     251             :   private void rework(
     252             :       String changeId, TestRepository<InMemoryRepository> testRepo, TestAccount user)
     253             :       throws Exception {
     254           2 :     PushOneCommit push =
     255           2 :         pushFactory.create(
     256           2 :             user.newIdent(),
     257             :             testRepo,
     258             :             PushOneCommit.SUBJECT,
     259             :             PushOneCommit.FILE_NAME,
     260           2 :             "new content " + System.nanoTime(),
     261             :             changeId);
     262           2 :     push.to("refs/for/master").assertOkStatus();
     263           2 :     assertThat(getChangeKind(changeId)).isEqualTo(ChangeKind.REWORK);
     264           2 :   }
     265             : 
     266             :   private void trivialRebase(
     267             :       String changeId,
     268             :       TestRepository<InMemoryRepository> testRepo,
     269             :       TestAccount user,
     270             :       Project.NameKey project)
     271             :       throws Exception {
     272           2 :     requestScopeOperations.setApiUser(user.id());
     273           2 :     testRepo.reset(projectOperations.project(project).getHead("master"));
     274           2 :     PushOneCommit push =
     275           2 :         pushFactory.create(
     276           2 :             user.newIdent(),
     277             :             testRepo,
     278             :             "Other Change",
     279           2 :             "a" + System.nanoTime() + ".txt",
     280             :             PushOneCommit.FILE_CONTENT);
     281           2 :     PushOneCommit.Result r = push.to("refs/for/master");
     282           2 :     r.assertOkStatus();
     283           2 :     RevisionApi revision = gApi.changes().id(r.getChangeId()).current();
     284           2 :     ReviewInput in = new ReviewInput().label(LabelId.CODE_REVIEW, 2).label(LabelId.VERIFIED, 1);
     285           2 :     revision.review(in);
     286           2 :     revision.submit();
     287             : 
     288           2 :     gApi.changes().id(changeId).current().rebase();
     289           2 :     assertThat(getChangeKind(changeId)).isEqualTo(ChangeKind.TRIVIAL_REBASE);
     290           2 :   }
     291             : 
     292             :   private ChangeKind getChangeKind(String changeId) throws Exception {
     293           2 :     ChangeInfo c = gApi.changes().id(changeId).get(ListChangesOption.CURRENT_REVISION);
     294           2 :     return c.revisions.get(c.currentRevision).kind;
     295             :   }
     296             : 
     297             :   private PushOneCommit.Result createChange(
     298             :       TestRepository<InMemoryRepository> testRepo, TestAccount user) throws Exception {
     299           2 :     PushOneCommit push = pushFactory.create(user.newIdent(), testRepo);
     300           2 :     PushOneCommit.Result result = push.to("refs/for/master");
     301           2 :     result.assertOkStatus();
     302           2 :     return result;
     303             :   }
     304             : 
     305             :   private ChangeInfo detailedChange(String changeId) throws Exception {
     306           1 :     return gApi.changes()
     307           1 :         .id(changeId)
     308           1 :         .get(
     309             :             ListChangesOption.DETAILED_LABELS,
     310             :             ListChangesOption.CURRENT_REVISION,
     311             :             ListChangesOption.CURRENT_COMMIT);
     312             :   }
     313             : 
     314             :   private PushOneCommit.Result createChange(
     315             :       String subject,
     316             :       String fileName,
     317             :       String content,
     318             :       TestRepository<InMemoryRepository> testRepo,
     319             :       TestAccount user)
     320             :       throws Exception {
     321           1 :     PushOneCommit push = pushFactory.create(user.newIdent(), testRepo, subject, fileName, content);
     322           1 :     return push.to("refs/for/master");
     323             :   }
     324             : 
     325             :   private void vote(TestAccount user, String changeId, int codeReviewVote, int verifiedVote)
     326             :       throws Exception {
     327           1 :     requestScopeOperations.setApiUser(user.id());
     328           1 :     ReviewInput in =
     329             :         new ReviewInput()
     330           1 :             .label(LabelId.CODE_REVIEW, codeReviewVote)
     331           1 :             .label(LabelId.VERIFIED, verifiedVote);
     332           1 :     gApi.changes().id(changeId).current().review(in);
     333           1 :   }
     334             : 
     335             :   private void merge(PushOneCommit.Result r) throws Exception {
     336           1 :     gApi.changes().id(r.getChangeId()).current().review(ReviewInput.approve());
     337           1 :     gApi.changes().id(r.getChangeId()).current().submit();
     338           1 :   }
     339             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750