LCOV - code coverage report
Current view: top level - server/change - LabelNormalizer.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 44 45 97.8 %
Date: 2022-11-19 15:00:39 Functions: 6 6 100.0 %

          Line data    Source code
       1             : // Copyright (C) 2013 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 com.google.common.collect.ImmutableSet.toImmutableSet;
      19             : import static com.google.gerrit.server.project.ProjectCache.illegalState;
      20             : 
      21             : import com.google.auto.value.AutoValue;
      22             : import com.google.common.annotations.VisibleForTesting;
      23             : import com.google.common.collect.ImmutableSet;
      24             : import com.google.common.collect.Streams;
      25             : import com.google.gerrit.entities.Change;
      26             : import com.google.gerrit.entities.LabelType;
      27             : import com.google.gerrit.entities.LabelTypes;
      28             : import com.google.gerrit.entities.LabelValue;
      29             : import com.google.gerrit.entities.PatchSetApproval;
      30             : import com.google.gerrit.server.notedb.ChangeNotes;
      31             : import com.google.gerrit.server.project.ProjectCache;
      32             : import com.google.inject.Inject;
      33             : import com.google.inject.Singleton;
      34             : import java.util.Collection;
      35             : import java.util.HashSet;
      36             : import java.util.Optional;
      37             : import java.util.Set;
      38             : 
      39             : /**
      40             :  * Normalizes votes on labels according to project config.
      41             :  *
      42             :  * <p>Votes are recorded in the database for a user based on the state of the project at that time:
      43             :  * what labels are defined for the project. The label definition can change between the time a vote
      44             :  * is originally made and a later point, for example when a change is submitted. This class
      45             :  * normalizes old votes against current project configuration.
      46             :  */
      47             : @Singleton
      48             : public class LabelNormalizer {
      49             :   @AutoValue
      50         103 :   public abstract static class Result {
      51             :     @VisibleForTesting
      52             :     static Result create(
      53             :         Set<PatchSetApproval> unchanged,
      54             :         Set<PatchSetApproval> updated,
      55             :         Set<PatchSetApproval> deleted) {
      56         103 :       return new AutoValue_LabelNormalizer_Result(
      57         103 :           ImmutableSet.copyOf(unchanged),
      58         103 :           ImmutableSet.copyOf(updated),
      59         103 :           ImmutableSet.copyOf(deleted));
      60             :     }
      61             : 
      62             :     public abstract ImmutableSet<PatchSetApproval> unchanged();
      63             : 
      64             :     public abstract ImmutableSet<PatchSetApproval> updated();
      65             : 
      66             :     public abstract ImmutableSet<PatchSetApproval> deleted();
      67             : 
      68             :     public ImmutableSet<PatchSetApproval> getNormalized() {
      69         103 :       return Streams.concat(unchanged().stream(), updated().stream())
      70         103 :           .distinct()
      71         103 :           .collect(toImmutableSet());
      72             :     }
      73             :   }
      74             : 
      75             :   private final ProjectCache projectCache;
      76             : 
      77             :   @Inject
      78         146 :   LabelNormalizer(ProjectCache projectCache) {
      79         146 :     this.projectCache = projectCache;
      80         146 :   }
      81             : 
      82             :   /**
      83             :    * Returns copies of approvals normalized to the defined ranges for the label type. Approvals for
      84             :    * unknown labels are not included in the output
      85             :    *
      86             :    * @param notes change notes containing the given approvals.
      87             :    * @param approvals list of approvals.
      88             :    */
      89             :   public Result normalize(ChangeNotes notes, Collection<PatchSetApproval> approvals) {
      90         103 :     Set<PatchSetApproval> unchanged = new HashSet<>(approvals.size());
      91         103 :     Set<PatchSetApproval> updated = new HashSet<>(approvals.size());
      92         103 :     Set<PatchSetApproval> deleted = new HashSet<>(approvals.size());
      93         103 :     LabelTypes labelTypes =
      94             :         projectCache
      95         103 :             .get(notes.getProjectName())
      96         103 :             .orElseThrow(illegalState(notes.getProjectName()))
      97         103 :             .getLabelTypes(notes);
      98         103 :     for (PatchSetApproval psa : approvals) {
      99          68 :       Change.Id changeId = psa.key().patchSetId().changeId();
     100          68 :       checkArgument(
     101          68 :           changeId.equals(notes.getChangeId()),
     102             :           "Approval %s does not match change %s",
     103          68 :           psa.key(),
     104          68 :           notes.getChange().getKey());
     105          68 :       if (psa.isLegacySubmit()) {
     106          55 :         unchanged.add(psa);
     107          55 :         continue;
     108             :       }
     109          59 :       Optional<LabelType> label = labelTypes.byLabel(psa.labelId());
     110          59 :       if (!label.isPresent()) {
     111           4 :         deleted.add(psa);
     112           4 :         continue;
     113             :       }
     114          59 :       PatchSetApproval copy = applyTypeFloor(label.get(), psa);
     115          59 :       if (copy.value() != psa.value()) {
     116           1 :         updated.add(copy);
     117             :       } else {
     118          59 :         unchanged.add(psa);
     119             :       }
     120          59 :     }
     121         103 :     return Result.create(unchanged, updated, deleted);
     122             :   }
     123             : 
     124             :   private PatchSetApproval applyTypeFloor(LabelType lt, PatchSetApproval a) {
     125          59 :     PatchSetApproval.Builder b = a.toBuilder();
     126          59 :     LabelValue atMin = lt.getMin();
     127          59 :     if (atMin != null && a.value() < atMin.getValue()) {
     128           0 :       b.value(atMin.getValue());
     129             :     }
     130          59 :     LabelValue atMax = lt.getMax();
     131          59 :     if (atMax != null && a.value() > atMax.getValue()) {
     132           1 :       b.value(atMax.getValue());
     133             :     }
     134          59 :     return b.build();
     135             :   }
     136             : }

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