Click here to Skip to main content
15,891,738 members
Articles / Programming Languages / C#

ObjectLounge - An Object-Oriented Database Framework

Rate me:
Please Sign up or sign in to vote.
4.07/5 (8 votes)
30 Jul 2009LGPL310 min read 43.9K   425   45  
Host your Domain Models "Out Of The Box" + No storage or schema needed + Transactions on Domain Models + Validation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Technewlogic.ObjectLounge.Test.Model;
using System.Threading;
using NUnit.Framework;

namespace Technewlogic.ObjectLounge.Test
{
	public class D_Transactions_IsolationTests : BaseTest
	{
		[Test]
		public void ReadCommittedValue_Primitive()
		{
			Customer sundk = _context.Customers.Single(c => c.Name == Customer.SKName);
			int originalAccount = sundk.AccountNumber;
			int newAccount = 12349;

			Exception exception = null;
			AutoResetEvent evt1 = new AutoResetEvent(false);
			AutoResetEvent evt2 = new AutoResetEvent(false);
			AutoResetEvent evt3 = new AutoResetEvent(false);
			AutoResetEvent endOfB = new AutoResetEvent(false);

			Action a = () =>
			{
				var ta = _engine.BeginTransaction();
				try
				{
					sundk.AccountNumber = newAccount;

					Assert.AreEqual(newAccount, sundk.AccountNumber);

					// start the other thread
					evt1.Set();

					// the other thread should read the "original" value...

					evt2.WaitOne();

					// now we commit the changes
					ta.Commit();

					evt3.Set();

					// the other thread should read the committed value

					Console.WriteLine("End Thread A");
				}
				catch (Exception ex)
				{
					exception = ex;
				}
			};

			Action b = () =>
			{
				try
				{
					// wait for the other thread to change the value
					evt1.WaitOne();

					Assert.AreEqual(originalAccount, sundk.AccountNumber);

					evt2.Set();

					// let the other thread continue and commit

					evt3.WaitOne();

					Assert.AreEqual(newAccount, sundk.AccountNumber);

					Console.WriteLine("End Thread B");

					endOfB.Set();
				}
				catch (Exception ex)
				{
					exception = ex;
				}
			};

			a.BeginInvoke(null, null);
			b.BeginInvoke(null, null);

			if (!endOfB.WaitOne(2000, false))
				throw exception;

			Console.WriteLine("End Main Thread");
		}

		[Test]
		public void ReadCommittedValue_Composition()
		{
			Customer sundk = GetOldCustomer();
			Order cmms = GetOldOrder();
			Customer pizzaInder = _context.Customers.Single(c => c.Name == Customer.PizzaInderName);
			Order billingSystem = pizzaInder.Orders.Single(o => o.OrderID == Order.BillingSystemID);
			Order newOrder = GetNewOrder();

			Exception exception = null;
			AutoResetEvent evt1 = new AutoResetEvent(false);
			AutoResetEvent evt2 = new AutoResetEvent(false);
			AutoResetEvent evt3 = new AutoResetEvent(false);
			AutoResetEvent endOfB = new AutoResetEvent(false);

			Action a = () =>
			{
				var ta = _engine.BeginTransaction();
				try
				{
					sundk.Orders.Add(billingSystem);
					sundk.Orders.Add(newOrder);

					Assert.IsTrue(sundk.Orders.Contains(billingSystem));
					Assert.IsTrue(sundk.Orders.Contains(newOrder));
					Assert.IsFalse(pizzaInder.Orders.Contains(billingSystem));
					Assert.AreEqual(sundk, billingSystem.Customer);
					Assert.AreEqual(sundk, newOrder.Customer);

					// start the other thread
					evt1.Set();

					// the other thread should read the "original" value...

					evt2.WaitOne();

					// now we commit the changes
					ta.Commit();

					Assert.IsTrue(sundk.Orders.Contains(billingSystem));
					Assert.IsTrue(sundk.Orders.Contains(newOrder));
					Assert.IsFalse(pizzaInder.Orders.Contains(billingSystem));
					Assert.AreEqual(sundk, billingSystem.Customer);
					Assert.AreEqual(sundk, newOrder.Customer);

					evt3.Set();

					// the other thread should read the committed value

					Console.WriteLine("End Thread A");
				}
				catch (Exception ex)
				{
					exception = ex;
				}
			};

			Action b = () =>
			{
				try
				{
					// wait for the other thread to change the value
					evt1.WaitOne();

					Assert.IsFalse(sundk.Orders.Contains(billingSystem));
					Assert.IsFalse(sundk.Orders.Contains(newOrder));
					Assert.IsTrue(pizzaInder.Orders.Contains(billingSystem));
					Assert.AreEqual(pizzaInder, billingSystem.Customer);
					Assert.AreNotEqual(sundk, newOrder.Customer);

					evt2.Set();

					// let the other thread continue and commit

					evt3.WaitOne();

					Assert.IsTrue(sundk.Orders.Contains(billingSystem));
					Assert.IsTrue(sundk.Orders.Contains(newOrder));
					Assert.IsFalse(pizzaInder.Orders.Contains(billingSystem));
					Assert.AreEqual(sundk, billingSystem.Customer);
					Assert.AreEqual(sundk, newOrder.Customer);

					Console.WriteLine("End Thread B");

					endOfB.Set();
				}
				catch (Exception ex)
				{
					exception = ex;
				}
			};

			a.BeginInvoke(null, null);
			b.BeginInvoke(null, null);

			if (!endOfB.WaitOne(2000, false))
				throw exception;

			Console.WriteLine("End Main Thread");
		}

