diff test/org/tmatesoft/hg/test/TestPush.java @ 652:cd77bf51b562

Push: tests. Commit respects phases.new-commit setting. Fix outgoing when changes are not children of common (Issue 47)
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Tue, 02 Jul 2013 23:21:16 +0200
parents 6e98d34eaca8
children 629a7370554c
line wrap: on
line diff
--- a/test/org/tmatesoft/hg/test/TestPush.java	Mon Jul 01 21:19:53 2013 +0200
+++ b/test/org/tmatesoft/hg/test/TestPush.java	Tue Jul 02 23:21:16 2013 +0200
@@ -26,7 +26,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.tmatesoft.hg.core.HgCheckoutCommand;
@@ -36,9 +35,11 @@
 import org.tmatesoft.hg.core.Nodeid;
 import org.tmatesoft.hg.internal.PhasesHelper;
 import org.tmatesoft.hg.internal.RevisionSet;
+import org.tmatesoft.hg.repo.HgBookmarks;
 import org.tmatesoft.hg.repo.HgChangelog;
 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;
 
@@ -101,12 +102,192 @@
 	
 	@Test
 	public void testPushToNonPublishingServer() throws Exception {
-		Assert.fail();
+		// check drafts are same as on server
+		// copy, not clone as latter updates phase information
+		File srcRepoLoc = RepoUtils.copyRepoToTempLocation("test-phases", "test-push-nopub-src");
+		File dstRepoLoc = RepoUtils.initEmptyTempRepo("test-push-nopub-dst");
+		File f1 = new File(srcRepoLoc, "hello.c");
+		assertTrue("[sanity]", f1.canWrite());
+		HgServer server = new HgServer().publishing(false).start(dstRepoLoc);
+		try {
+			final HgLookup hgLookup = new HgLookup();
+			final HgRepository srcRepo = hgLookup.detect(srcRepoLoc);
+			final HgRemoteRepository dstRemote = hgLookup.detect(server.getURL());
+			PhasesHelper phaseHelper = new PhasesHelper(HgInternals.getImplementationRepo(srcRepo));
+			final RevisionSet allDraft = phaseHelper.allDraft();
+			assertFalse("[sanity]", allDraft.isEmpty());
+			final int publicCsetToBranchAt = 4;
+			assertEquals("[sanity]", HgPhase.Public, phaseHelper.getPhase(publicCsetToBranchAt, null));
+			// in addition to existing draft csets, add one more draft, branching at some other public revision
+			new HgCheckoutCommand(srcRepo).changeset(publicCsetToBranchAt).clean(true).execute();
+			RepoUtils.modifyFileAppend(f1, "// aaa");
+			final HgCommitCommand commitCmd = new HgCommitCommand(srcRepo).message("Commit aaa");
+			assertTrue(commitCmd.execute().isOk());
+			Nodeid newCommit = commitCmd.getCommittedRevision();
+			//
+			new HgPushCommand(srcRepo).destination(dstRemote).execute();
+			HgRepository dstRepo = hgLookup.detect(dstRepoLoc);
+			final HgChangelog srcClog = srcRepo.getChangelog();
+			final HgChangelog dstClog = dstRepo.getChangelog();
+			// refresh PhasesHelper
+			phaseHelper = new PhasesHelper(HgInternals.getImplementationRepo(srcRepo));
+			// check if phase didn't change
+			errorCollector.assertEquals(HgPhase.Draft, phaseHelper.getPhase(srcClog.getRevisionIndex(newCommit), newCommit));
+			for (Nodeid n : allDraft) {
+				// check drafts from src were actually pushed to dst 
+				errorCollector.assertTrue(dstClog.isKnown(n));
+				// check drafts didn't change their phase
+				errorCollector.assertEquals(HgPhase.Draft, phaseHelper.getPhase(srcClog.getRevisionIndex(n), n));
+			}
+		} finally {
+			server.stop();
+		}
 	}
 	
