using System; using System.Collections.Generic; using Db4objects.Db4o.Ext; using Moq; using NUnit.Framework; namespace Db4OSeries { [TestFixture] public class TestLockExtensions { private Mock dbMock; [SetUp] public void Setup() { dbMock = new Mock(); dbMock.Setup(db => db.Ext()).Returns(dbMock.Object); } [Test] public void ArgExceptionOnLockingNulls() { Assert.Throws(typeof (ArgumentException), () => dbMock.Object.LockObjects(new TestObject(), null)); } [Test] public void ArgExceptionOnUnLockingNulls() { Assert.Throws(typeof (ArgumentException), () => dbMock.Object.UnlockObjects(new TestObject(), null)); } [Test] public void FailsIfTryLockNonPersistedObject() { var objToLock = new TestObject(); SetupGetID(objToLock, 0); Assert.Throws(typeof (ArgumentException), () => dbMock.Object.LockObjects(objToLock)); } [Test] public void FailsIfTryUnLockNonPersistedObject() { var objToLock = new TestObject(); SetupGetID(objToLock, 0); Assert.Throws(typeof (ArgumentException), () => dbMock.Object.UnlockObjects(objToLock)); } [Test] public void LockNoObjects() { dbMock.Object.LockObjects(); dbMock.Verify(); } [Test] public void UnLockNoObjects() { dbMock.Object.UnlockObjects(); dbMock.Verify(); } [Test] public void ExpectLockSingle() { var objToLock = new TestObject(); SetupGetID(objToLock, 1); SetupSetSemaphore(1, true); var couldLock = dbMock.Object.LockObjects(objToLock); Assert.IsTrue(couldLock); VerifyAquireLock(1); } [Test] public void ExpectUnLockSingle() { var objToLock = new TestObject(); SetupGetID(objToLock, 1); dbMock.Object.UnlockObjects(objToLock); VerifyReleaseLock(1); } [Test] public void ExpectMultipleLocks() { var objToLock1 = new TestObject(); var objToLock2 = new TestObject(); var objToLock3 = new TestObject(); SetupGetID(objToLock1, 1); SetupGetID(objToLock2, 2); SetupGetID(objToLock3, 3); SetupSetSemaphore(1, true); SetupSetSemaphore(2, true); SetupSetSemaphore(3, true); var couldLock = dbMock.Object.LockObjects(objToLock1, objToLock2, objToLock3); Assert.IsTrue(couldLock); VerifyAquireLock(1); VerifyAquireLock(2); VerifyAquireLock(3); } [Test] public void ExpectUnLockMultiple() { var objToLock1 = new TestObject(); var objToLock2 = new TestObject(); var objToLock3 = new TestObject(); SetupGetID(objToLock1, 1); SetupGetID(objToLock2, 2); SetupGetID(objToLock3, 3); dbMock.Object.UnlockObjects(objToLock1, objToLock2, objToLock3); VerifyReleaseLock(1); VerifyReleaseLock(2); VerifyReleaseLock(3); } [Test] public void ExpectOrderingOfLocks() { var objToLock1 = new TestObject(); var objToLock2 = new TestObject(); var objToLock3 = new TestObject(); SetupGetID(objToLock1, 100); SetupGetID(objToLock2, 10); SetupGetID(objToLock3, 2); var listOfIdsToCheckOrder = new List(); ExpectSemaphoresSet(listOfIdsToCheckOrder); var couldLock = dbMock.Object.LockObjects(objToLock1, objToLock2, objToLock3); Assert.IsTrue(couldLock); Assert.AreEqual(3, listOfIdsToCheckOrder.Count); Assert.AreEqual(NameOfLock(2), listOfIdsToCheckOrder[0]); Assert.AreEqual(NameOfLock(10), listOfIdsToCheckOrder[1]); Assert.AreEqual(NameOfLock(100), listOfIdsToCheckOrder[2]); } [Test] public void ExpectOrderingOfUnLocks() { var objToLock1 = new TestObject(); var objToLock2 = new TestObject(); var objToLock3 = new TestObject(); SetupGetID(objToLock1, 2); SetupGetID(objToLock2, 10); SetupGetID(objToLock3, 100); var listOfIdsToCheckOrder = new List(); ExpectSemaphoresRelease(listOfIdsToCheckOrder); dbMock.Object.UnlockObjects(objToLock1, objToLock2, objToLock3); Assert.AreEqual(3, listOfIdsToCheckOrder.Count); Assert.AreEqual(NameOfLock(100), listOfIdsToCheckOrder[0]); Assert.AreEqual(NameOfLock(10), listOfIdsToCheckOrder[1]); Assert.AreEqual(NameOfLock(2), listOfIdsToCheckOrder[2]); } [Test] public void ExpectFalseIfCannotLock() { var objToLock = new TestObject(); SetupGetID(objToLock, 42); SetupSetSemaphore(42, false); var couldLock = dbMock.Object.LockObjects(objToLock); Assert.IsFalse(couldLock); } [Test] public void ExpectUnlockIfCannotGetAllLocks() { var objToLock1 = new TestObject(); var objToLock2 = new TestObject(); SetupGetID(objToLock1, 42); SetupGetID(objToLock2, 43); SetupSetSemaphore(42, true); SetupSetSemaphore(43, false); var couldLock = dbMock.Object.LockObjects(objToLock1, objToLock2); Assert.IsFalse(couldLock); VerifyAquireLock(42); VerifyAquireLock(43); VerifyReleaseLock(42); } [Test] public void WithLockHoldsSemaphores() { var testObj = new TestObject(); SetupGetID(testObj, 1); SetupSetSemaphore(1, true); var lockHold = false; dbMock.Setup(db => db.SetSemaphore(NameOfLock(1), LockExtensions.TimeOut)) .Returns(true).Callback((name, timeOut) => lockHold = true); var expectResult = dbMock.Object.WithLock(testObj).Execute(() => { Assert.IsTrue(lockHold); return 42; }); VerifyReleaseLock(1); Assert.AreEqual(42, expectResult); } [Test] public void WithLockReleasesOnException() { var testObj = new TestObject(); SetupGetID(testObj, 1); SetupSetSemaphore(1, true); Assert.Throws(typeof (Exception), () => dbMock.Object.WithLock(testObj).Execute( () => { throw new Exception("Expect Me"); }), "Expect Me"); VerifyAquireLock(1); VerifyReleaseLock(1); } [Test] public void WithLockThrowsIfCannotGetLock() { var testObj = new TestObject(); SetupGetID(testObj, 1); SetupSetSemaphore(1, false); Assert.Throws(typeof (InvalidOperationException), () => dbMock.Object.WithLock(testObj).Execute( () => Assert.Fail("This call isn't expected"))); VerifyAquireLock(1); VerifyReleaseLock(1); } private void ExpectSemaphoresSet(ICollection listOfIdsToCheckOrder) { dbMock.Setup(db => db.SetSemaphore(It.IsAny(), LockExtensions.TimeOut)) .Returns(true).Callback((name, timeOut) => listOfIdsToCheckOrder.Add(name)); } private void ExpectSemaphoresRelease(ICollection listOfIdsToCheckOrder) { dbMock.Setup(db => db.ReleaseSemaphore(It.IsAny())) .Callback(listOfIdsToCheckOrder.Add); } private void VerifyAquireLock(long expectedId) { dbMock.Verify( db => db.SetSemaphore(LockExtensions.LockPrefix + expectedId, LockExtensions.TimeOut)); } private void VerifyReleaseLock(long expectedId) { dbMock.Verify(db => db.ReleaseSemaphore(LockExtensions.LockPrefix + expectedId)); } private void SetupSetSemaphore(long expectedId, bool lockSucessfull) { dbMock.Setup(db => db.SetSemaphore(NameOfLock(expectedId), LockExtensions.TimeOut)) .Returns(lockSucessfull); } private static string NameOfLock(long id) { return LockExtensions.LockPrefix + id; } private void SetupGetID(TestObject objToLock, long idToReturn) { dbMock.Setup(db => db.GetID(objToLock)).Returns(idToReturn); } public class TestObject { } } }