view mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/AgentSideCheckoutTest.java @ 834:80ae3dc66685

TW-18605 add support for 'hg purge'
author Dmitry Neverov <dmitry.neverov@jetbrains.com>
date Sun, 01 Jun 2014 22:16:18 +0200
parents 3047ff388393
children a11bcfb63f4f
line wrap: on
line source
/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jetbrains.buildServer.buildTriggers.vcs.mercurial;

import jetbrains.buildServer.agent.AgentRunningBuild;
import jetbrains.buildServer.agent.BuildAgentConfiguration;
import jetbrains.buildServer.agent.BuildProgressLogger;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandSettingsForRootImpl;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandlineViaFileWrapperWeaver;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.ExtensionsWeaver;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.TestCommandSettingsFactory;
import jetbrains.buildServer.util.FileUtil;
import jetbrains.buildServer.util.TestFor;
import jetbrains.buildServer.vcs.CheckoutRules;
import jetbrains.buildServer.vcs.IncludeRule;
import jetbrains.buildServer.vcs.VcsException;
import jetbrains.buildServer.vcs.VcsRoot;
import jetbrains.buildServer.vcs.impl.VcsRootImpl;
import org.jetbrains.annotations.NotNull;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

import static jetbrains.buildServer.buildTriggers.vcs.mercurial.Util.copyRepository;

/**
 * @author Pavel.Sher
 *         Date: 30.07.2008
 */
@Test
public class AgentSideCheckoutTest extends BaseMercurialPatchTestCase {

  final static String HG_PATH_REFERENCE = "%" + HgDetector.AGENT_HG_PATH_PROPERTY + "%";
  private MercurialAgentSideVcsSupport myVcsSupport;
  private File myWorkDir;
  private File myMirrorsRootDir;
  private Mockery myContext;
  private BuildProgressLogger myLogger;
  private int myBuildCounter = 0;

  @Override
  @BeforeMethod
  protected void setUp() throws Exception {
    super.setUp();

    myContext = new Mockery();

    myMirrorsRootDir = myTempFiles.createTempDir();

    final BuildAgentConfiguration agentConfig = myContext.mock(BuildAgentConfiguration.class);
    myContext.checking(new Expectations() {{
      allowing(agentConfig).getCacheDirectory("mercurial"); will(returnValue(myMirrorsRootDir));
      allowing(agentConfig).getTempDirectory(); will(returnValue(myTempFiles.createTempDir()));
      allowing(agentConfig).getParametersResolver(); will(returnValue(new HgPathResolver()));
    }});

    final AgentPluginConfigImpl pluginConfig = new AgentPluginConfigImpl(agentConfig);
    myVcsSupport = new MercurialAgentSideVcsSupport(pluginConfig,
            new MirrorManagerImpl(pluginConfig),
            new AgentRepoFactory(new CommandSettingsForRootImpl(new TestCommandSettingsFactory(), new ExtensionsWeaver(), new CommandlineViaFileWrapperWeaver()), new AgentHgPathProvider(agentConfig)));

    myLogger = myContext.mock(BuildProgressLogger.class);
    myContext.checking(new Expectations() {{
      allowing(myLogger).message(with(any(String.class)));
    }});

    myWorkDir = myTempFiles.createTempDir();

  }

  public void should_work_when_path_to_hg_is_property() throws Exception {
    VcsRootImpl root = new VcsRootBuilder()
            .withUrl(copyRepository(myTempFiles, simpleRepo()).getAbsolutePath())
            .withHgPath(HG_PATH_REFERENCE).build();
    testUpdate(root, "b06a290a363b", "cleanPatch1/after", new IncludeRule(".", ".", null));
  }


  public void checkout_on_agent() throws IOException, VcsException {
    testUpdate(createVcsRoot(simpleRepo()), "4:b06a290a363b", "cleanPatch1/after", new IncludeRule(".", ".", null));
  }

  public void checkout_on_agent_include_rule_with_mapping() throws IOException, VcsException {
    testUpdate(createVcsRoot(simpleRepo()), "4:b06a290a363b", "cleanPatch1/after", new IncludeRule("+:.", "subdir", null));
  }

  private void testUpdate(final VcsRoot vcsRoot, String version, String expected, final IncludeRule includeRule) throws VcsException, IOException {
    File workDir = doUpdate(vcsRoot, version, includeRule);

    checkWorkingDir(expected, workDir);
  }

  private void checkWorkingDir(final String expected, final File workDir) throws IOException {
    FileUtil.delete(new File(workDir, ".hg"));
    checkDirectoriesAreEqual(new File(getTestDataPath(), expected), workDir);
  }

