view test/org/tmatesoft/hg/test/TestPull.java @ 709:497e697636fc

Report merged lines as changed block if possible, not as a sequence of added/deleted blocks. To facilitate access to merge parent lines AddBlock got mergeLineAt() method that reports index of the line in the second parent (if any), while insertedAt() has been changed to report index in the first parent always
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 21 Aug 2013 16:23:27 +0200
parents dde18bc7053b
children
line wrap: on
line source
/*
 * Copyright (c) 2013 TMate Software Ltd
 *  
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * For information on how to redistribute this software under
 * the terms of a license other than GNU General Public License
 * contact TMate Software at support@hg4j.com
 */
package org.tmatesoft.hg.test;

import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.tmatesoft.hg.repo.HgRepository.TIP;

import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.junit.Rule;
import org.junit.Test;
import org.tmatesoft.hg.core.HgAddRemoveCommand;
import org.tmatesoft.hg.core.HgCheckoutCommand;
import org.tmatesoft.hg.core.HgCommitCommand;
import org.tmatesoft.hg.core.HgIncomingCommand;
import org.tmatesoft.hg.core.HgPullCommand;
import org.tmatesoft.hg.core.Nodeid;
import org.tmatesoft.hg.internal.BasicSessionContext;
import org.tmatesoft.hg.internal.Internals;
import org.tmatesoft.hg.internal.PhasesHelper;
import org.tmatesoft.hg.internal.RevisionSet;
import org.tmatesoft.hg.repo.HgInternals;
import org.tmatesoft.hg.repo.HgLookup;
import org.tmatesoft.hg.repo.HgPhase;
import org.tmatesoft.hg.repo.HgRemoteRepository;
import org.tmatesoft.hg.repo.HgRepository;
import org.tmatesoft.hg.util.Path;

/**
 * @author Artem Tikhomirov
 * @author TMate Software Ltd.
 */
public class TestPull {

	@Rule
	public ErrorCollectorExt errorCollector = new ErrorCollectorExt();
	
	@Test
	public void testPullToEmpty() throws Exception {
		File srcRepoLoc = RepoUtils.cloneRepoToTempLocation("test-annotate", "test-pull2empty-src", false);
		File dstRepoLoc = RepoUtils.initEmptyTempRepo("test-pull2empty-dst");
		HgServer server = new HgServer().start(srcRepoLoc);
		try {
			final HgLookup hgLookup = new HgLookup();
			final HgRemoteRepository srcRemote = hgLookup.detect(server.getURL());
			final HgRepository dstRepo = hgLookup.detect(dstRepoLoc);
			HgPullCommand cmd = new HgPullCommand(dstRepo).source(srcRemote);
			cmd.execute();
			final HgRepository srcRepo = hgLookup.detect(srcRepoLoc);
			checkRepositoriesAreSame(srcRepo, dstRepo);
			final List<Nodeid> incoming = new HgIncomingCommand(dstRepo).against(srcRemote).executeLite();
			errorCollector.assertTrue(incoming.toString(), incoming.isEmpty());
			RepoUtils.assertHgVerifyOk(errorCollector, dstRepoLoc);
		} finally {
			server.stop();
		}
	}

