view mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java @ 172:ded3c1ad49be

tests for uncompressed transfer
author Dmitry Neverov <dmitry.neverov@jetbrains.com>
date Wed, 09 Feb 2011 13:52:20 +0300
parents 5198b02fc5e9
children c3157374a356
line wrap: on
line source
/*
 * Copyright 2000-2011 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 com.intellij.execution.configurations.GeneralCommandLine;
import jetbrains.buildServer.ExecResult;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.CommandUtil;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.Settings;
import jetbrains.buildServer.serverSide.BuildServerListener;
import jetbrains.buildServer.serverSide.SBuildServer;
import jetbrains.buildServer.serverSide.ServerPaths;
import jetbrains.buildServer.util.EventDispatcher;
import jetbrains.buildServer.vcs.*;
import jetbrains.buildServer.vcs.impl.VcsRootImpl;
import jetbrains.buildServer.vcs.patches.PatchBuilderImpl;
import junit.framework.Assert;
import org.jetbrains.annotations.NotNull;
import org.jmock.Mock;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

@Test
public class MercurialVcsSupportTest extends BaseMercurialTestCase {
  private MercurialVcsSupport myVcs;
  private ServerPaths myServerPaths;

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

    Mock vcsManagerMock = new Mock(VcsManager.class);
    vcsManagerMock.stubs().method("registerVcsSupport");
    Mock serverMock = new Mock(SBuildServer.class);
    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
    serverMock.stubs().method("getExecutor").will(myMockSupport.returnValue(executor));

    EventDispatcher<BuildServerListener> dispatcher = EventDispatcher.create(BuildServerListener.class);

    File systemDir = myTempFiles.createTempDir();
    myServerPaths = new ServerPaths(systemDir.getAbsolutePath(), systemDir.getAbsolutePath(), systemDir.getAbsolutePath());
    assertTrue(new File(myServerPaths.getCachesDir()).mkdirs());
    myVcs = new MercurialVcsSupport((VcsManager)vcsManagerMock.proxy(), myServerPaths, (SBuildServer)serverMock.proxy(), dispatcher);
  }

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

  public void test_get_current_version() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    assertEquals(myVcs.getCurrentVersion(vcsRoot), "10:9c6a6b4aede0");
    assertEquals("9c6a6b4aede0", myVcs.getVersionDisplayName("10:9c6a6b4aede0", vcsRoot));

    assertEquals(myVcs.getCurrentVersion(createVcsRoot(simpleRepo(), "test_branch")), "8:04c3ae4c6312");

    assertEquals(myVcs.getCurrentVersion(createVcsRoot(simpleRepo(), "name with space")), "9:9babcf2d5705");
  }

  private List<ModificationData> collectChanges(@NotNull VcsRoot vcsRoot, @NotNull String from, @NotNull String to, @NotNull CheckoutRules rules) throws VcsException {
    return ((CollectChangesByCheckoutRules) myVcs.getCollectChangesPolicy()).collectChanges(vcsRoot, from, to, rules);
  }

  public void test_collect_changes_between_two_same_roots() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    VcsRootImpl sameVcsRoot = createVcsRoot(simpleRepo());
    List<ModificationData> changes = myVcs.collectChanges(vcsRoot, "0:9875b412a788", sameVcsRoot, "3:9522278aa38d", new CheckoutRules(""));
    do_check_for_collect_changes(changes);
  }

  public void test_collect_changes() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    List<ModificationData> changes = collectChanges(vcsRoot, "0:9875b412a788", "3:9522278aa38d", new CheckoutRules(""));
    do_check_for_collect_changes(changes);
  }

  private void do_check_for_collect_changes(List<ModificationData> changes) throws Exception {
    assertEquals(3, changes.size());

    ModificationData md1 = changes.get(0);
    ModificationData md2 = changes.get(1);
    ModificationData md3 = changes.get(2);
    assertEquals(md1.getVersion(), "1:1d446e82d356");
    assertEquals(md1.getDescription(), "new file added");
    List<VcsChange> files1 = md1.getChanges();
    assertEquals(1, files1.size());
    assertEquals(VcsChangeInfo.Type.ADDED, files1.get(0).getType());
    assertEquals(normalizePath(files1.get(0).getRelativeFileName()), "dir1/file3.txt");

    assertEquals(md2.getVersion(), "2:7209b1f1d793");
    assertEquals(md2.getDescription(), "file4.txt added");
    List<VcsChange> files2 = md2.getChanges();
    assertEquals(1, files2.size());
    assertEquals(files2.get(0).getType(), VcsChangeInfo.Type.ADDED);
    assertEquals(normalizePath(files2.get(0).getRelativeFileName()), "dir1/file4.txt");

    assertEquals(md3.getVersion(), "3:9522278aa38d");
    assertEquals(md3.getDescription(), "file removed");
    List<VcsChange> files3 = md3.getChanges();
    assertEquals(1, files3.size());
    assertEquals(files3.get(0).getType(), VcsChangeInfo.Type.REMOVED);
    assertEquals(normalizePath(files3.get(0).getRelativeFileName()), "dir1/file4.txt");
  }

  private ByteArrayOutputStream buildPatch(VcsRoot vcsRoot, String from, String to, CheckoutRules rules) throws IOException, VcsException {
    final ByteArrayOutputStream output = new ByteArrayOutputStream();
    final PatchBuilderImpl builder = new PatchBuilderImpl(output);

    ((BuildPatchByCheckoutRules)myVcs.getBuildPatchPolicy()).buildPatch(vcsRoot, from, to, builder, rules);
    builder.close();
    return output;
  }
  
  @Test
  public void test_build_patch() throws IOException, VcsException {
    setName("cleanPatch1");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    ByteArrayOutputStream output = buildPatch(vcsRoot, null, "4:b06a290a363b", new CheckoutRules(""));
    checkPatchResult(output.toByteArray());

    File clonedReposParentDir = new File(myServerPaths.getCachesDir(), "mercurial");
    assertTrue(clonedReposParentDir.isDirectory());
    assertTrue(1 == clonedReposParentDir.list(new FilenameFilter() {
      public boolean accept(final File dir, final String name) {
        return name.startsWith("hg_");
      }
    }).length);
  }

  public void test_build_incremental_patch() throws IOException, VcsException {
    setName("patch1");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    ByteArrayOutputStream output = buildPatch(vcsRoot, "3:9522278aa38d", "4:b06a290a363b", new CheckoutRules(""));

    checkPatchResult(output.toByteArray());
  }

  public void test_build_incremental_patch_checkout_rules() throws IOException, VcsException {
    setName("patch1_checkout_rules");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    ByteArrayOutputStream output = buildPatch(vcsRoot, "3:9522278aa38d", "4:b06a290a363b", new CheckoutRules("+:dir1=>path"));

    checkPatchResult(output.toByteArray());
  }

  public void test_build_clean_patch_checkout_rules() throws IOException, VcsException {
    setName("cleanPatch1_checkout_rules");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    ByteArrayOutputStream output = buildPatch(vcsRoot, null, "4:b06a290a363b", new CheckoutRules("+:dir1/subdir=>."));

    checkPatchResult(output.toByteArray());
  }

  public void test_build_incremental_patch_file_with_space() throws IOException, VcsException {
    setName("patch2");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    ByteArrayOutputStream output = buildPatch(vcsRoot, "3:9522278aa38d", "6:b9deb9a1c6f4", new CheckoutRules(""));

    checkPatchResult(output.toByteArray());
  }

  public void test_get_content() throws IOException, VcsException {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    byte[] content = myVcs.getContent("dir1/subdir/file2.txt", vcsRoot, "4:b06a290a363b");
    assertEquals(new String(content), "bbb");
    content = myVcs.getContent("dir1/subdir/file2.txt", vcsRoot, "5:1d2cc6f3bc29");
    assertEquals(new String(content), "modified\r\nbbb");
  }

  public void test_get_content_in_branch() throws IOException, VcsException {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");

    byte[] content = myVcs.getContent("file_in_branch.txt", vcsRoot, "8:04c3ae4c6312");
    assertEquals(new String(content), "file from the test_branch\r\nfile modified");
  }

  public void test_test_connection() throws IOException, VcsException {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    System.out.println(myVcs.getTestConnectionSupport().testConnection(vcsRoot));

    vcsRoot.addProperty(Constants.REPOSITORY_PROP, "/some/non/existent/path");
    try {
      myVcs.getTestConnectionSupport().testConnection(vcsRoot);
      fail("Exception expected");
    } catch (VcsException e) {
    }
  }

  public void test_tag() throws IOException, VcsException {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    cleanRepositoryAfterTest(simpleRepo());

    String actualTag = myVcs.label("new:tag", "1:1d446e82d356", vcsRoot, new CheckoutRules(""));
    assertEquals(actualTag, "new_tag");

    // check the tag is pushed to the parent repository
    GeneralCommandLine cli = new GeneralCommandLine();
    cli.setExePath(vcsRoot.getProperty(Constants.HG_COMMAND_PATH_PROP));
    cli.setWorkDirectory(vcsRoot.getProperty(Constants.REPOSITORY_PROP));
    cli.addParameter("tags");
    ExecResult res = CommandUtil.runCommand(cli);
    assertTrue(res.getStdout().contains("new_tag"));
    assertTrue(res.getStdout().contains("1:1d446e82d356"));
  }

  public void test_tag_in_branch() throws IOException, VcsException {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");
    cleanRepositoryAfterTest(simpleRepo());

    String actualTag = myVcs.label("branch_tag", "7:376dcf05cd2a", vcsRoot, new CheckoutRules(""));
    assertEquals(actualTag, "branch_tag");

    // check the tag is pushed to the parent repository
    GeneralCommandLine cli = new GeneralCommandLine();
    cli.setExePath(vcsRoot.getProperty(Constants.HG_COMMAND_PATH_PROP));
    cli.setWorkDirectory(vcsRoot.getProperty(Constants.REPOSITORY_PROP));
    cli.addParameter("tags");
    ExecResult res = CommandUtil.runCommand(cli);
    assertTrue(res.getStdout().contains("branch_tag"));
    assertTrue(res.getStdout().contains("7:376dcf05cd2a"));
  }

  public void test_collect_changes_in_branch() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");

    // fromVersion(6:b9deb9a1c6f4) is not in the branch (it is in the default branch)
    List<ModificationData> changes = collectChanges(vcsRoot, "6:b9deb9a1c6f4", "7:376dcf05cd2a", CheckoutRules.DEFAULT);
    assertEquals(1, changes.size());

    ModificationData md1 = changes.get(0);
    assertEquals(md1.getVersion(), "7:376dcf05cd2a");
    assertEquals(md1.getDescription(), "new file added in the test_branch");
    List<VcsChange> files1 = md1.getChanges();
    assertEquals(1, files1.size());
    assertEquals(VcsChangeInfo.Type.ADDED, files1.get(0).getType());
    assertEquals(normalizePath(files1.get(0).getRelativeFileName()), "file_in_branch.txt");

    changes = collectChanges(vcsRoot, "7:376dcf05cd2a", "8:04c3ae4c6312", CheckoutRules.DEFAULT);
    assertEquals(1, changes.size());

    md1 = changes.get(0);
    assertEquals(md1.getVersion(), "8:04c3ae4c6312");
    assertEquals(md1.getDescription(), "file modified");
  }

  public void test_full_patch_from_branch() throws IOException, VcsException {
    setName("patch3");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");

    ByteArrayOutputStream output = buildPatch(vcsRoot, null, "7:376dcf05cd2a", new CheckoutRules(""));

    checkPatchResult(output.toByteArray());
  }

  public void test_full_patch_from_branch_with_checkout_rules() throws IOException, VcsException {
    setName("patch3_checkout_rules1");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");

    ByteArrayOutputStream output = buildPatch(vcsRoot, null, "7:376dcf05cd2a", new CheckoutRules("+:.=>path"));

    checkPatchResult(output.toByteArray());
  }

  public void test_full_patch_from_branch_with_checkout_rules_mapped_and_skipped() throws IOException, VcsException {
    setName("patch3_checkout_rules2");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");

    ByteArrayOutputStream output = buildPatch(vcsRoot, null, "7:376dcf05cd2a", new CheckoutRules("+:dir1=>path/dir1\n+:dir with space"));

    checkPatchResult(output.toByteArray());
  }

  public void test_incremental_patch_from_branch() throws IOException, VcsException {
    setName("patch4");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");

    ByteArrayOutputStream output = buildPatch(vcsRoot, "7:376dcf05cd2a", "8:04c3ae4c6312", new CheckoutRules(""));

    checkPatchResult(output.toByteArray());
  }

  @Test(enabled = false)
  public void support_anchor_branch_notation() throws IOException {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    String repPath = vcsRoot.getProperty(Constants.REPOSITORY_PROP);
    vcsRoot.addProperty(Constants.REPOSITORY_PROP, repPath + "#test_branch");
    Settings settings = new Settings(new File(myServerPaths.getCachesDir()), vcsRoot);
    assertEquals("test_branch", settings.getBranchName());

    vcsRoot.addProperty(Constants.REPOSITORY_PROP, repPath + "#");
    settings = new Settings(new File(myServerPaths.getCachesDir()), vcsRoot);
    assertEquals("default", settings.getBranchName());

    vcsRoot.addProperty(Constants.REPOSITORY_PROP, repPath);
    settings = new Settings(new File(myServerPaths.getCachesDir()), vcsRoot);
    assertEquals("default", settings.getBranchName());
  }

  public void build_patch_using_custom_clone_path() throws IOException, VcsException {
    setName("cleanPatch1");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    File cloneDir = myTempFiles.createTempDir();
    vcsRoot.addProperty(Constants.SERVER_CLONE_PATH_PROP, cloneDir.getAbsolutePath());

    ByteArrayOutputStream output = buildPatch(vcsRoot, null, "4:b06a290a363b", new CheckoutRules(""));

    checkPatchResult(output.toByteArray());

    assertTrue(new File(cloneDir, new File(vcsRoot.getProperty(Constants.REPOSITORY_PROP)).getName()).isDirectory());
  }

  private String mergeCommittsRepo() {
    return new File("mercurial-tests/testData/rep2").getAbsolutePath();
  }

  public void test_collect_changes_between_two_different_roots() throws Exception {
    VcsRootImpl defaultRoot = createVcsRoot(mergeCommittsRepo());
    VcsRootImpl branchRoot = createVcsRoot(mergeCommittsRepo(), "test");
    List<ModificationData> changes = myVcs.collectChanges(defaultRoot, "11:48177654181c", branchRoot, "10:fc524efc2bc4", CheckoutRules.DEFAULT);
    assertEquals(changes.size(), 2);

    assertEquals("9:8c44244d6645", changes.get(0).getVersion());
    assertEquals("10:fc524efc2bc4", changes.get(1).getVersion());
  }

  public void test_collect_changes_merge() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(mergeCommittsRepo());

    List<ModificationData> changes = collectChanges(vcsRoot, "1:a3d15477d297", "4:6eeb8974fe67", CheckoutRules.DEFAULT);
    assertEquals(changes.size(), 3);

    assertEquals("2:db8a04d262f3", changes.get(0).getVersion());
    assertEquals("3:2538c02bafeb", changes.get(1).getVersion());
    assertEquals("4:6eeb8974fe67", changes.get(2).getVersion());

    assertFiles(Arrays.asList("A dir1/file1.txt"), changes.get(0));
    assertFiles(Arrays.asList("A dir2/file2.txt"), changes.get(1));
    assertFiles(Arrays.asList("A dir1/file1.txt", "A dir2/file2.txt"), changes.get(2));
  }

  public void test_collect_changes_merge_conflict() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(mergeCommittsRepo());

    List<ModificationData> changes = collectChanges(vcsRoot, "6:6066b677d026", "8:b6e2d176fe8e", CheckoutRules.DEFAULT);
    assertEquals(changes.size(), 2);

    assertFiles(Arrays.asList("A dir4/file41.txt"), changes.get(0));
    assertFiles(Arrays.asList("M dir4/file41.txt", "A dir4/file42.txt", "A dir4/file43.txt", "R dir3/file3.txt"), changes.get(1));
  }

  public void test_collect_changes_merge_conflict_named_branch() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(mergeCommittsRepo());

    List<ModificationData> changes = collectChanges(vcsRoot, "8:b6e2d176fe8e", "12:1e620196c4b6", CheckoutRules.DEFAULT);
    assertEquals(changes.size(), 2);

    assertFiles(Arrays.asList("A dir6/file6.txt"), changes.get(0));
    assertFiles(Arrays.asList("M dir6/file6.txt", "A dir5/file5.txt"), changes.get(1));
  }

  public void use_compressed_transfer_by_default() {
    VcsRootImpl root = new VcsRootImpl(1, Constants.VCS_NAME);
    root.addAllProperties(myVcs.getDefaultVcsProperties());
    root.addProperty(Constants.REPOSITORY_PROP, "http://host.com/path");
    Settings settings = new Settings(new File("."), root);
    assertFalse(settings.isUncompressedTransfer());
  }

  private void assertFiles(final List<String> expectedFiles, final ModificationData modificationData) {
    List<String> actualFiles = new ArrayList<String>();
    for (VcsChange vc: modificationData.getChanges()) {
      actualFiles.add(toFileStatus(vc.getType()) + " " + vc.getRelativeFileName());
    }
    Assert.assertEquals("Actual files: " + actualFiles.toString(), expectedFiles, actualFiles);
  }

  private String toFileStatus(VcsChange.Type type) {
    switch (type) {
      case ADDED:
        return "A";
      case REMOVED:
        return "R";
      case CHANGED:
        return "M";
    }
    return "?";
  }

  private Object normalizePath(final String path) {
    return path.replace(File.separatorChar, '/');
  }


  public void test_collect_changes_using_checkout_rules() {
    assertTrue(myVcs.getCollectChangesPolicy() instanceof CollectChangesByCheckoutRules);
  }
}