changeset 665:dde18bc7053b v1.2m1

Test Copy-on-Write transactions
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 10 Jul 2013 20:16:37 +0200
parents ae2d439fbed3
children 27a3ddedd6cc
files build.xml src/org/tmatesoft/hg/internal/BasicSessionContext.java src/org/tmatesoft/hg/internal/COWTransaction.java test/org/tmatesoft/hg/test/TestPull.java test/org/tmatesoft/hg/test/TestTransaction.java
diffstat 5 files changed, 115 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/build.xml	Wed Jul 10 19:33:51 2013 +0200
+++ b/build.xml	Wed Jul 10 20:16:37 2013 +0200
@@ -84,6 +84,7 @@
 			<test name="org.tmatesoft.hg.test.TestIntMap" />
 			<test name="org.tmatesoft.hg.test.TestAuxUtilities" />
 			<test name="org.tmatesoft.hg.test.TestConfigFileParser" />
+			<test name="org.tmatesoft.hg.test.TestTransaction" />
 			<test name="org.tmatesoft.hg.test.TestInflaterDataAccess" />
 			<test name="org.tmatesoft.hg.test.TestHistory" />
 			<test name="org.tmatesoft.hg.test.TestManifest" />
--- a/src/org/tmatesoft/hg/internal/BasicSessionContext.java	Wed Jul 10 19:33:51 2013 +0200
+++ b/src/org/tmatesoft/hg/internal/BasicSessionContext.java	Wed Jul 10 20:16:37 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012 TMate Software Ltd
+ * Copyright (c) 2011-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
@@ -28,7 +28,7 @@
  * @author Artem Tikhomirov
  * @author TMate Software Ltd.
  */
-public class BasicSessionContext extends SessionContext {
+public class BasicSessionContext extends SessionContext implements SessionContext.Source {
 
 	private LogFacility logFacility;
 	private final Map<String, Object> properties;
@@ -68,4 +68,8 @@
 		value = System.getProperty(name);
 		return value == null ? defaultValue : value;
 	}
+
+	public SessionContext getSessionContext() {
+		return this;
+	}
 }
--- a/src/org/tmatesoft/hg/internal/COWTransaction.java	Wed Jul 10 19:33:51 2013 +0200
+++ b/src/org/tmatesoft/hg/internal/COWTransaction.java	Wed Jul 10 20:16:37 2013 +0200
@@ -24,6 +24,7 @@
 
 import org.tmatesoft.hg.core.HgIOException;
 import org.tmatesoft.hg.core.SessionContext;
+import org.tmatesoft.hg.repo.HgInvalidStateException;
 
 /**
  * This transaction strategy makes a copy of original file and breaks origin hard links, if any.
@@ -103,7 +104,9 @@
 	public void commit() throws HgIOException {
 		for (Iterator<RollbackEntry> it = entries.iterator(); it.hasNext();) {
 			RollbackEntry e = it.next();
-			assert e.success;
+			if (!e.success) {
+				throw new HgInvalidStateException(String.format("Attempt to commit transaction without successful clearance of file %s", e.origin));
+			}
 			if (e.failure != null) {
 				throw new HgIOException("Can't close transaction with a failure.", e.failure, e.origin);
 			}
--- a/test/org/tmatesoft/hg/test/TestPull.java	Wed Jul 10 19:33:51 2013 +0200
+++ b/test/org/tmatesoft/hg/test/TestPull.java	Wed Jul 10 20:16:37 2013 +0200
@@ -45,7 +45,6 @@
 import org.tmatesoft.hg.util.Path;
 
 /**
- * FIXME need TestTransaction to check transaction rolback/commit as it's tricky to test transactions as part of pull/push commands
  * @author Artem Tikhomirov
  * @author TMate Software Ltd.
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/org/tmatesoft/hg/test/TestTransaction.java	Wed Jul 10 20:16:37 2013 +0200
@@ -0,0 +1,104 @@
+/*
+ * 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 org.junit.Assert.*;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.tmatesoft.hg.internal.BasicSessionContext;
+import org.tmatesoft.hg.internal.COWTransaction;
+import org.tmatesoft.hg.internal.Transaction;
+
+/**
+ * Check transaction rollback/commit as it's tricky to test transactions as part of pull/push commands
+ * 
+ * @author Artem Tikhomirov
+ * @author TMate Software Ltd.
+ */
+public class TestTransaction {
+
+	@Rule
+	public ErrorCollectorExt errorCollector = new ErrorCollectorExt();
+	
+	@Test
+	public void testCopyOnWriteTransaction() throws Exception {
+		final BasicSessionContext ctx = new BasicSessionContext(null);
+		Transaction.Factory f = new COWTransaction.Factory();
+		File dir = RepoUtils.createEmptyDir("test-transaction-cow");
+		File f1 = new File(dir, "f1");
+		File f2 = new File(dir, "f2");
+		File f3 = new File(dir, "f3");
+		RepoUtils.createFile(f1, "1");
+		assertTrue(f1.exists());
+		assertFalse(f2.exists());
+		assertFalse(f3.exists());
+		//
+		// transaction commit
+		Transaction tr1 = f.create(ctx);
+		File tf1 = tr1.prepare(f1);
+		RepoUtils.modifyFileAppend(tf1, "2");
+		tr1.done(tf1);
+		File tf2 = tr1.prepare(f2);
+		errorCollector.assertTrue(tf2.exists());
+		RepoUtils.modifyFileAppend(tf2, "A");
+		tr1.done(tf2);
+		tr1.commit();
+		errorCollector.assertTrue(f1.isFile());
+		errorCollector.assertTrue(f2.isFile());
+		errorCollector.assertEquals("12", read(f1));
+		errorCollector.assertEquals("A", read(f2));
+		//
+		// transaction rollback
+		assertFalse(f3.exists());
+		Transaction tr2 = f.create(ctx);
+		tf1 = tr2.prepare(f1);
+		RepoUtils.modifyFileAppend(tf1, "3");
+		tr2.done(tf1);
+		errorCollector.assertEquals("123", read(tf1));
+		tf2 = tr2.prepare(f2);
+		RepoUtils.modifyFileAppend(tf2, "B");
+		tr2.done(tf2);
+		errorCollector.assertEquals("AB", read(tf2));
+		File tf3 = tr2.prepare(f3);
+		errorCollector.assertTrue(tf3.exists());
+		RepoUtils.modifyFileAppend(tf3, "!");
+		tr2.done(tf3);
+		errorCollector.assertEquals("!", read(tf3));
+		tr2.rollback();
+		errorCollector.assertTrue(f1.isFile());
+		errorCollector.assertTrue(f2.isFile());
+		errorCollector.assertFalse(f3.isFile());
+		errorCollector.assertEquals("12", read(f1));
+		errorCollector.assertEquals("A", read(f2));
+	}
+
+	String read(File f) throws IOException {
+		StringBuilder sb = new StringBuilder();
+		FileReader fr = new FileReader(f);
+		int ch;
+		while ((ch = fr.read()) != -1) {
+			sb.append((char) ch);
+		}
+		fr.close();
+		return sb.toString();
+	}
+}