	/**
	 * pull comes with 2 changes, one of them with new file
	 */
	@Test
	public void testPullChanges() throws Exception {
 
		File srcRepoLoc = RepoUtils.cloneRepoToTempLocation("test-annotate", "test-pull-src", false);
		File dstRepoLoc = RepoUtils.cloneRepoToTempLocation("test-annotate", "test-pull-dst", false);
		File f1 = new File(srcRepoLoc, "file1");
		assertTrue("[sanity]", f1.canWrite());
		final HgLookup hgLookup = new HgLookup();
		// add two commits, one with new file at different branch
		// commit 1
		final HgRepository srcRepo = hgLookup.detect(srcRepoLoc);
		assertEquals("[sanity]", "default", srcRepo.getWorkingCopyBranchName());
		RepoUtils.modifyFileAppend(f1, "change1");
		HgCommitCommand commitCmd = new HgCommitCommand(srcRepo).message("Commit 1");
		assertTrue(commitCmd.execute().isOk());
		final Nodeid cmt1 = commitCmd.getCommittedRevision();
		// commit 2
		new HgCheckoutCommand(srcRepo).changeset(7).clean(true).execute();
		assertEquals("[sanity]", "no-merge", srcRepo.getWorkingCopyBranchName());
		RepoUtils.createFile(new File(srcRepoLoc, "file-new"), "whatever");
		new HgAddRemoveCommand(srcRepo).add(Path.create("file-new")).execute();
		commitCmd = new HgCommitCommand(srcRepo).message("Commit 2");
		assertTrue(commitCmd.execute().isOk());
		final Nodeid cmt2 = commitCmd.getCommittedRevision();
		//
		// pull
		HgServer server = new HgServer().start(srcRepoLoc);
		final HgRepository dstRepo = hgLookup.detect(dstRepoLoc);
		try {
			final HgRemoteRepository srcRemote = hgLookup.detect(server.getURL());
			new HgPullCommand(dstRepo).source(srcRemote).execute();
		} finally {
			server.stop();
		}
		//
		errorCollector.assertTrue(dstRepo.getChangelog().isKnown(cmt1));
		errorCollector.assertTrue(dstRepo.getChangelog().isKnown(cmt2));
		checkRepositoriesAreSame(srcRepo, dstRepo);
		RepoUtils.assertHgVerifyOk(errorCollector, dstRepoLoc);
	}
	
	/**
	 * Add two draft changesets, one child of r8 (local:draft, remote:public) and another 
	 * as child of r4 (public), pull and see if 5, 7 and 8 became public, but newly added drafts remained
	 */
	@Test
	public void testPullFromPublishing() throws Exception {
		// copy, not clone as latter updates phase information
		File srcRepoLoc = RepoUtils.copyRepoToTempLocation("test-phases", "test-pull-pub-src");
		File dstRepoLoc = RepoUtils.copyRepoToTempLocation("test-phases", "test-pull-pub-dst");
		File f1 = new File(dstRepoLoc, "hello.c");
		assertTrue("[sanity]", f1.canWrite());
		final HgLookup hgLookup = new HgLookup();
		HgRepository dstRepo = hgLookup.detect(dstRepoLoc);
		PhasesHelper phaseHelper = new PhasesHelper(HgInternals.getImplementationRepo(dstRepo));
		//
		// new child revision for shared public parent
		assertEquals(HgPhase.Public, phaseHelper.getPhase(4, null));
		new HgCheckoutCommand(dstRepo).changeset(4).clean(true).execute();
		RepoUtils.modifyFileAppend(f1, "// aaa");
		HgCommitCommand commitCmd = new HgCommitCommand(dstRepo).message("Commit 1");
		assertTrue(commitCmd.execute().isOk());
		final Nodeid cmt1 = commitCmd.getCommittedRevision();
		//
		// new child rev for parent locally draft, remotely public
		assertEquals(HgPhase.Draft, phaseHelper.getPhase(5, null));
		assertEquals(HgPhase.Draft, phaseHelper.getPhase(7, null));
		assertEquals(HgPhase.Draft, phaseHelper.getPhase(8, null));
		new HgCheckoutCommand(dstRepo).changeset(8).clean(true).execute();
		RepoUtils.modifyFileAppend(f1, "// bbb");
		commitCmd = new HgCommitCommand(dstRepo).message("Commit 2");
		assertTrue(commitCmd.execute().isOk());
		final Nodeid cmt2 = commitCmd.getCommittedRevision();
		// both new revisions shall be draft
		phaseHelper = new PhasesHelper(HgInternals.getImplementationRepo(dstRepo)); // refresh PhasesHelper
		assertEquals(HgPhase.Draft, phaseHelper.getPhase(dstRepo.getChangelog().getRevisionIndex(cmt1), cmt1));
		assertEquals(HgPhase.Draft, phaseHelper.getPhase(dstRepo.getChangelog().getRevisionIndex(cmt2), cmt2));
		//

		HgServer server = new HgServer().publishing(true).start(srcRepoLoc);
		try {
			final HgRemoteRepository srcRemote = hgLookup.detect(server.getURL());
			new HgPullCommand(dstRepo).source(srcRemote).execute();
		} finally {
			server.stop();
		}
		// refresh PhasesHelper
		phaseHelper = new PhasesHelper(HgInternals.getImplementationRepo(dstRepo));
		errorCollector.assertEquals(HgPhase.Public, phaseHelper.getPhase(5, null));
		errorCollector.assertEquals(HgPhase.Public, phaseHelper.getPhase(7, null));
		errorCollector.assertEquals(HgPhase.Public, phaseHelper.getPhase(8, null));
		// phase of local-only new revisions shall not change
		errorCollector.assertEquals(HgPhase.Draft, phaseHelper.getPhase(dstRepo.getChangelog().getRevisionIndex(cmt1), cmt1));
		errorCollector.assertEquals(HgPhase.Draft, phaseHelper.getPhase(dstRepo.getChangelog().getRevisionIndex(cmt2), cmt2));
	}
	