+	/**
+	 * If server lists revisions we know as drafts as public, update them locally
+	 */
+	@Test
+	public void testPushUpdatesPublishedDrafts() throws Exception {
+		/* o		r9, secret
+		 * |  o		r8, draft
+		 * |  |
+		 * |  o		r7, draft
+		 * o  |		r6, secret 
+		 * | /
+		 * o		r5, draft
+		 * |
+		 * o		r4, public
+		 */
+		// remote: r5 -> public, r6 -> draft, r8 -> secret
+		// local: new draft from r4, push
+		File srcRepoLoc = RepoUtils.copyRepoToTempLocation("test-phases", "test-push-phase-update-1-src");
+		File dstRepoLoc = RepoUtils.copyRepoToTempLocation("test-phases", "test-push-phase-update-1-dst");
+		File f1 = new File(srcRepoLoc, "hello.c");
+		assertTrue("[sanity]", f1.canWrite());
+		final HgLookup hgLookup = new HgLookup();
+		final HgRepository srcRepo = hgLookup.detect(srcRepoLoc);
+		final ExecHelper dstRun = new ExecHelper(new OutputParser.Stub(), dstRepoLoc);
+		final int publicCsetToBranchAt = 4;
+		final int r5 = 5, r6 = 6, r8 = 8;
+		PhasesHelper srcPhase = new PhasesHelper(HgInternals.getImplementationRepo(srcRepo));
+		assertEquals("[sanity]", HgPhase.Draft, srcPhase.getPhase(r5, null));
+		assertEquals("[sanity]", HgPhase.Secret, srcPhase.getPhase(r6, null));
+		assertEquals("[sanity]", HgPhase.Draft, srcPhase.getPhase(r8, null));
+		// change phases in repository of remote server:
+		dstRun.exec("hg", "phase", "--public", String.valueOf(r5));
+		assertEquals(0, dstRun.getExitValue());
+		dstRun.exec("hg", "phase", "--draft", String.valueOf(r6));
+		assertEquals(0, dstRun.getExitValue());
+		dstRun.exec("hg", "phase", "--secret", "--force", String.valueOf(r8));
+		assertEquals(0, dstRun.getExitValue());
+		HgServer server = new HgServer().publishing(false).start(dstRepoLoc);
+		try {
+			final HgRemoteRepository dstRemote = hgLookup.detect(server.getURL());
+			// commit new draft head
+			new HgCheckoutCommand(srcRepo).changeset(publicCsetToBranchAt).clean(true).execute();
+			RepoUtils.modifyFileAppend(f1, "// aaa");
+			final HgCommitCommand commitCmd = new HgCommitCommand(srcRepo).message("Commit aaa");
+			assertTrue(commitCmd.execute().isOk());
+			final Nodeid newCommit = commitCmd.getCommittedRevision();
+			//
+			new HgPushCommand(srcRepo).destination(dstRemote).execute();
+			// refresh phase information
+			srcPhase = new PhasesHelper(HgInternals.getImplementationRepo(srcRepo));
+			// r5 and r6 are changed to match server phases (more exposed)
+			errorCollector.assertEquals(HgPhase.Public, srcPhase.getPhase(r5, null));
+			errorCollector.assertEquals(HgPhase.Draft, srcPhase.getPhase(r6, null));
+			// r8 is secret on server, locally can't make it less exposed though
+			errorCollector.assertEquals(HgPhase.Draft, srcPhase.getPhase(r8, null));
+			//
+			HgRepository dstRepo = hgLookup.detect(dstRepoLoc);
+			final HgChangelog dstClog = dstRepo.getChangelog();
+			assertTrue(dstClog.isKnown(newCommit));
+			PhasesHelper dstPhase = new PhasesHelper(HgInternals.getImplementationRepo(dstRepo));
+			errorCollector.assertEquals(HgPhase.Draft, dstPhase.getPhase(dstClog.getRevisionIndex(newCommit), newCommit));
+			// the one that was secret is draft now
+			errorCollector.assertEquals(HgPhase.Draft, srcPhase.getPhase(r8, null));
+		} finally {
+			server.stop();
+		}
+	}
+	
+	/**
+	 * update phases of local revisions and push changes
+	 */
+	@Test
+	public void testPushPublishAndUpdates() throws Exception {
+		File srcRepoLoc = RepoUtils.copyRepoToTempLocation("test-phases", "test-push-phase-update-2-src");
+		File dstRepoLoc = RepoUtils.initEmptyTempRepo("test-push-phase-update-1-dst");
+		final int r4 = 4, r5 = 5, r6 = 6, r9 = 9;
+		HgServer server = new HgServer().publishing(false).start(dstRepoLoc);
+		try {
+			final HgLookup hgLookup = new HgLookup();
+			final HgRepository srcRepo = hgLookup.detect(srcRepoLoc);
+			final HgRemoteRepository dstRemote = hgLookup.detect(server.getURL());
+			new HgPushCommand(srcRepo).destination(dstRemote).execute();
+			//
+			// make sure pushed repository got same draft root
+			final Nodeid r4PublicHead = srcRepo.getChangelog().getRevision(r4);
+			final Nodeid r5DraftRoot = srcRepo.getChangelog().getRevision(r5);
+			HgRepository dstRepo = hgLookup.detect(dstRepoLoc);
+			final HgChangelog dstClog = dstRepo.getChangelog();
+			PhasesHelper dstPhase = new PhasesHelper(HgInternals.getImplementationRepo(dstRepo));
+			assertEquals(HgPhase.Public, dstPhase.getPhase(dstClog.getRevisionIndex(r4PublicHead), r4PublicHead));
+			assertEquals(HgPhase.Draft, dstPhase.getPhase(dstClog.getRevisionIndex(r5DraftRoot), r5DraftRoot));
+			//
+			// now, graduate some local revisions, r5:draft->public, r6:secret->public, r9: secret->draft
+			final ExecHelper srcRun = new ExecHelper(new OutputParser.Stub(), srcRepoLoc);
+			srcRun.exec("hg", "phase", "--public", String.valueOf(r5));
+			srcRun.exec("hg", "phase", "--public", String.valueOf(r6));
+			srcRun.exec("hg", "phase", "--draft", String.valueOf(r9));
+			// PhaseHelper shall be new for the command, and would pick up these external changes 
+			new HgPushCommand(srcRepo).destination(dstRemote).execute();
+			final Nodeid r6Nodeid = srcRepo.getChangelog().getRevision(r6);
+			final Nodeid r9Nodeid = srcRepo.getChangelog().getRevision(r9);
+			// refresh 
+			dstPhase = new PhasesHelper(HgInternals.getImplementationRepo(dstRepo));
+			// not errorCollector as subsequent code would fail if these secret revs didn't get into dst
+			assertTrue(dstClog.isKnown(r6Nodeid));
+			assertTrue(dstClog.isKnown(r9Nodeid));
+			errorCollector.assertEquals(HgPhase.Public, dstPhase.getPhase(dstClog.getRevisionIndex(r5DraftRoot), r5DraftRoot));
+			errorCollector.assertEquals(HgPhase.Public, dstPhase.getPhase(dstClog.getRevisionIndex(r6Nodeid), r6Nodeid));
+			errorCollector.assertEquals(HgPhase.Draft, dstPhase.getPhase(dstClog.getRevisionIndex(r9Nodeid), r9Nodeid));
+		} finally {
+			server.stop();
+		}
+	}
+
+	
 	@Test
 	public void testPushToPublishingServer() throws Exception {
-		Assert.fail();
+		// copy, not clone as latter updates phase information
+		File srcRepoLoc = RepoUtils.copyRepoToTempLocation("test-phases", "test-push-pub-src");
+		File dstRepoLoc = RepoUtils.initEmptyTempRepo("test-push-pub-dst");
+		HgServer server = new HgServer().publishing(true).start(dstRepoLoc);
+		try {
+			final HgLookup hgLookup = new HgLookup();
+			final HgRepository srcRepo = hgLookup.detect(srcRepoLoc);
+			final HgRemoteRepository dstRemote = hgLookup.detect(server.getURL());
+			PhasesHelper phaseHelper = new PhasesHelper(HgInternals.getImplementationRepo(srcRepo));
+			final RevisionSet allDraft = phaseHelper.allDraft();
+			assertFalse("[sanity]", allDraft.isEmpty());
+			// push all changes
+			new HgPushCommand(srcRepo).destination(dstRemote).execute();
+			HgRepository dstRepo = hgLookup.detect(dstRepoLoc);
+			final HgChangelog srcClog = srcRepo.getChangelog();
+			final HgChangelog dstClog = dstRepo.getChangelog();
+			// refresh PhasesHelper
+			phaseHelper = new PhasesHelper(HgInternals.getImplementationRepo(srcRepo));
+			for (Nodeid n : allDraft) {
+				// check drafts from src were actually pushed to dst 
+				errorCollector.assertTrue(dstClog.isKnown(n));
+				// check drafts became public
+				errorCollector.assertEquals(HgPhase.Public, phaseHelper.getPhase(srcClog.getRevisionIndex(n), n));
+			}
+		} finally {
+			server.stop();
+		}
 	}
 
 	@Test