  private File doUpdate(@NotNull final VcsRoot root, @NotNull final String version, int timeoutSeconds) throws Exception {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<File> future = executor.submit(new Callable<File>() {
      public File call() throws Exception {
        return doUpdate(root, version);
      }
    });
    executor.shutdown();
    executor.awaitTermination(timeoutSeconds, TimeUnit.SECONDS);
    if (!future.isDone())
      fail("Update failed due to timeout");
    return future.get();
  }

  protected File doUpdate(@NotNull VcsRoot root, @NotNull String version) throws VcsException {
    return doUpdate(root, version, IncludeRule.createDefaultInstance());
  }

  private File doUpdate(final VcsRoot vcsRoot, final String version, final IncludeRule includeRule) throws VcsException {
    return doUpdate(vcsRoot, version, includeRule, false);
  }

  private File doUpdate(final VcsRoot vcsRoot, final String version, final IncludeRule includeRule, boolean useLocalMirrors) throws VcsException {
    File actualWorkDir = new File(myWorkDir, includeRule.getTo());
    final Map<String, String> sharedConfigParameters = new HashMap<String, String>();
    sharedConfigParameters.put("teamcity.hg.use.local.mirrors", String.valueOf(useLocalMirrors));
    final AgentRunningBuild build = myContext.mock(AgentRunningBuild.class, "build" + myBuildCounter++);
    myContext.checking(new Expectations() {{
      allowing(build).getBuildLogger(); will(returnValue(myLogger));
      allowing(build).getSharedConfigParameters(); will(returnValue(sharedConfigParameters));
    }});
    myVcsSupport.getUpdater(vcsRoot, new CheckoutRules(""), version, myWorkDir, build, false).process(includeRule, actualWorkDir);

    File hgDir = new File(actualWorkDir, ".hg");
    assertTrue(hgDir.isDirectory());
    return actualWorkDir;
  }

  public void checkout_on_agent_from_branch() throws IOException, VcsException {
    testUpdate(createVcsRoot(simpleRepo(), "test_branch"), "7:376dcf05cd2a", "patch3/after", new IncludeRule(".", ".", null));
  }

  public void update_on_agent() throws IOException, VcsException {
    VcsRoot vcsRoot = createVcsRoot(simpleRepo());
    doUpdate(vcsRoot, "3:9522278aa38d", new IncludeRule(".", ".", null));
    File workDir = doUpdate(vcsRoot, "4:b06a290a363b", new IncludeRule(".", ".", null));

    checkWorkingDir("patch1/after", workDir);
  }

  public void update_on_agent_with_include_rule() throws IOException, VcsException {
    VcsRoot vcsRoot = createVcsRoot(simpleRepo());
    doUpdate(vcsRoot, "3:9522278aa38d", new IncludeRule(".", "subdir", null));
    File workDir = doUpdate(vcsRoot, "4:b06a290a363b", new IncludeRule(".", "subdir", null));

    checkWorkingDir("patch1/after", workDir);
  }

  public void update_on_agent_from_branch() throws IOException, VcsException {
    VcsRoot vcsRoot = createVcsRoot(simpleRepo(), "test_branch");
    doUpdate(vcsRoot, "7:376dcf05cd2a", new IncludeRule(".", ".", null));
    File workDir = doUpdate(vcsRoot, "8:04c3ae4c6312", new IncludeRule(".", ".", null));

    checkWorkingDir("patch4/after", workDir);
  }