	@Test
	public void testPullFromNonPublishing() throws Exception {
		// copy, not clone as latter updates phase information
		File srcRepoLoc = RepoUtils.copyRepoToTempLocation("test-phases", "test-pull-nopub-src");
		File dstRepoLoc = RepoUtils.initEmptyTempRepo("test-pull-nopub-dst");
		Map<String,?> props = Collections.singletonMap(Internals.CFG_PROPERTY_CREATE_PHASEROOTS, true);
		final HgLookup hgLookup = new HgLookup(new BasicSessionContext(props, null));
		HgRepository srcRepo = hgLookup.detect(srcRepoLoc);		
		// revisions 6 and 9 are secret, so
		// index of revisions 4 and 5 won't change, but that of 7 and 8 would
		Nodeid r7 = srcRepo.getChangelog().getRevision(7);
		Nodeid r8 = srcRepo.getChangelog().getRevision(8);

		HgRepository dstRepo = hgLookup.detect(dstRepoLoc);
		HgServer server = new HgServer().publishing(false).start(srcRepoLoc);
		try {
			final HgRemoteRepository srcRemote = hgLookup.detect(server.getURL());
			new HgPullCommand(dstRepo).source(srcRemote).execute();
		} finally {
			server.stop();
		}
		PhasesHelper phaseHelper = new PhasesHelper(HgInternals.getImplementationRepo(dstRepo));
		errorCollector.assertEquals(HgPhase.Public, phaseHelper.getPhase(4, null));
		errorCollector.assertEquals(HgPhase.Draft, phaseHelper.getPhase(5, null));
		errorCollector.assertEquals(HgPhase.Draft, phaseHelper.getPhase(dstRepo.getChangelog().getRevisionIndex(r7), r7));
		errorCollector.assertEquals(HgPhase.Draft, phaseHelper.getPhase(dstRepo.getChangelog().getRevisionIndex(r8), r8));
		final RevisionSet dstSecret = phaseHelper.allSecret();
		errorCollector.assertTrue(dstSecret.toString(), dstSecret.isEmpty());
	}

	private void checkRepositoriesAreSame(HgRepository srcRepo, HgRepository dstRepo) {
		// XXX copy of TestPush#checkRepositoriesAreSame
		errorCollector.assertEquals(srcRepo.getChangelog().getRevisionCount(), dstRepo.getChangelog().getRevisionCount());
		errorCollector.assertEquals(srcRepo.getChangelog().getRevision(0), dstRepo.getChangelog().getRevision(0));
		errorCollector.assertEquals(srcRepo.getChangelog().getRevision(TIP), dstRepo.getChangelog().getRevision(TIP));
	}
}