@@ -137,7 +318,69 @@
 
 	@Test
 	public void testUpdateBookmarkOnPush() throws Exception {
-		Assert.fail();
+		File srcRepoLoc = RepoUtils.cloneRepoToTempLocation("test-annotate", "test-push-src", false);
+		File dstRepoLoc = RepoUtils.cloneRepoToTempLocation("test-annotate", "test-push-dst", false);
+		final ExecHelper srcRun = new ExecHelper(new OutputParser.Stub(), srcRepoLoc);
+		final ExecHelper dstRun = new ExecHelper(new OutputParser.Stub(), dstRepoLoc);
+		File f1 = new File(srcRepoLoc, "file1");
+		assertTrue("[sanity]", f1.canWrite());
+		//
+		final String bm1 = "mark1", bm2 = "mark2", bm3 = "mark3", bm4 = "mark4", bm5 = "mark5";
+		final int bm2Local = 1, bm2Remote = 6, bm3Local = 7, bm3Remote = 2, bm_4_5 = 3;
+		// 1) bm1 - local active bookmark, check that push updates in remote
+		srcRun.exec("hg", "bookmark", bm1);
+		dstRun.exec("hg", "bookmark", "-r", "8", bm1);
+		// 2) bm2 - local points to ancestor of revision remote points to
+		srcRun.exec("hg", "bookmark", "-r", String.valueOf(bm2Local), bm2);
+		dstRun.exec("hg", "bookmark", "-r", String.valueOf(bm2Remote), bm2);
+		// 3) bm3 - remote points to ancestor of revision local one points to   
+		srcRun.exec("hg", "bookmark", "-r", String.valueOf(bm3Local), bm3);
+		dstRun.exec("hg", "bookmark", "-r", String.valueOf(bm3Remote), bm3);
+		// 4) bm4 - remote bookmark, not known locally
+		dstRun.exec("hg", "bookmark", "-r", String.valueOf(bm_4_5), bm4);
+		// 5) bm5 - local bookmark, not known remotely
+		srcRun.exec("hg", "bookmark", "-r", String.valueOf(bm_4_5), bm5);
+		//
+		HgServer server = new HgServer().start(dstRepoLoc);
+		try {
+			final HgLookup hgLookup = new HgLookup();
+			final HgRepository srcRepo = hgLookup.detect(srcRepoLoc);
+			final HgRemoteRepository dstRemote = hgLookup.detect(server.getURL());
+			RepoUtils.modifyFileAppend(f1, "change1");
+			final HgCommitCommand commitCmd = new HgCommitCommand(srcRepo).message("Commit 1");
+			assertTrue(commitCmd.execute().isOk());
+			assertEquals(bm1, srcRepo.getBookmarks().getActiveBookmarkName());
+			assertEquals(commitCmd.getCommittedRevision(), srcRepo.getBookmarks().getRevision(bm1));
+			//
+			new HgPushCommand(srcRepo).destination(dstRemote).execute();
+			Thread.sleep(300); // let the server perform the update
+			//
+			HgBookmarks srcBookmarks = srcRepo.getBookmarks();
+			final HgChangelog srcClog = srcRepo.getChangelog();
+			// first, check local bookmarks are intact
+			errorCollector.assertEquals(srcClog.getRevision(bm2Local), srcBookmarks.getRevision(bm2));
+			errorCollector.assertEquals(srcClog.getRevision(bm3Local), srcBookmarks.getRevision(bm3));
+			errorCollector.assertEquals(null, srcBookmarks.getRevision(bm4));
+			errorCollector.assertEquals(srcClog.getRevision(bm_4_5), srcBookmarks.getRevision(bm5));
+			// now, check remote bookmarks were touched
+			HgRepository dstRepo = hgLookup.detect(dstRepoLoc);
+			HgBookmarks dstBookmarks = dstRepo.getBookmarks();
+			final HgChangelog dstClog = dstRepo.getChangelog();
+			// bm1 changed and points to newly pushed commit.
+			// if the test fails (bm1 points to r8), chances are server didn't manage to update
+			// bookmarks yet (there's Thread.sleep() above to give it a chance).
+			errorCollector.assertEquals(commitCmd.getCommittedRevision(), dstBookmarks.getRevision(bm1));
+			// bm2 didn't change
+			errorCollector.assertEquals(dstClog.getRevision(bm2Remote), dstBookmarks.getRevision(bm2));
+			// bm3 did change, now points to value we've got in srcRepo
+			errorCollector.assertEquals(srcClog.getRevision(bm3Local), dstBookmarks.getRevision(bm3));
+			// bm4 is not affected
+			errorCollector.assertEquals(dstClog.getRevision(bm_4_5), dstBookmarks.getRevision(bm4));
+			// bm5 is not known remotely
+			errorCollector.assertEquals(null, dstBookmarks.getRevision(bm5));
+		} finally {
+			server.stop();
+		}
 	}
 
 
@@ -149,6 +392,12 @@
 
 	static class HgServer {
 		private Process serverProcess;
+		private boolean publish = true;
+		
+		public HgServer publishing(boolean pub) {
+			publish = pub;
+			return this;
+		}
 
 		public HgServer start(File dir) throws IOException, InterruptedException {
 			if (serverProcess != null) {
@@ -164,6 +413,10 @@
 			cmdline.add("server.validate=True");
 			cmdline.add("--config");
 			cmdline.add(String.format("web.port=%d", port()));
+			if (!publish) {
+				cmdline.add("--config");
+				cmdline.add("phases.publish=False");
+			}
 			cmdline.add("serve");
 			serverProcess = new ProcessBuilder(cmdline).directory(dir).start();
 			Thread.sleep(500);