LCOV - code coverage report
Current view: top level - acceptance - GitUtil.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 59 62 95.2 %
Date: 2022-11-19 15:00:39 Functions: 16 18 88.9 %

          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.acceptance;
      16             : 
      17             : import static com.google.common.truth.Truth.assertThat;
      18             : import static com.google.common.truth.Truth.assertWithMessage;
      19             : 
      20             : import com.google.common.collect.Iterables;
      21             : import com.google.common.collect.Lists;
      22             : import com.google.common.primitives.Ints;
      23             : import com.google.gerrit.common.FooterConstants;
      24             : import com.google.gerrit.entities.Project;
      25             : import java.io.IOException;
      26             : import java.util.List;
      27             : import java.util.Optional;
      28             : import java.util.concurrent.TimeUnit;
      29             : import java.util.concurrent.atomic.AtomicInteger;
      30             : import org.eclipse.jgit.api.FetchCommand;
      31             : import org.eclipse.jgit.api.PushCommand;
      32             : import org.eclipse.jgit.api.TagCommand;
      33             : import org.eclipse.jgit.api.errors.GitAPIException;
      34             : import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
      35             : import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
      36             : import org.eclipse.jgit.junit.TestRepository;
      37             : import org.eclipse.jgit.lib.Config;
      38             : import org.eclipse.jgit.lib.ObjectId;
      39             : import org.eclipse.jgit.lib.PersonIdent;
      40             : import org.eclipse.jgit.lib.Ref;
      41             : import org.eclipse.jgit.lib.Repository;
      42             : import org.eclipse.jgit.revwalk.RevCommit;
      43             : import org.eclipse.jgit.transport.FetchResult;
      44             : import org.eclipse.jgit.transport.PushResult;
      45             : import org.eclipse.jgit.transport.RefSpec;
      46             : import org.eclipse.jgit.transport.RemoteRefUpdate;
      47             : import org.eclipse.jgit.util.FS;
      48             : 
      49           0 : public class GitUtil {
      50         132 :   private static final AtomicInteger testRepoCount = new AtomicInteger();
      51             :   private static final int TEST_REPO_WINDOW_DAYS = 2;
      52             : 
      53             :   /**
      54             :    * Create a new {@link TestRepository} with a distinct commit clock.
      55             :    *
      56             :    * <p>It is very easy for tests to create commits with identical subjects and trees; if such
      57             :    * commits also have identical authors/committers, then the computed Change-Id is identical as
      58             :    * well. Tests may generally assume that Change-Ids are unique, so to ensure this, we provision
      59             :    * TestRepository instances with non-overlapping commit clock times.
      60             :    *
      61             :    * <p>Space test repos 1 day apart, which allows for about 86k ticks per repo before overlapping,
      62             :    * and about 8k instances per process before hitting JGit's year 2038 limit.
      63             :    *
      64             :    * @param repo repository to wrap.
      65             :    * @return wrapped test repository with distinct commit time space.
      66             :    */
      67             :   public static <R extends Repository> TestRepository<R> newTestRepository(R repo)
      68             :       throws IOException {
      69         132 :     TestRepository<R> tr = new TestRepository<>(repo);
      70         132 :     tr.tick(
      71         132 :         Ints.checkedCast(
      72         132 :             TimeUnit.SECONDS.convert(
      73         132 :                 testRepoCount.getAndIncrement() * TEST_REPO_WINDOW_DAYS, TimeUnit.DAYS)));
      74         132 :     return tr;
      75             :   }
      76             : 
      77             :   public static TestRepository<InMemoryRepository> cloneProject(Project.NameKey project, String uri)
      78             :       throws Exception {
      79         132 :     DfsRepositoryDescription desc = new DfsRepositoryDescription("clone of " + project.get());
      80             : 
      81         132 :     InMemoryRepository.Builder b = new InMemoryRepository.Builder().setRepositoryDescription(desc);
      82         132 :     if (uri.startsWith("ssh://")) {
      83             :       // SshTransport depends on a real FS to read ~/.ssh/config, but InMemoryRepository by default
      84             :       // uses a null FS.
      85             :       // Avoid leaking user state into our tests.
      86           2 :       b.setFS(FS.detect().setUserHome(null));
      87             :     }
      88         132 :     InMemoryRepository dest = b.build();
      89         132 :     Config cfg = dest.getConfig();
      90         132 :     cfg.setString("remote", "origin", "url", uri);
      91         132 :     cfg.setString("remote", "origin", "fetch", "+refs/heads/*:refs/remotes/origin/*");
      92         132 :     TestRepository<InMemoryRepository> testRepo = newTestRepository(dest);
      93         132 :     FetchResult result = testRepo.git().fetch().setRemote("origin").call();
      94         132 :     String originMaster = "refs/remotes/origin/master";
      95         132 :     if (result.getTrackingRefUpdate(originMaster) != null) {
      96         132 :       testRepo.reset(originMaster);
      97             :     }
      98         132 :     return testRepo;
      99             :   }
     100             : 
     101             :   public static Ref createAnnotatedTag(TestRepository<?> testRepo, String name, PersonIdent tagger)
     102             :       throws GitAPIException {
     103           2 :     TagCommand cmd =
     104           2 :         testRepo.git().tag().setName(name).setAnnotated(true).setMessage(name).setTagger(tagger);
     105           2 :     return cmd.call();
     106             :   }
     107             : 
     108             :   public static Ref updateAnnotatedTag(TestRepository<?> testRepo, String name, PersonIdent tagger)
     109             :       throws GitAPIException {
     110           2 :     TagCommand tc = testRepo.git().tag().setName(name);
     111           2 :     return tc.setAnnotated(true).setMessage(name).setTagger(tagger).setForceUpdate(true).call();
     112             :   }
     113             : 
     114             :   public static void fetch(TestRepository<?> testRepo, String spec) throws GitAPIException {
     115          18 :     FetchCommand fetch = testRepo.git().fetch();
     116          18 :     fetch.setRefSpecs(new RefSpec(spec));
     117          18 :     fetch.call();
     118          18 :   }
     119             : 
     120             :   public static PushResult pushHead(TestRepository<?> testRepo, String ref) throws GitAPIException {
     121          11 :     return pushHead(testRepo, ref, false);
     122             :   }
     123             : 
     124             :   public static PushResult pushHead(TestRepository<?> testRepo, String ref, boolean pushTags)
     125             :       throws GitAPIException {
     126          27 :     return pushHead(testRepo, ref, pushTags, false);
     127             :   }
     128             : 
     129             :   public static PushResult pushHead(
     130             :       TestRepository<?> testRepo, String ref, boolean pushTags, boolean force)
     131             :       throws GitAPIException {
     132          27 :     return pushOne(testRepo, "HEAD", ref, pushTags, force, null);
     133             :   }
     134             : 
     135             :   public static PushResult pushHead(
     136             :       TestRepository<?> testRepo,
     137             :       String ref,
     138             :       boolean pushTags,
     139             :       boolean force,
     140             :       List<String> pushOptions)
     141             :       throws GitAPIException {
     142          88 :     return pushOne(testRepo, "HEAD", ref, pushTags, force, pushOptions);
     143             :   }
     144             : 
     145             :   public static PushResult deleteRef(TestRepository<?> testRepo, String ref)
     146             :       throws GitAPIException {
     147           9 :     return pushOne(testRepo, "", ref, false, true, null);
     148             :   }
     149             : 
     150             :   public static PushResult pushOne(
     151             :       TestRepository<?> testRepo,
     152             :       String source,
     153             :       String target,
     154             :       boolean pushTags,
     155             :       boolean force,
     156             :       List<String> pushOptions)
     157             :       throws GitAPIException {
     158          93 :     PushCommand pushCmd = testRepo.git().push();
     159          93 :     pushCmd.setForce(force);
     160          93 :     pushCmd.setPushOptions(pushOptions);
     161          93 :     pushCmd.setRefSpecs(new RefSpec((source != null ? source : "") + ":" + target));
     162          93 :     if (pushTags) {
     163           0 :       pushCmd.setPushTags();
     164             :     }
     165          93 :     Iterable<PushResult> r = pushCmd.call();
     166          93 :     return Iterables.getOnlyElement(r);
     167             :   }
     168             : 
     169             :   public static void assertPushOk(PushResult result, String ref) {
     170          11 :     RemoteRefUpdate rru = result.getRemoteUpdate(ref);
     171          11 :     assertWithMessage(rru.toString()).that(rru.getStatus()).isEqualTo(RemoteRefUpdate.Status.OK);
     172          11 :   }
     173             : 
     174             :   public static void assertPushRejected(PushResult result, String ref, String expectedMessage) {
     175           4 :     RemoteRefUpdate rru = result.getRemoteUpdate(ref);
     176           4 :     assertWithMessage(rru.toString())
     177           4 :         .that(rru.getStatus())
     178           4 :         .isEqualTo(RemoteRefUpdate.Status.REJECTED_OTHER_REASON);
     179           4 :     assertThat(rru.getMessage()).isEqualTo(expectedMessage);
     180           4 :   }
     181             : 
     182             :   public static PushResult pushTag(TestRepository<?> testRepo, String tag) throws GitAPIException {
     183           0 :     return pushTag(testRepo, tag, false);
     184             :   }
     185             : 
     186             :   public static PushResult pushTag(TestRepository<?> testRepo, String tag, boolean force)
     187             :       throws GitAPIException {
     188           2 :     PushCommand pushCmd = testRepo.git().push();
     189           2 :     pushCmd.setForce(force);
     190           2 :     pushCmd.setRefSpecs(new RefSpec("refs/tags/" + tag + ":refs/tags/" + tag));
     191           2 :     Iterable<PushResult> r = pushCmd.call();
     192           2 :     return Iterables.getOnlyElement(r);
     193             :   }
     194             : 
     195             :   public static Optional<String> getChangeId(TestRepository<?> tr, ObjectId id) throws IOException {
     196          89 :     RevCommit c = tr.getRevWalk().parseCommit(id);
     197          89 :     tr.getRevWalk().parseBody(c);
     198          89 :     return Lists.reverse(c.getFooterLines(FooterConstants.CHANGE_ID)).stream().findFirst();
     199             :   }
     200             : }

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