LCOV - code coverage report
Current view: top level - server/change - GetRelatedChangesUtil.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 31 34 91.2 %
Date: 2022-11-19 15:00:39 Functions: 8 8 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.server.change;
      16             : 
      17             : import static com.google.common.base.Preconditions.checkArgument;
      18             : import static java.util.stream.Collectors.toSet;
      19             : 
      20             : import com.google.common.annotations.VisibleForTesting;
      21             : import com.google.common.flogger.FluentLogger;
      22             : import com.google.gerrit.entities.PatchSet;
      23             : import com.google.gerrit.index.IndexConfig;
      24             : import com.google.gerrit.server.permissions.PermissionBackendException;
      25             : import com.google.gerrit.server.query.change.ChangeData;
      26             : import com.google.gerrit.server.query.change.InternalChangeQuery;
      27             : import com.google.inject.Inject;
      28             : import com.google.inject.Provider;
      29             : import com.google.inject.Singleton;
      30             : import java.io.IOException;
      31             : import java.util.ArrayList;
      32             : import java.util.Collection;
      33             : import java.util.Collections;
      34             : import java.util.List;
      35             : import java.util.Set;
      36             : 
      37             : /** Utility class that gets the ancestor changes and the descendent changes of a specific change. */
      38             : @Singleton
      39             : public class GetRelatedChangesUtil {
      40         145 :   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
      41             : 
      42             :   private final Provider<InternalChangeQuery> queryProvider;
      43             :   private final RelatedChangesSorter sorter;
      44             :   private final IndexConfig indexConfig;
      45             :   private final ChangeData.Factory changeDataFactory;
      46             : 
      47             :   @Inject
      48             :   GetRelatedChangesUtil(
      49             :       Provider<InternalChangeQuery> queryProvider,
      50             :       RelatedChangesSorter sorter,
      51             :       IndexConfig indexConfig,
      52         145 :       ChangeData.Factory changeDataFactory) {
      53         145 :     this.queryProvider = queryProvider;
      54         145 :     this.sorter = sorter;
      55         145 :     this.indexConfig = indexConfig;
      56         145 :     this.changeDataFactory = changeDataFactory;
      57         145 :   }
      58             : 
      59             :   /**
      60             :    * Gets related changes of a specific change revision.
      61             :    *
      62             :    * @param changeData the change of the inputted revision.
      63             :    * @param basePs the revision that the method checks for related changes.
      64             :    * @return list of related changes, sorted via {@link RelatedChangesSorter}
      65             :    */
      66             :   public List<RelatedChangesSorter.PatchSetData> getRelated(ChangeData changeData, PatchSet basePs)
      67             :       throws IOException, PermissionBackendException {
      68           6 :     Set<String> groups = getAllGroups(changeData.patchSets());
      69           6 :     logger.atFine().log("groups = %s", groups);
      70           6 :     if (groups.isEmpty()) {
      71           0 :       return Collections.emptyList();
      72             :     }
      73             : 
      74           6 :     List<ChangeData> cds =
      75           6 :         InternalChangeQuery.byProjectGroups(
      76           6 :             queryProvider, indexConfig, changeData.project(), groups);
      77           6 :     if (cds.isEmpty()) {
      78           0 :       return Collections.emptyList();
      79             :     }
      80           6 :     if (cds.size() == 1 && cds.get(0).getId().equals(changeData.getId())) {
      81           5 :       return Collections.emptyList();
      82             :     }
      83             : 
      84           5 :     cds = reloadChangeIfStale(cds, changeData, basePs);
      85             : 
      86           5 :     return sorter.sort(cds, basePs);
      87             :   }
      88             : 
      89             :   private List<ChangeData> reloadChangeIfStale(
      90             :       List<ChangeData> changeDatasFromIndex, ChangeData wantedChange, PatchSet wantedPs) {
      91           5 :     checkArgument(
      92           5 :         wantedChange.getId().equals(wantedPs.id().changeId()),
      93             :         "change of wantedPs (%s) doesn't match wantedChange (%s)",
      94           5 :         wantedPs.id().changeId(),
      95           5 :         wantedChange.getId());
      96             : 
      97           5 :     List<ChangeData> changeDatas = new ArrayList<>(changeDatasFromIndex.size() + 1);
      98           5 :     changeDatas.addAll(changeDatasFromIndex);
      99             : 
     100             :     // Reload the change in case the patch set is absent.
     101           5 :     changeDatas.stream()
     102           5 :         .filter(
     103           5 :             cd -> cd.getId().equals(wantedPs.id().changeId()) && cd.patchSet(wantedPs.id()) == null)
     104           5 :         .forEach(ChangeData::reloadChange);
     105             : 
     106           5 :     if (changeDatas.stream().noneMatch(cd -> cd.getId().equals(wantedPs.id().changeId()))) {
     107             :       // The change of the wanted patch set is missing in the result from the index.
     108             :       // Load it from NoteDb and add it to the result.
     109           0 :       changeDatas.add(changeDataFactory.create(wantedChange.change()));
     110             :     }
     111             : 
     112           5 :     return changeDatas;
     113             :   }
     114             : 
     115             :   @VisibleForTesting
     116             :   public static Set<String> getAllGroups(Collection<PatchSet> patchSets) {
     117           6 :     return patchSets.stream().flatMap(ps -> ps.groups().stream()).collect(toSet());
     118             :   }
     119             : }

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