LCOV - code coverage report
Current view: top level - acceptance - AbstractNotificationTest.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 223 275 81.1 %
Date: 2022-11-19 15:00:39 Functions: 53 60 88.3 %

          Line data    Source code
       1             : // Copyright (C) 2017 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;
      16             : 
      17             : import static com.google.common.truth.Fact.fact;
      18             : import static com.google.common.truth.Truth.assertAbout;
      19             : import static com.google.gerrit.extensions.api.changes.RecipientType.BCC;
      20             : import static com.google.gerrit.extensions.api.changes.RecipientType.CC;
      21             : import static com.google.gerrit.extensions.api.changes.RecipientType.TO;
      22             : import static java.util.stream.Collectors.toList;
      23             : 
      24             : import com.google.common.base.Joiner;
      25             : import com.google.common.collect.ImmutableList;
      26             : import com.google.common.truth.FailureMetadata;
      27             : import com.google.common.truth.Subject;
      28             : import com.google.common.truth.Truth;
      29             : import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
      30             : import com.google.gerrit.common.Nullable;
      31             : import com.google.gerrit.entities.Address;
      32             : import com.google.gerrit.entities.EmailHeader;
      33             : import com.google.gerrit.entities.EmailHeader.AddressList;
      34             : import com.google.gerrit.entities.EmailHeader.StringEmailHeader;
      35             : import com.google.gerrit.entities.NotifyConfig.NotifyType;
      36             : import com.google.gerrit.extensions.api.changes.RecipientType;
      37             : import com.google.gerrit.extensions.api.changes.ReviewInput;
      38             : import com.google.gerrit.extensions.api.changes.ReviewResult;
      39             : import com.google.gerrit.extensions.api.projects.ConfigInput;
      40             : import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
      41             : import com.google.gerrit.extensions.client.GeneralPreferencesInfo.EmailStrategy;
      42             : import com.google.gerrit.extensions.client.InheritableBoolean;
      43             : import com.google.gerrit.extensions.client.ReviewerState;
      44             : import com.google.gerrit.testing.FakeEmailSender;
      45             : import com.google.gerrit.testing.FakeEmailSender.Message;
      46             : import com.google.inject.Inject;
      47             : import java.util.ArrayList;
      48             : import java.util.HashMap;
      49             : import java.util.HashSet;
      50             : import java.util.List;
      51             : import java.util.Map;
      52             : import java.util.Set;
      53             : import java.util.function.Function;
      54             : import org.eclipse.jgit.junit.TestRepository;
      55             : import org.junit.After;
      56             : import org.junit.Before;
      57             : 
      58           1 : public abstract class AbstractNotificationTest extends AbstractDaemonTest {
      59             :   @Inject private RequestScopeOperations requestScopeOperations;
      60             : 
      61             :   @Before
      62             :   public void enableReviewerByEmail() throws Exception {
      63           1 :     requestScopeOperations.setApiUser(admin.id());
      64           1 :     ConfigInput conf = new ConfigInput();
      65           1 :     conf.enableReviewerByEmail = InheritableBoolean.TRUE;
      66           1 :     gApi.projects().name(project.get()).config(conf);
      67           1 :   }
      68             : 
      69             :   @Override
      70             :   protected ProjectResetter.Config resetProjects() {
      71             :     // Don't reset anything so that stagedUsers can be cached across all tests.
      72             :     // Without this caching these tests become much too slow.
      73           1 :     return new ProjectResetter.Config();
      74             :   }
      75             : 
      76             :   protected static FakeEmailSenderSubject assertThat(FakeEmailSender sender) {
      77           1 :     return assertAbout(fakeEmailSenders()).that(sender);
      78             :   }
      79             : 
      80             :   protected static Subject.Factory<FakeEmailSenderSubject, FakeEmailSender> fakeEmailSenders() {
      81           1 :     return FakeEmailSenderSubject::new;
      82             :   }
      83             : 
      84             :   protected void setEmailStrategy(TestAccount account, EmailStrategy strategy) throws Exception {
      85           1 :     setEmailStrategy(account, strategy, true);
      86           1 :   }
      87             : 
      88             :   protected void setEmailStrategy(TestAccount account, EmailStrategy strategy, boolean record)
      89             :       throws Exception {
      90           1 :     if (record) {
      91           1 :       accountsModifyingEmailStrategy.add(account);
      92             :     }
      93           1 :     requestScopeOperations.setApiUser(account.id());
      94           1 :     GeneralPreferencesInfo prefs = gApi.accounts().self().getPreferences();
      95           1 :     prefs.emailStrategy = strategy;
      96           1 :     gApi.accounts().self().setPreferences(prefs);
      97           1 :   }
      98             : 
      99             :   protected static class FakeEmailSenderSubject extends Subject {
     100             :     private final FakeEmailSender fakeEmailSender;
     101             :     private String emailTitle;
     102             :     private Message message;
     103             :     private StagedUsers users;
     104           1 :     private Map<RecipientType, List<String>> recipients = new HashMap<>();
     105           1 :     private Set<String> accountedFor = new HashSet<>();
     106             : 
     107             :     FakeEmailSenderSubject(FailureMetadata failureMetadata, FakeEmailSender target) {
     108           1 :       super(failureMetadata, target);
     109           1 :       fakeEmailSender = target;
     110           1 :     }
     111             : 
     112             :     public FakeEmailSenderSubject didNotSend() {
     113           1 :       Message message = fakeEmailSender.peekMessage();
     114           1 :       if (message != null) {
     115           0 :         failWithoutActual(fact("expected no message", message));
     116             :       }
     117           1 :       return this;
     118             :     }
     119             : 
     120             :     public FakeEmailSenderSubject sent(String messageType, StagedUsers users) {
     121           1 :       message = fakeEmailSender.nextMessage();
     122           1 :       if (message == null) {
     123           0 :         failWithoutActual(fact("expected message", "not sent"));
     124             :       }
     125           1 :       recipients = new HashMap<>();
     126           1 :       recipients.put(TO, parseAddresses(message, "To"));
     127           1 :       recipients.put(CC, parseAddresses(message, "Cc"));
     128           1 :       recipients.put(
     129             :           BCC,
     130           1 :           message.rcpt().stream()
     131           1 :               .map(Address::email)
     132           1 :               .filter(e -> !recipients.get(TO).contains(e) && !recipients.get(CC).contains(e))
     133           1 :               .collect(toList()));
     134           1 :       this.users = users;
     135           1 :       if (!message.headers().containsKey("X-Gerrit-MessageType")) {
     136           0 :         failWithoutActual(
     137           0 :             fact("expected to have message sent with", "X-Gerrit-MessageType header"));
     138             :       }
     139           1 :       EmailHeader header = message.headers().get("X-Gerrit-MessageType");
     140           1 :       if (!header.equals(new StringEmailHeader(messageType))) {
     141           0 :         failWithoutActual(
     142           0 :             fact("expected message of type", messageType),
     143           0 :             fact(
     144             :                 "actual",
     145           0 :                 header instanceof StringEmailHeader
     146           0 :                     ? ((StringEmailHeader) header).getString()
     147           0 :                     : header));
     148             :       }
     149           1 :       EmailHeader titleHeader = message.headers().get("Subject");
     150           1 :       if (titleHeader instanceof StringEmailHeader) {
     151           1 :         emailTitle = ((StringEmailHeader) titleHeader).getString();
     152             :       }
     153             : 
     154           1 :       return this;
     155             :     }
     156             : 
     157             :     private static String recipientMapToString(
     158             :         Map<RecipientType, List<String>> recipients, Function<String, String> emailToName) {
     159           0 :       StringBuilder buf = new StringBuilder();
     160           0 :       buf.append('[');
     161           0 :       for (RecipientType type : ImmutableList.of(TO, CC, BCC)) {
     162           0 :         buf.append('\n');
     163           0 :         buf.append(type);
     164           0 :         buf.append(':');
     165           0 :         String delim = " ";
     166           0 :         for (String r : recipients.get(type)) {
     167           0 :           buf.append(delim);
     168           0 :           buf.append(emailToName.apply(r));
     169           0 :           delim = ", ";
     170           0 :         }
     171           0 :       }
     172           0 :       buf.append("\n]");
     173           0 :       return buf.toString();
     174             :     }
     175             : 
     176             :     List<String> parseAddresses(Message msg, String headerName) {
     177           1 :       EmailHeader header = msg.headers().get(headerName);
     178           1 :       if (header == null) {
     179           0 :         return ImmutableList.of();
     180             :       }
     181           1 :       Truth.assertThat(header).isInstanceOf(AddressList.class);
     182           1 :       AddressList addrList = (AddressList) header;
     183           1 :       return addrList.getAddressList().stream().map(Address::email).collect(toList());
     184             :     }
     185             : 
     186             :     public FakeEmailSenderSubject to(String... emails) {
     187           1 :       return rcpt(users.supportReviewersByEmail ? TO : null, emails);
     188             :     }
     189             : 
     190             :     public FakeEmailSenderSubject cc(String... emails) {
     191           1 :       return rcpt(users.supportReviewersByEmail ? CC : null, emails);
     192             :     }
     193             : 
     194             :     public FakeEmailSenderSubject bcc(String... emails) {
     195           0 :       return rcpt(users.supportReviewersByEmail ? BCC : null, emails);
     196             :     }
     197             : 
     198             :     public FakeEmailSenderSubject title(String expectedEmailTitle) {
     199           1 :       if (!emailTitle.equals(expectedEmailTitle)) {
     200           0 :         failWithoutActual(
     201           0 :             fact("Expected email title", expectedEmailTitle),
     202           0 :             fact("but actual title is", emailTitle));
     203             :       }
     204           1 :       return this;
     205             :     }
     206             : 
     207             :     private FakeEmailSenderSubject rcpt(@Nullable RecipientType type, String[] emails) {
     208           1 :       for (String email : emails) {
     209           1 :         rcpt(type, email);
     210             :       }
     211           1 :       return this;
     212             :     }
     213             : 
     214             :     private void rcpt(@Nullable RecipientType type, String email) {
     215           1 :       rcpt(TO, email, TO.equals(type));
     216           1 :       rcpt(CC, email, CC.equals(type));
     217           1 :       rcpt(BCC, email, BCC.equals(type));
     218           1 :     }
     219             : 
     220             :     private void rcpt(@Nullable RecipientType type, String email, boolean expected) {
     221           1 :       if (recipients.get(type).contains(email) != expected) {
     222           0 :         failWithoutActual(
     223           0 :             fact(
     224           0 :                 expected ? "expected to notify" : "expected not to notify",
     225           0 :                 type + ": " + users.emailToName(email)),
     226           0 :             fact("but notified", recipientMapToString(recipients, users::emailToName)));
     227             :       }
     228           1 :       if (expected) {
     229           1 :         accountedFor.add(email);
     230             :       }
     231           1 :     }
     232             : 
     233             :     public FakeEmailSenderSubject noOneElse() {
     234           1 :       for (Map.Entry<NotifyType, TestAccount> watchEntry : users.watchers.entrySet()) {
     235           1 :         if (!accountedFor.contains(watchEntry.getValue().email())) {
     236           1 :           notTo(watchEntry.getKey());
     237             :         }
     238           1 :       }
     239             : 
     240           1 :       Map<RecipientType, List<String>> unaccountedFor = new HashMap<>();
     241           1 :       boolean ok = true;
     242           1 :       for (Map.Entry<RecipientType, List<String>> entry : recipients.entrySet()) {
     243           1 :         unaccountedFor.put(entry.getKey(), new ArrayList<>());
     244           1 :         for (String address : entry.getValue()) {
     245           1 :           if (!accountedFor.contains(address)) {
     246           0 :             unaccountedFor.get(entry.getKey()).add(address);
     247           0 :             ok = false;
     248             :           }
     249           1 :         }
     250           1 :       }
     251           1 :       if (!ok) {
     252           0 :         failWithoutActual(
     253           0 :             fact(
     254             :                 "expected assertions for",
     255           0 :                 recipientMapToString(unaccountedFor, e -> users.emailToName(e))));
     256             :       }
     257           1 :       return this;
     258             :     }
     259             : 
     260             :     public FakeEmailSenderSubject notTo(String... emails) {
     261           0 :       return rcpt(null, emails);
     262             :     }
     263             : 
     264             :     public FakeEmailSenderSubject to(TestAccount... accounts) {
     265           1 :       return rcpt(TO, accounts);
     266             :     }
     267             : 
     268             :     public FakeEmailSenderSubject cc(TestAccount... accounts) {
     269           1 :       return rcpt(CC, accounts);
     270             :     }
     271             : 
     272             :     public FakeEmailSenderSubject bcc(TestAccount... accounts) {
     273           1 :       return rcpt(BCC, accounts);
     274             :     }
     275             : 
     276             :     public FakeEmailSenderSubject notTo(TestAccount... accounts) {
     277           1 :       return rcpt(null, accounts);
     278             :     }
     279             : 
     280             :     private FakeEmailSenderSubject rcpt(@Nullable RecipientType type, TestAccount[] accounts) {
     281           1 :       for (TestAccount account : accounts) {
     282           1 :         rcpt(type, account);
     283             :       }
     284           1 :       return this;
     285             :     }
     286             : 
     287             :     private void rcpt(@Nullable RecipientType type, TestAccount account) {
     288           1 :       rcpt(type, account.email());
     289           1 :     }
     290             : 
     291             :     public FakeEmailSenderSubject to(NotifyType... watches) {
     292           0 :       return rcpt(TO, watches);
     293             :     }
     294             : 
     295             :     public FakeEmailSenderSubject cc(NotifyType... watches) {
     296           0 :       return rcpt(CC, watches);
     297             :     }
     298             : 
     299             :     public FakeEmailSenderSubject bcc(NotifyType... watches) {
     300           1 :       return rcpt(BCC, watches);
     301             :     }
     302             : 
     303             :     public FakeEmailSenderSubject notTo(NotifyType... watches) {
     304           1 :       return rcpt(null, watches);
     305             :     }
     306             : 
     307             :     private FakeEmailSenderSubject rcpt(@Nullable RecipientType type, NotifyType[] watches) {
     308           1 :       for (NotifyType watch : watches) {
     309           1 :         rcpt(type, watch);
     310             :       }
     311           1 :       return this;
     312             :     }
     313             : 
     314             :     private void rcpt(@Nullable RecipientType type, NotifyType watch) {
     315           1 :       if (!users.watchers.containsKey(watch)) {
     316           0 :         failWithoutActual(fact("expected to be configured to watch", watch));
     317             :       }
     318           1 :       rcpt(type, users.watchers.get(watch));
     319           1 :     }
     320             :   }
     321             : 
     322           1 :   private static final Map<String, StagedUsers> stagedUsers = new HashMap<>();
     323             : 
     324             :   // TestAccount doesn't implement hashCode/equals, so this set is according
     325             :   // to object identity. That's fine for our purposes.
     326           1 :   private Set<TestAccount> accountsModifyingEmailStrategy = new HashSet<>();
     327             : 
     328             :   @After
     329             :   public void resetEmailStrategies() throws Exception {
     330           1 :     for (TestAccount account : accountsModifyingEmailStrategy) {
     331           1 :       setEmailStrategy(account, EmailStrategy.ENABLED, false);
     332           1 :     }
     333           1 :     accountsModifyingEmailStrategy.clear();
     334           1 :   }
     335             : 
     336             :   protected class StagedUsers {
     337             :     public static final String REVIEWER_BY_EMAIL = "reviewerByEmail@example.com";
     338             :     public static final String CC_BY_EMAIL = "ccByEmail@example.com";
     339             : 
     340             :     public final TestAccount owner;
     341             :     public final TestAccount author;
     342             :     public final TestAccount uploader;
     343             :     public final TestAccount reviewer;
     344             :     public final TestAccount ccer;
     345             :     public final TestAccount starrer;
     346             :     public final TestAccount assignee;
     347             :     public final TestAccount watchingProjectOwner;
     348           1 :     private final Map<NotifyType, TestAccount> watchers = new HashMap<>();
     349           1 :     private final Map<String, TestAccount> accountsByEmail = new HashMap<>();
     350             : 
     351             :     public boolean supportReviewersByEmail;
     352             : 
     353             :     private String usersCacheKey() {
     354           1 :       return description.getClassName();
     355             :     }
     356             : 
     357             :     private TestAccount reindexAndCopy(TestAccount account) {
     358           1 :       reindexAccount(account.id());
     359           1 :       return account;
     360             :     }
     361             : 
     362           1 :     public StagedUsers() throws Exception {
     363           1 :       synchronized (stagedUsers) {
     364           1 :         if (stagedUsers.containsKey(usersCacheKey())) {
     365           1 :           StagedUsers existing = stagedUsers.get(usersCacheKey());
     366           1 :           owner = reindexAndCopy(existing.owner);
     367           1 :           author = reindexAndCopy(existing.author);
     368           1 :           uploader = reindexAndCopy(existing.uploader);
     369           1 :           reviewer = reindexAndCopy(existing.reviewer);
     370           1 :           ccer = reindexAndCopy(existing.ccer);
     371           1 :           starrer = reindexAndCopy(existing.starrer);
     372           1 :           assignee = reindexAndCopy(existing.assignee);
     373           1 :           watchingProjectOwner = reindexAndCopy(existing.watchingProjectOwner);
     374           1 :           watchers.putAll(existing.watchers);
     375           1 :           return;
     376             :         }
     377             : 
     378           1 :         owner = testAccount("owner");
     379           1 :         reviewer = testAccount("reviewer");
     380           1 :         author = testAccount("author");
     381           1 :         uploader = testAccount("uploader");
     382           1 :         ccer = testAccount("ccer");
     383           1 :         starrer = testAccount("starrer");
     384           1 :         assignee = testAccount("assignee");
     385             : 
     386           1 :         watchingProjectOwner = testAccount("watchingProjectOwner", "Administrators");
     387           1 :         requestScopeOperations.setApiUser(watchingProjectOwner.id());
     388           1 :         watch(allProjects.get(), pwi -> pwi.notifyNewChanges = true);
     389             : 
     390           1 :         for (NotifyType watch : NotifyType.values()) {
     391           1 :           if (watch == NotifyType.ALL) {
     392           1 :             continue;
     393             :           }
     394           1 :           TestAccount watcher = testAccount(watch.toString());
     395           1 :           requestScopeOperations.setApiUser(watcher.id());
     396           1 :           watch(
     397           1 :               allProjects.get(),
     398             :               pwi -> {
     399           1 :                 pwi.notifyAllComments = watch.equals(NotifyType.ALL_COMMENTS);
     400           1 :                 pwi.notifyAbandonedChanges = watch.equals(NotifyType.ABANDONED_CHANGES);
     401           1 :                 pwi.notifyNewChanges = watch.equals(NotifyType.NEW_CHANGES);
     402           1 :                 pwi.notifyNewPatchSets = watch.equals(NotifyType.NEW_PATCHSETS);
     403           1 :                 pwi.notifySubmittedChanges = watch.equals(NotifyType.SUBMITTED_CHANGES);
     404           1 :               });
     405           1 :           watchers.put(watch, watcher);
     406             :         }
     407             : 
     408           1 :         stagedUsers.put(usersCacheKey(), this);
     409           1 :       }
     410           1 :     }
     411             : 
     412             :     private String email(String username) {
     413             :       // Email validator rejects usernames longer than 64 bytes.
     414           1 :       if (username.length() > 64) {
     415           1 :         username = username.substring(username.length() - 64);
     416           1 :         if (username.startsWith(".")) {
     417           1 :           username = username.substring(1);
     418             :         }
     419             :       }
     420           1 :       return username + "@example.com";
     421             :     }
     422             : 
     423             :     public TestAccount testAccount(String name) throws Exception {
     424           1 :       String username = name(name);
     425           1 :       TestAccount account = accountCreator.create(username, email(username), name, null);
     426           1 :       accountsByEmail.put(account.email(), account);
     427           1 :       return account;
     428             :     }
     429             : 
     430             :     public TestAccount testAccount(String name, String groupName) throws Exception {
     431           1 :       String username = name(name);
     432           1 :       TestAccount account = accountCreator.create(username, email(username), name, null, groupName);
     433           1 :       accountsByEmail.put(account.email(), account);
     434           1 :       return account;
     435             :     }
     436             : 
     437             :     String emailToName(String email) {
     438           0 :       if (accountsByEmail.containsKey(email)) {
     439           0 :         return accountsByEmail.get(email).fullName();
     440             :       }
     441           0 :       return email;
     442             :     }
     443             : 
     444             :     protected void addReviewers(PushOneCommit.Result r) throws Exception {
     445             :       ReviewInput in =
     446           1 :           ReviewInput.noScore()
     447           1 :               .reviewer(reviewer.email())
     448           1 :               .reviewer(REVIEWER_BY_EMAIL)
     449           1 :               .reviewer(ccer.email(), ReviewerState.CC, false)
     450           1 :               .reviewer(CC_BY_EMAIL, ReviewerState.CC, false);
     451           1 :       ReviewResult result = gApi.changes().id(r.getChangeId()).current().review(in);
     452           1 :       supportReviewersByEmail = true;
     453           1 :       if (result.reviewers.values().stream().anyMatch(v -> v.error != null)) {
     454           0 :         supportReviewersByEmail = false;
     455             :         in =
     456           0 :             ReviewInput.noScore()
     457           0 :                 .reviewer(reviewer.email())
     458           0 :                 .reviewer(ccer.email(), ReviewerState.CC, false);
     459           0 :         result = gApi.changes().id(r.getChangeId()).current().review(in);
     460             :       }
     461           1 :       Truth.assertThat(result.reviewers.values().stream().allMatch(v -> v.error == null)).isTrue();
     462           1 :     }
     463             :   }
     464             : 
     465             :   protected interface PushOptionGenerator {
     466             :     List<String> pushOptions(StagedUsers users);
     467             :   }
     468             : 
     469             :   protected class StagedPreChange extends StagedUsers {
     470             :     public final TestRepository<?> repo;
     471             :     protected final PushOneCommit.Result result;
     472             :     public final String changeId;
     473             : 
     474             :     StagedPreChange(String ref) throws Exception {
     475           1 :       this(ref, null);
     476           1 :     }
     477             : 
     478             :     StagedPreChange(String ref, @Nullable PushOptionGenerator pushOptionGenerator)
     479           1 :         throws Exception {
     480           1 :       super();
     481           1 :       List<String> pushOptions = null;
     482           1 :       if (pushOptionGenerator != null) {
     483           1 :         pushOptions = pushOptionGenerator.pushOptions(this);
     484             :       }
     485           1 :       if (pushOptions != null) {
     486           1 :         ref = ref + '%' + Joiner.on(',').join(pushOptions);
     487             :       }
     488           1 :       requestScopeOperations.setApiUser(owner.id());
     489           1 :       repo = cloneProject(project, owner);
     490           1 :       PushOneCommit push = pushFactory.create(owner.newIdent(), repo);
     491           1 :       result = push.to(ref);
     492           1 :       result.assertOkStatus();
     493           1 :       changeId = result.getChangeId();
     494           1 :     }
     495             :   }
     496             : 
     497             :   protected StagedPreChange stagePreChange(String ref) throws Exception {
     498           1 :     return new StagedPreChange(ref);
     499             :   }
     500             : 
     501             :   protected StagedPreChange stagePreChange(
     502             :       String ref, @Nullable PushOptionGenerator pushOptionGenerator) throws Exception {
     503           1 :     return new StagedPreChange(ref, pushOptionGenerator);
     504             :   }
     505             : 
     506             :   protected class StagedChange extends StagedPreChange {
     507           1 :     StagedChange(String ref) throws Exception {
     508           1 :       super(ref);
     509             : 
     510           1 :       requestScopeOperations.setApiUser(starrer.id());
     511           1 :       gApi.accounts().self().starChange(result.getChangeId());
     512             : 
     513           1 :       requestScopeOperations.setApiUser(owner.id());
     514           1 :       addReviewers(result);
     515           1 :       sender.clear();
     516           1 :     }
     517             :   }
     518             : 
     519             :   protected StagedChange stageReviewableChange() throws Exception {
     520           1 :     StagedChange sc = new StagedChange("refs/for/master");
     521           1 :     sender.clear();
     522           1 :     return sc;
     523             :   }
     524             : 
     525             :   protected StagedChange stageWipChange() throws Exception {
     526           1 :     StagedChange sc = new StagedChange("refs/for/master%wip");
     527           1 :     sender.clear();
     528           1 :     return sc;
     529             :   }
     530             : 
     531             :   protected StagedChange stageReviewableWipChange() throws Exception {
     532           1 :     StagedChange sc = stageReviewableChange();
     533           1 :     requestScopeOperations.setApiUser(sc.owner.id());
     534           1 :     gApi.changes().id(sc.changeId).setWorkInProgress();
     535           1 :     sender.clear();
     536           1 :     return sc;
     537             :   }
     538             : 
     539             :   protected StagedChange stageAbandonedReviewableChange() throws Exception {
     540           1 :     StagedChange sc = stageReviewableChange();
     541           1 :     requestScopeOperations.setApiUser(sc.owner.id());
     542           1 :     gApi.changes().id(sc.changeId).abandon();
     543           1 :     sender.clear();
     544           1 :     return sc;
     545             :   }
     546             : 
     547             :   protected StagedChange stageAbandonedReviewableWipChange() throws Exception {
     548           1 :     StagedChange sc = stageReviewableWipChange();
     549           1 :     requestScopeOperations.setApiUser(sc.owner.id());
     550           1 :     gApi.changes().id(sc.changeId).abandon();
     551           1 :     sender.clear();
     552           1 :     return sc;
     553             :   }
     554             : 
     555             :   protected StagedChange stageAbandonedWipChange() throws Exception {
     556           1 :     StagedChange sc = stageWipChange();
     557           1 :     requestScopeOperations.setApiUser(sc.owner.id());
     558           1 :     gApi.changes().id(sc.changeId).abandon();
     559           1 :     sender.clear();
     560           1 :     return sc;
     561             :   }
     562             : }

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