  public void by_default_local_mirror_not_created() throws IOException, VcsException {
    List<File> mirrors = FileUtil.getSubDirectories(myMirrorsRootDir);
    assertTrue(mirrors.isEmpty());
    VcsRoot root = createVcsRoot(simpleRepo());
    doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null));
    mirrors = FileUtil.getSubDirectories(myMirrorsRootDir);
    //though some dirs are created - they are empty => there were no clones into local mirrors
    for (File mirror : mirrors) {
      assertTrue(FileUtil.getSubDirectories(mirror).isEmpty());
    }
  }

  public void local_mirror_is_created() throws IOException, VcsException {
    List<File> mirrors = FileUtil.getSubDirectories(myMirrorsRootDir);
    assertTrue(mirrors.isEmpty());
    VcsRoot root = createVcsRoot(simpleRepo());
    doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true);
    mirrors = FileUtil.getSubDirectories(myMirrorsRootDir);
    assertEquals(1, mirrors.size());
    File mirror = mirrors.get(0);
    File dotHg = new File(mirror, ".hg");
    assertTrue(dotHg.exists());
    File hgrc = new File(dotHg, "hgrc");
    String hgrcContent = FileUtil.readText(hgrc);
    assertTrue(hgrcContent.contains("default = " + root.getProperty(Constants.REPOSITORY_PROP)));
  }

  private void new_repository_is_cloned_from_local_mirror() throws IOException, VcsException {
    VcsRoot root = createVcsRoot(simpleRepo());
    File workingDir = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true);
    File mirrorDir = FileUtil.getSubDirectories(myMirrorsRootDir).get(0);
    File hgrc = new File(workingDir, ".hg" + File.separator + "hgrc");
    String hgrcContent = FileUtil.readText(hgrc);
    assertTrue(hgrcContent.contains("default = " + mirrorDir.getCanonicalPath()));
  }

  private void repository_cloned_from_remote_start_cloning_from_local_mirror() throws IOException, VcsException {
    VcsRoot root = createVcsRoot(simpleRepo());
    //clone from remote repository
    File workingDir = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null));
    String hgrcContent = FileUtil.readText(new File(workingDir, ".hg" + File.separator + "hgrc"));

    File workingDir2 = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true);
    File newMirrorDir = FileUtil.getSubDirectories(myMirrorsRootDir).get(0);
    String hgrcContent2 = FileUtil.readText(new File(workingDir2, ".hg" + File.separator + "hgrc"));
    assertFalse(hgrcContent2.equals(hgrcContent));//repository settings are changed
    assertTrue(hgrcContent2.contains("default = " + newMirrorDir.getCanonicalPath()));//now it clones from local mirror
  }

  private void repository_cloned_from_local_mirror_start_cloning_from_remote() throws IOException, VcsException {
    VcsRoot root = createVcsRoot(simpleRepo());
    //clone from remote repository
    File workingDir = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null), true);
    String hgrcContent = FileUtil.readText(new File(workingDir, ".hg" + File.separator + "hgrc"));
    File newMirrorDir = FileUtil.getSubDirectories(myMirrorsRootDir).get(0);
    assertTrue(hgrcContent.contains("default = " + newMirrorDir.getCanonicalPath()));//now it clones from local mirror

    File workingDir2 = doUpdate(root, "3:9522278aa38d", new IncludeRule(".", ".", null));
    String hgrcContent2 = FileUtil.readText(new File(workingDir2, ".hg" + File.separator + "hgrc"));
    assertFalse(hgrcContent2.equals(hgrcContent));//repository settings are changed
    assertTrue(hgrcContent2.contains("default = " + root.getProperty(Constants.REPOSITORY_PROP)));//now it clones from remote
  }

  /**
   * TW-15984
   */
  public void should_be_able_to_clone_into_non_empty_dir() throws IOException, VcsException {
    VcsRoot vcsRoot = createVcsRoot(simpleRepo());
    doUpdate(vcsRoot, "3:9522278aa38d", new IncludeRule(".", "subdir", null));
    doUpdate(vcsRoot, "4:b06a290a363b", new IncludeRule(".", ".", null));
  }

  public void cloned_repo_should_contains_default_parameter_in_hgrc() throws VcsException, IOException {
    VcsRoot root = createVcsRoot(simpleRepo());
    File workingDir = doUpdate(root, "4:b06a290a363b", new IncludeRule(".", ".", null));
    File hgrc = new File(workingDir, ".hg" + File.separator + "hgrc");
    String hgrcContent = FileUtil.readText(hgrc);
    assertTrue(hgrcContent.contains("default = " + root.getProperty(Constants.REPOSITORY_PROP)));
  }

  @TestFor(issues = "TW-19703")
  public void should_work_when_repository_is_locked() throws Exception{
    VcsRootImpl root = new VcsRootBuilder()
            .withUrl(copyRepository(myTempFiles, simpleRepo()).getAbsolutePath())
            .withHgPath(HG_PATH_REFERENCE).build();
    File workingDir = doUpdate(root, "4:b06a290a363b");

    lockRepository(workingDir);
    doUpdate(root, "6:b9deb9a1c6f4", 10);

    lockWorkingDir(workingDir);
    doUpdate(root, "10:9c6a6b4aede0", 10);
  }

  private void lockRepository(@NotNull File workingDir) {
    File lock = new File(workingDir, ".hg" + File.separator + "store" + File.separator + "lock");
    FileUtil.writeFile(lock, "");
  }

  private void lockWorkingDir(@NotNull File workingDir) {
    File lock = new File(workingDir, ".hg" + File.separator + "wlock");
    FileUtil.writeFile(lock, "");
  }

  protected String getTestDataPath() {
    return "mercurial-tests/testData";
  }


}