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

          Line data    Source code
       1             : // Copyright (C) 2020 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 com.google.gerrit.entities.Account;
      18             : import com.google.gerrit.entities.Comment.Status;
      19             : import com.google.gerrit.entities.HumanComment;
      20             : import com.google.gerrit.entities.Patch;
      21             : import com.google.gerrit.entities.PatchSet;
      22             : import com.google.gerrit.entities.Project;
      23             : import com.google.gerrit.entities.RobotComment;
      24             : import com.google.gerrit.extensions.client.Comment;
      25             : import com.google.gerrit.extensions.client.Comment.Range;
      26             : import com.google.gerrit.extensions.restapi.RestApiException;
      27             : import com.google.gerrit.server.CommentsUtil;
      28             : import com.google.gerrit.server.IdentifiedUser;
      29             : import com.google.gerrit.server.IdentifiedUser.GenericFactory;
      30             : import com.google.gerrit.server.git.GitRepositoryManager;
      31             : import com.google.gerrit.server.notedb.ChangeNotes;
      32             : import com.google.gerrit.server.notedb.ChangeUpdate;
      33             : import com.google.gerrit.server.update.BatchUpdate;
      34             : import com.google.gerrit.server.update.BatchUpdateOp;
      35             : import com.google.gerrit.server.update.ChangeContext;
      36             : import com.google.gerrit.server.update.UpdateException;
      37             : import com.google.gerrit.server.util.time.TimeUtil;
      38             : import com.google.inject.Inject;
      39             : import com.google.inject.assistedinject.Assisted;
      40             : import java.io.IOException;
      41             : import java.time.Instant;
      42             : import org.eclipse.jgit.lib.ObjectInserter;
      43             : import org.eclipse.jgit.lib.Repository;
      44             : import org.eclipse.jgit.revwalk.RevWalk;
      45             : 
      46             : /**
      47             :  * The implementation of {@link PerPatchsetOperations}.
      48             :  *
      49             :  * <p>There is only one implementation of {@link PerPatchsetOperations}. Nevertheless, we keep the
      50             :  * separation between interface and implementation to enhance clarity.
      51             :  */
      52             : public class PerPatchsetOperationsImpl implements PerPatchsetOperations {
      53             :   private final GitRepositoryManager repositoryManager;
      54             :   private final IdentifiedUser.GenericFactory userFactory;
      55             :   private final BatchUpdate.Factory batchUpdateFactory;
      56             :   private final CommentsUtil commentsUtil;
      57             : 
      58             :   private final ChangeNotes changeNotes;
      59             :   private final PatchSet.Id patchsetId;
      60             : 
      61             :   public interface Factory {
      62             :     PerPatchsetOperationsImpl create(ChangeNotes changeNotes, PatchSet.Id patchsetId);
      63             :   }
      64             : 
      65             :   @Inject
      66             :   private PerPatchsetOperationsImpl(
      67             :       GitRepositoryManager repositoryManager,
      68             :       GenericFactory userFactory,
      69             :       BatchUpdate.Factory batchUpdateFactory,
      70             :       CommentsUtil commentsUtil,
      71             :       @Assisted ChangeNotes changeNotes,
      72           6 :       @Assisted PatchSet.Id patchsetId) {
      73           6 :     this.repositoryManager = repositoryManager;
      74           6 :     this.userFactory = userFactory;
      75           6 :     this.batchUpdateFactory = batchUpdateFactory;
      76           6 :     this.commentsUtil = commentsUtil;
      77           6 :     this.changeNotes = changeNotes;
      78           6 :     this.patchsetId = patchsetId;
      79           6 :   }
      80             : 
      81             :   @Override
      82             :   public TestPatchset get() {
      83           4 :     PatchSet patchset = changeNotes.getPatchSets().get(patchsetId);
      84           4 :     return TestPatchset.builder().patchsetId(patchsetId).commitId(patchset.commitId()).build();
      85             :   }
      86             : 
      87             :   @Override
      88             :   public TestCommentCreation.Builder newComment() {
      89           5 :     return TestCommentCreation.builder(this::createComment, Status.PUBLISHED);
      90             :   }
      91             : 
      92             :   @Override
      93             :   public TestCommentCreation.Builder newDraftComment() {
      94           3 :     return TestCommentCreation.builder(this::createComment, Status.DRAFT);
      95             :   }
      96             : 
      97             :   @Override
      98             :   public TestRobotCommentCreation.Builder newRobotComment() {
      99           3 :     return TestRobotCommentCreation.builder(this::createRobotComment);
     100             :   }
     101             : 
     102             :   private String createComment(TestCommentCreation commentCreation)
     103             :       throws IOException, RestApiException, UpdateException {
     104           5 :     Project.NameKey project = changeNotes.getProjectName();
     105             : 
     106           5 :     try (Repository repository = repositoryManager.openRepository(project);
     107           5 :         ObjectInserter objectInserter = repository.newObjectInserter();
     108           5 :         RevWalk revWalk = new RevWalk(objectInserter.newReader())) {
     109           5 :       Instant now = TimeUtil.now();
     110             : 
     111           5 :       IdentifiedUser author = getAuthor(commentCreation);
     112           5 :       CommentAdditionOp commentAdditionOp = new CommentAdditionOp(commentCreation);
     113           5 :       try (BatchUpdate batchUpdate = batchUpdateFactory.create(project, author, now)) {
     114           5 :         batchUpdate.setRepository(repository, revWalk, objectInserter);
     115           5 :         batchUpdate.addOp(changeNotes.getChangeId(), commentAdditionOp);
     116           5 :         batchUpdate.execute();
     117             :       }
     118           5 :       return commentAdditionOp.createdCommentUuid;
     119             :     }
     120             :   }
     121             : 
     122             :   private IdentifiedUser getAuthor(TestCommentCreation commentCreation) {
     123           5 :     Account.Id authorId = commentCreation.author().orElse(changeNotes.getChange().getOwner());
     124           5 :     return userFactory.create(authorId);
     125             :   }
     126             : 
     127             :   private IdentifiedUser getAuthor(TestRobotCommentCreation robotCommentCreation) {
     128           3 :     Account.Id authorId = robotCommentCreation.author().orElse(changeNotes.getChange().getOwner());
     129           3 :     return userFactory.create(authorId);
     130             :   }
     131             : 
     132             :   private static Comment.Range toCommentRange(TestRange range) {
     133           2 :     Comment.Range commentRange = new Range();
     134           2 :     commentRange.startLine = range.start().line();
     135           2 :     commentRange.startCharacter = range.start().charOffset();
     136           2 :     commentRange.endLine = range.end().line();
     137           2 :     commentRange.endCharacter = range.end().charOffset();
     138           2 :     return commentRange;
     139             :   }
     140             : 
     141             :   private class CommentAdditionOp implements BatchUpdateOp {
     142             :     private String createdCommentUuid;
     143             :     private final TestCommentCreation commentCreation;
     144             : 
     145           5 :     public CommentAdditionOp(TestCommentCreation commentCreation) {
     146           5 :       this.commentCreation = commentCreation;
     147           5 :     }
     148             : 
     149             :     @Override
     150             :     public boolean updateChange(ChangeContext context) {
     151           5 :       HumanComment comment = toNewComment(context, commentCreation);
     152           5 :       ChangeUpdate changeUpdate = context.getUpdate(patchsetId);
     153           5 :       changeUpdate.putComment(commentCreation.status(), comment);
     154             :       // For published comments, only the tag set on the ChangeUpdate (and not on the HumanComment)
     155             :       // matters.
     156           5 :       commentCreation.tag().ifPresent(changeUpdate::setTag);
     157           5 :       createdCommentUuid = comment.key.uuid;
     158           5 :       return true;
     159             :     }
     160             : 
     161             :     private HumanComment toNewComment(ChangeContext context, TestCommentCreation commentCreation) {
     162           5 :       String message = commentCreation.message().orElse("The text of a test comment.");
     163             : 
     164           5 :       String filePath = commentCreation.file().orElse(Patch.PATCHSET_LEVEL);
     165           5 :       short side = commentCreation.side().orElse(CommentSide.PATCHSET_COMMIT).getNumericSide();
     166           5 :       Boolean unresolved = commentCreation.unresolved().orElse(null);
     167           5 :       String parentUuid = commentCreation.parentUuid().orElse(null);
     168           5 :       Instant createdOn = commentCreation.createdOn().orElse(context.getWhen());
     169           5 :       HumanComment newComment =
     170           5 :           commentsUtil.newHumanComment(
     171           5 :               context.getNotes(),
     172           5 :               context.getUser(),
     173             :               createdOn,
     174             :               filePath,
     175             :               patchsetId,
     176             :               side,
     177             :               message,
     178             :               unresolved,
     179             :               parentUuid);
     180             :       // For draft comments, only the tag set on the HumanComment (and not on the ChangeUpdate)
     181             :       // matters.
     182           5 :       commentCreation.tag().ifPresent(tag -> newComment.tag = tag);
     183             : 
     184           5 :       commentCreation.line().ifPresent(line -> newComment.setLineNbrAndRange(line, null));
     185             :       // Specification of range trumps explicit line specification.
     186           5 :       commentCreation
     187           5 :           .range()
     188           5 :           .map(PerPatchsetOperationsImpl::toCommentRange)
     189           5 :           .ifPresent(range -> newComment.setLineNbrAndRange(null, range));
     190             : 
     191           5 :       commentsUtil.setCommentCommitId(
     192           5 :           newComment, context.getChange(), changeNotes.getPatchSets().get(patchsetId));
     193           5 :       return newComment;
     194             :     }
     195             :   }
     196             : 
     197             :   private String createRobotComment(TestRobotCommentCreation robotCommentCreation)
     198             :       throws IOException, RestApiException, UpdateException {
     199           3 :     Project.NameKey project = changeNotes.getProjectName();
     200             : 
     201           3 :     try (Repository repository = repositoryManager.openRepository(project);
     202           3 :         ObjectInserter objectInserter = repository.newObjectInserter();
     203           3 :         RevWalk revWalk = new RevWalk(objectInserter.newReader())) {
     204           3 :       Instant now = TimeUtil.now();
     205             : 
     206           3 :       IdentifiedUser author = getAuthor(robotCommentCreation);
     207           3 :       RobotCommentAdditionOp robotCommentAdditionOp =
     208             :           new RobotCommentAdditionOp(robotCommentCreation);
     209           3 :       try (BatchUpdate batchUpdate = batchUpdateFactory.create(project, author, now)) {
     210           3 :         batchUpdate.setRepository(repository, revWalk, objectInserter);
     211           3 :         batchUpdate.addOp(changeNotes.getChangeId(), robotCommentAdditionOp);
     212           3 :         batchUpdate.execute();
     213             :       }
     214           3 :       return robotCommentAdditionOp.createdRobotCommentUuid;
     215             :     }
     216             :   }
     217             : 
     218             :   private class RobotCommentAdditionOp implements BatchUpdateOp {
     219             :     private String createdRobotCommentUuid;
     220             :     private final TestRobotCommentCreation robotCommentCreation;
     221             : 
     222           3 :     public RobotCommentAdditionOp(TestRobotCommentCreation robotCommentCreation) {
     223           3 :       this.robotCommentCreation = robotCommentCreation;
     224           3 :     }
     225             : 
     226             :     @Override
     227             :     public boolean updateChange(ChangeContext context) {
     228           3 :       RobotComment robotComment = toNewRobotComment(context, robotCommentCreation);
     229           3 :       ChangeUpdate changeUpdate = context.getUpdate(patchsetId);
     230           3 :       changeUpdate.putRobotComment(robotComment);
     231             :       // For robot comments, only the tag set on the ChangeUpdate (and not on the RobotComment)
     232             :       // matters.
     233           3 :       robotCommentCreation.tag().ifPresent(changeUpdate::setTag);
     234           3 :       createdRobotCommentUuid = robotComment.key.uuid;
     235           3 :       return true;
     236             :     }
     237             : 
     238             :     private RobotComment toNewRobotComment(
     239             :         ChangeContext context, TestRobotCommentCreation robotCommentCreation) {
     240           3 :       String message = robotCommentCreation.message().orElse("The text of a test robot comment.");
     241             : 
     242           3 :       String filePath = robotCommentCreation.file().orElse(Patch.PATCHSET_LEVEL);
     243           3 :       short side = robotCommentCreation.side().orElse(CommentSide.PATCHSET_COMMIT).getNumericSide();
     244           3 :       String robotId = robotCommentCreation.robotId().orElse("robot");
     245           3 :       String robotRunId = robotCommentCreation.robotId().orElse("1");
     246           3 :       RobotComment newRobotComment =
     247           3 :           commentsUtil.newRobotComment(
     248             :               context, filePath, patchsetId, side, message, robotId, robotRunId);
     249             : 
     250             :       // TODO(paiking): This should not be needed, as the tag only matters in ChangeUpdate.
     251           3 :       robotCommentCreation.tag().ifPresent(tag -> newRobotComment.tag = tag);
     252             : 
     253           3 :       robotCommentCreation.line().ifPresent(line -> newRobotComment.setLineNbrAndRange(line, null));
     254             :       // Specification of range trumps explicit line specification.
     255           3 :       robotCommentCreation
     256           3 :           .range()
     257           3 :           .map(PerPatchsetOperationsImpl::toCommentRange)
     258           3 :           .ifPresent(range -> newRobotComment.setLineNbrAndRange(null, range));
     259             : 
     260           3 :       robotCommentCreation
     261           3 :           .parentUuid()
     262           3 :           .ifPresent(parentUuid -> newRobotComment.parentUuid = parentUuid);
     263           3 :       robotCommentCreation.url().ifPresent(url -> newRobotComment.url = url);
     264           3 :       if (!robotCommentCreation.properties().isEmpty()) {
     265           1 :         newRobotComment.properties = robotCommentCreation.properties();
     266             :       }
     267             : 
     268           3 :       commentsUtil.setCommentCommitId(
     269           3 :           newRobotComment, context.getChange(), changeNotes.getPatchSets().get(patchsetId));
     270           3 :       return newRobotComment;
     271             :     }
     272             :   }
     273             : }

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