package com.exedio.cope;

import java.text.SimpleDateFormat;
import java.util.Date;

public class TransactionOnlyTest extends AbstractLibTest
{
	
	public TransactionOnlyTest()
	{
		super(CacheIsolationTest.MODEL);
	}
	
	public void testNesting()
	{
		assertEquals( true, model.hasCurrentTransaction() );
		final Transaction tx = model.getCurrentTransaction();
		try
		{
			model.startTransaction("nested");
			fail();
		}
		catch(IllegalStateException e)
		{
			assertEquals("tried to start a new transaction with name >nested<, but there is already a transaction CT." + model.getCurrentTransaction().getID() + " with name >CopeTest< started on " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS").format(tx.getStartDate()) + " bound to current thread", e.getMessage());
		}
		assertEquals( tx, model.getCurrentTransaction() );
		try
		{
			model.startTransaction(null);
			fail();
		}
		catch(IllegalStateException e)
		{
			assertEquals("tried to start a new transaction without a name, but there is already a transaction CT." + model.getCurrentTransaction().getID() + " with name >CopeTest< started on " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS").format(tx.getStartDate()) + " bound to current thread", e.getMessage());
		}
		assertEquals(tx, model.getCurrentTransaction());
	}
	
	public void testJoinClosed()
	{
		Transaction tx = model.getCurrentTransaction();
		model.commit();
		try
		{
			model.joinTransaction( tx );
			fail();
		}
		catch(IllegalStateException e)
		{
			assertEquals( "cannot bind to closed transaction", e.getMessage() );
		}
		assertEquals( false, model.hasCurrentTransaction() );
		model.startTransaction("just for tearDown");
		assertEquals( "just for tearDown", model.getCurrentTransaction().getName() );
	}
	
	static class IllegalStateExceptionReference
	{
		IllegalStateException e = null;
	}
	
	public void testJoinMultiple() throws InterruptedException
	{
		final Transaction tx = model.getCurrentTransaction();
		final IllegalStateExceptionReference rer = new IllegalStateExceptionReference();
		
		final Thread t2 = new Thread(new Runnable(){
			public void run()
			{
				try
				{
					model.joinTransaction(tx);
				}
				catch(IllegalStateException e)
				{
					rer.e = e;
				}
			}
		});
		t2.start();
		t2.join();
		assertNotNull(rer.e);
		assertEquals("transaction already bound to other thread: " + Thread.currentThread().getId(), rer.e.getMessage());
	}
	
	public void testTransactionLifecycle()
	{
		final Transaction copeTest = model.getCurrentTransaction();
		assertContains( copeTest, model.getOpenTransactions() );
		assertUnmodifiable( model.getOpenTransactions() );
		assertEquals( false, copeTest.isClosed() );
		assertCurrentTransaction( copeTest );
		
		model.leaveTransaction();
		assertContains( copeTest, model.getOpenTransactions() );
		assertEquals( false, copeTest.isClosed() );
		assertCurrentTransaction( null );
		
		final Date before = new Date();
		final Transaction tx1 = model.startTransaction( "tx1" );
		final Date after = new Date();
		assertContains( copeTest, tx1, model.getOpenTransactions() );
		assertEquals(copeTest.getID()+1, tx1.getID());
		assertEquals("tx1", tx1.getName());
		assertWithin(before, after, tx1.getStartDate());
		assertEquals( false, copeTest.isClosed() );
		assertEquals( false, tx1.isClosed() );
		assertCurrentTransaction( tx1 );
		
		model.leaveTransaction();
		assertContains( copeTest, tx1, model.getOpenTransactions() );
		assertEquals( false, copeTest.isClosed() );
		assertEquals( false, tx1.isClosed() );
		assertCurrentTransaction( null );
		
		model.joinTransaction( copeTest );
		assertContains( copeTest, tx1, model.getOpenTransactions() );
		assertEquals( false, copeTest.isClosed() );
		assertEquals( false, tx1.isClosed() );
		assertCurrentTransaction( copeTest );
		
		model.commit();
		assertContains( tx1, model.getOpenTransactions() );
		assertEquals( true, copeTest.isClosed() );
		assertEquals( false, tx1.isClosed() );
		assertCurrentTransaction( null );
		
		model.joinTransaction( tx1 );
		assertContains( tx1, model.getOpenTransactions() );
		assertEquals( true, copeTest.isClosed() );
		assertEquals( false, tx1.isClosed() );
		assertCurrentTransaction( tx1 );
		
		model.rollback();
		assertContains( model.getOpenTransactions() );
		assertEquals( true, copeTest.isClosed() );
		assertEquals( true, tx1.isClosed() );
		assertCurrentTransaction( null );
		
		model.startTransaction( "forTearDown" );
	}
	
	private void assertCurrentTransaction( Transaction tx )
	{
		assertEquals( tx!=null, model.hasCurrentTransaction() );
		if ( tx==null )
		{
			try
			{
				model.getCurrentTransaction();
				fail();
			}
			catch(IllegalStateException e)
			{
				assertEquals( "there is no cope transaction bound to this thread, see Model#startTransaction", e.getMessage() );
			}
		}
		else
		{
			assertEquals( tx, model.getCurrentTransaction() );
		}
	}
}

@@ -460,32 +460,38 @@
 %09%09%09assertEquals(
+%0A%09%09%09%09%09
 %22tried to start 
@@ -528,16 +528,26 @@
 ested%3C, 
+%22 +%0A%09%09%09%09%09%22
 but ther
@@ -611,33 +611,38 @@
 tion().getID() +
- 
+%0A%09%09%09%09%09
 %22 with name %3ECop
@@ -640,32 +640,42 @@
 name %3ECopeTest%3C 
+%22 +%0A%09%09%09%09%09%22
 started on %22 + n
@@ -740,33 +740,38 @@
 etStartDate()) +
- 
+%0A%09%09%09%09%09
 %22 bound to curre
@@ -773,33 +773,38 @@
 current thread%22,
- 
+%0A%09%09%09%09%09
 e.getMessage());
@@ -972,16 +972,22 @@
 tEquals(
+%0A%09%09%09%09%09
 %22tried t
@@ -1028,16 +1028,26 @@
 a name, 
+%22 +%0A%09%09%09%09%09%22
 but ther
@@ -1119,17 +1119,22 @@
 etID() +
- 
+%0A%09%09%09%09%09
 %22 with n
@@ -1148,16 +1148,26 @@
 peTest%3C 
+%22 +%0A%09%09%09%09%09%22
 started 
@@ -1248,17 +1248,22 @@
 ate()) +
- 
+%0A%09%09%09%09%09
 %22 bound 
@@ -1281,17 +1281,22 @@
 thread%22,
- 
+%0A%09%09%09%09%09
 e.getMes

format source code