		/// <summary>
		/// Two concurrent transactions want to write same and different entities.
		/// Result: The transactions are queued.
		/// </summary>
		[Test]
		public void Write_Serialized()
		{
			DateTime startTime = DateTime.Now.AddDays(-1);
			DateTime endRead = startTime.AddDays(-1);
			DateTime endWriteA = endRead.AddDays(-1);
			DateTime endWriteB = endWriteA.AddDays(-1);
			DateTime endWriteC = endWriteB.AddDays(-1);

			ManualResetEvent writeAStarted = new ManualResetEvent(false);
			AutoResetEvent endOfWriteC = new AutoResetEvent(false);

			Action writeA = () =>
			{
				_engine.ExecuteTransaction(() =>
					{
						var sundk = GetOldCustomer();
						sundk.AccountNumber = 12349;

						// now this transaction is the writing transaction, so we can start the other concurrent transaction
						writeAStarted.Set();
						Thread.Sleep(2000);

						endWriteA = DateTime.Now;
					});
			};

			Action read = () =>
			{
				writeAStarted.WaitOne();
				var sundk = GetOldCustomer();

				Assert.AreEqual(1, sundk.AccountNumber);

				endRead = DateTime.Now;
			};

			Action writeB = () =>
			{
				_engine.ExecuteTransaction(() =>
				{
					writeAStarted.WaitOne();

					var sundk = GetOldCustomer();
					sundk.AccountNumber = 345;

					endWriteB = DateTime.Now;
				});
			};

			Action writeC = () =>
			{
				_engine.ExecuteTransaction(() =>
				{
					writeAStarted.WaitOne();
					// wait so that the B is the next one in the queue
					Thread.Sleep(500);

					var sundk = GetOldCustomer();
					sundk.AccountNumber = 5500;

					endWriteC = DateTime.Now;
				});

				endOfWriteC.Set();
			};

			writeA.BeginInvoke(null, null);
			read.BeginInvoke(null, null);
			writeB.BeginInvoke(null, null);
			writeC.BeginInvoke(null, null);

			if (!endOfWriteC.WaitOne(5000, false))
				throw new Exception();

			Assert.GreaterOrEqual(endRead, startTime);
			Assert.GreaterOrEqual(endWriteA, endRead);
			Assert.GreaterOrEqual(endWriteB, endWriteA);
			Assert.GreaterOrEqual(endWriteC, endWriteB);

			var check = GetOldCustomer();
			Assert.AreEqual(5500, check.AccountNumber);
		}

		// TODO: Read only / Write
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Software Developer (Senior) www.technewlogic.de
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions