Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

1351 lines
37 KiB
C#

//
// Tests for combination of volatile & durable resource manangers
//
// Author:
// Ankit Jain <JAnkit@novell.com>
//
// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
//
// This define is needed when running this tests under MS.NET as right
// now we always wrap thrown exceptions insde TransactionAbortedException.
// However, MS implementation in some cases, directly relays the exception
// thrown by RM without wrapping it. Not sure if this is a bug or a feature.
//#define MS_EXCEPTIONS_BEHAVIOR
using System;
using System.Transactions;
using NUnit.Framework;
using NUnit.Framework.Constraints;
namespace MonoTests.System.Transactions {
[TestFixture]
public class EnlistTest {
#region Vol1_Dur0
/* Single volatile resource, SPC happens */
[Test]
public void Vol1_Dur0 ()
{
IntResourceManager irm = new IntResourceManager (1);
irm.UseSingle = true;
using (TransactionScope scope = new TransactionScope ()) {
irm.Value = 2;
scope.Complete ();
}
irm.CheckSPC ("irm");
}
[Test]
public void Vol1_Dur0_2PC ()
{
IntResourceManager irm = new IntResourceManager (1);
using (TransactionScope scope = new TransactionScope ()) {
irm.Value = 2;
scope.Complete ();
}
irm.Check2PC ("irm");
}
/* Single volatile resource, SPC happens */
[Test]
public void Vol1_Dur0_Fail1 ()
{
IntResourceManager irm = new IntResourceManager (1);
irm.UseSingle = true;
using (TransactionScope scope = new TransactionScope ()) {
irm.Value = 2;
/* Not completing this..
scope.Complete ();*/
}
irm.Check ( 0, 0, 0, 1, 0, 0, 0, "irm" );
}
[Test]
[ExpectedException ( typeof ( TransactionAbortedException ) )]
public void Vol1_Dur0_Fail2 ()
{
IntResourceManager irm = new IntResourceManager (1);
irm.FailPrepare = true;
using (TransactionScope scope = new TransactionScope ()) {
irm.Value = 2;
scope.Complete ();
}
}
[Test]
[ExpectedException ( typeof ( TransactionAbortedException ) )]
public void Vol1_Dur0_Fail3 ()
{
IntResourceManager irm = new IntResourceManager (1);
irm.UseSingle = true;
irm.FailSPC = true;
using (TransactionScope scope = new TransactionScope ()) {
irm.Value = 2;
scope.Complete ();
}
}
#endregion
#region Vol2_Dur0
/* >1 volatile, 2PC */
[Test]
public void Vol2_Dur0_SPC ()
{
IntResourceManager irm = new IntResourceManager (1);
IntResourceManager irm2 = new IntResourceManager (3);
irm.UseSingle = true;
irm2.UseSingle = true;
using (TransactionScope scope = new TransactionScope ()) {
irm.Value = 2;
irm2.Value = 6;
scope.Complete ();
}
irm.Check2PC ( "irm" );
irm2.Check2PC ( "irm2" );
}
#endregion
#region Vol0_Dur1
/* 1 durable */
[Test]
public void Vol0_Dur1 ()
{
IntResourceManager irm = new IntResourceManager (1);
irm.Type = ResourceManagerType.Durable;
irm.UseSingle = true;
using (TransactionScope scope = new TransactionScope ()) {
irm.Value = 2;
scope.Complete ();
}
irm.CheckSPC ( "irm" );
}
/* We support only 1 durable with 2PC
* On .net, this becomes a distributed transaction
*/
[Test]
[Category ("NotWorking")]
public void Vol0_Dur1_2PC ()
{
IntResourceManager irm = new IntResourceManager (1);
/* Durable resource enlisted with a IEnlistedNotification
* object
*/
irm.Type = ResourceManagerType.Durable;
using (TransactionScope scope = new TransactionScope ()) {
irm.Value = 2;
scope.Complete ();
}
}
[Test]
public void Vol0_Dur1_Fail ()
{
IntResourceManager irm = new IntResourceManager ( 1 );
/* Durable resource enlisted with a IEnlistedNotification
* object
*/
irm.Type = ResourceManagerType.Durable;
irm.FailSPC = true;
irm.UseSingle = true;
try {
using (TransactionScope scope = new TransactionScope ()) {
irm.Value = 2;
scope.Complete ();
}
}
catch (TransactionAbortedException) {
irm.Check ( 1, 0, 0, 0, 0, 0, 0, "irm" );
return;
}
Assert.Fail ();
}
#endregion
#region Vol2_Dur1
/* >1vol + 1 durable */
[Test]
public void Vol2_Dur1 ()
{
IntResourceManager [] irm = new IntResourceManager [4];
irm [0] = new IntResourceManager ( 1 );
irm [1] = new IntResourceManager ( 3 );
irm [2] = new IntResourceManager ( 5 );
irm [3] = new IntResourceManager ( 7 );
irm [0].Type = ResourceManagerType.Durable;
for ( int i = 0; i < 4; i++ )
irm [i].UseSingle = true;
using (TransactionScope scope = new TransactionScope ()) {
irm [0].Value = 2;
irm [1].Value = 6;
irm [2].Value = 10;
irm [3].Value = 14;
scope.Complete ();
}
irm [0].CheckSPC ( "irm [0]" );
/* Volatile RMs get 2PC */
for (int i = 1; i < 4; i++)
irm [i].Check2PC ( "irm [" + i + "]" );
}
/* >1vol + 1 durable
* Durable fails SPC
*/
[Test]
public void Vol2_Dur1_Fail1 ()
{
IntResourceManager [] irm = new IntResourceManager [4];
irm [0] = new IntResourceManager (1);
irm [1] = new IntResourceManager (3);
irm [2] = new IntResourceManager (5);
irm [3] = new IntResourceManager (7);
irm [0].Type = ResourceManagerType.Durable;
irm [0].FailSPC = true;
for ( int i = 0; i < 4; i++ )
irm [i].UseSingle = true;
/* Durable RM irm[0] does Abort on SPC, so
* all volatile RMs get Rollback */
try {
using (TransactionScope scope = new TransactionScope ()) {
irm [0].Value = 2;
irm [1].Value = 6;
irm [2].Value = 10;
irm [3].Value = 14;
scope.Complete ();
}
}
catch (TransactionAbortedException) {
irm [0].CheckSPC ( "irm [0]" );
/* Volatile RMs get 2PC Prepare, and then get rolled back */
for (int i = 1; i < 4; i++)
irm [i].Check ( 0, 1, 0, 1, 0, 0, 0, "irm [" + i + "]" );
return;
}
Assert.Fail();
}
/* >1vol + 1 durable
* durable doesn't complete SPC
*/
[Test]
[Ignore ( "Correct this test, it should throw TimeOutException or something" )]
public void Vol2_Dur1_Fail2 ()
{
TransactionAbortedException exception = null;
IntResourceManager [] irm = new IntResourceManager [4];
irm [0] = new IntResourceManager (1);
irm [1] = new IntResourceManager (3);
irm [2] = new IntResourceManager (5);
irm [3] = new IntResourceManager (7);
irm [0].Type = ResourceManagerType.Durable;
irm [0].IgnoreSPC = true;
for ( int i = 0; i < 4; i++ )
irm [i].UseSingle = true;
/* Durable RM irm[2] does on SPC, so
* all volatile RMs get Rollback */
try {
using (TransactionScope scope = new TransactionScope ( TransactionScopeOption.Required, new TimeSpan ( 0, 0, 5 ) )) {
irm [0].Value = 2;
irm [1].Value = 6;
irm [2].Value = 10;
irm [3].Value = 14;
scope.Complete ();
}
}
catch (TransactionAbortedException ex) {
irm [0].CheckSPC ( "irm [0]" );
/* Volatile RMs get 2PC Prepare, and then get rolled back */
for (int i = 1; i < 4; i++)
irm [i].Check ( 0, 1, 0, 1, 0, 0, 0, "irm [" + i + "]" );
exception = ex;
}
Assert.IsNotNull(exception, "Expected TransactionAbortedException not thrown!");
Assert.IsNotNull(exception.InnerException, "TransactionAbortedException has no inner exception!");
Assert.AreEqual(typeof(TimeoutException), exception.InnerException.GetType());
}
/* Same as Vol2_Dur1_Fail2, but with a volatile manager timming out */
[Test]
[Ignore ( "Correct this test, it should throw TimeOutException or something" )]
public void Vol2_Dur1_Fail2b()
{
TransactionAbortedException exception = null;
IntResourceManager[] irm = new IntResourceManager[4];
irm[0] = new IntResourceManager(1);
irm[1] = new IntResourceManager(3);
irm[2] = new IntResourceManager(5);
irm[3] = new IntResourceManager(7);
irm[0].IgnoreSPC = true;
irm[1].Type = ResourceManagerType.Durable;
for (int i = 0; i < 4; i++)
irm[i].UseSingle = true;
/* Durable RM irm[2] does on SPC, so
* all volatile RMs get Rollback */
try
{
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 0, 5)))
{
irm[0].Value = 2;
irm[1].Value = 6;
irm[2].Value = 10;
irm[3].Value = 14;
scope.Complete();
}
}
catch (TransactionAbortedException ex)
{
irm[0].CheckSPC("irm [0]");
/* Volatile RMs get 2PC Prepare, and then get rolled back */
for (int i = 1; i < 4; i++)
irm[i].Check(0, 1, 0, 1, 0, 0, 0, "irm [" + i + "]");
exception = ex;
}
Assert.IsNotNull(exception, "Expected TransactionAbortedException not thrown!");
Assert.IsNotNull(exception.InnerException, "TransactionAbortedException has no inner exception!");
Assert.AreEqual(typeof(TimeoutException), exception.InnerException.GetType());
}
/* >1vol + 1 durable
* Volatile fails Prepare
*/
[Test]
public void Vol2_Dur1_Fail3 ()
{
IntResourceManager [] irm = new IntResourceManager [4];
irm [0] = new IntResourceManager ( 1 );
irm [1] = new IntResourceManager ( 3 );
irm [2] = new IntResourceManager ( 5 );
irm [3] = new IntResourceManager ( 7 );
irm [0].Type = ResourceManagerType.Durable;
irm [2].FailPrepare = true;
for ( int i = 0; i < 4; i++ )
irm [i].UseSingle = true;
/* Durable RM irm[2] does on SPC, so
* all volatile RMs get Rollback */
try {
using (TransactionScope scope = new TransactionScope ()) {
irm [0].Value = 2;
irm [1].Value = 6;
irm [2].Value = 10;
irm [3].Value = 14;
scope.Complete ();
}
}
catch (TransactionAbortedException) {
irm [0].Check ( 0, 0, 0, 1, 0, 0, 0, "irm [0]");
/* irm [1] & [2] get prepare,
* [2] -> ForceRollback,
* [1] & [3] get rollback,
* [0](durable) gets rollback */
irm [1].Check ( 0, 1, 0, 1, 0, 0, 0, "irm [1]" );
irm [2].Check ( 0, 1, 0, 0, 0, 0, 0, "irm [2]" );
irm [3].Check ( 0, 0, 0, 1, 0, 0, 0, "irm [3]" );
return;
}
Assert.Fail ( "Expected TransactionAbortedException" );
}
[Test]
public void Vol2_Dur1_Fail4 ()
{
IntResourceManager [] irm = new IntResourceManager [2];
irm [0] = new IntResourceManager ( 1 );
irm [1] = new IntResourceManager ( 3 );
irm [0].Type = ResourceManagerType.Durable;
irm [0].FailSPC = true;
irm [0].FailWithException = true;
for ( int i = 0; i < 2; i++ )
irm [i].UseSingle = true;
/* Durable RM irm[2] does on SPC, so
* all volatile RMs get Rollback */
try {
using ( TransactionScope scope = new TransactionScope () ) {
irm [0].Value = 2;
irm [1].Value = 6;
scope.Complete ();
}
}
catch ( TransactionAbortedException e) {
Assert.IsNotNull ( e.InnerException, "Expected e.InnerException == NotSupportedException, but got None");
Assert.AreEqual ( typeof ( NotSupportedException ), e.InnerException.GetType (), "Expected e.InnerException == NotSupportedException, but got " + e.GetType () );
irm [0].Check ( 1, 0, 0, 0, 0, 0, 0, "irm [0]" );
irm [1].Check ( 0, 1, 0, 1, 0, 0, 0, "irm [1]" );
return;
}
Assert.Fail ( "Expected TransactionAbortedException" );
}
[Test]
public void Vol2_Dur1_Fail5 ()
{
CommittableTransaction ct = new CommittableTransaction ();
IntResourceManager [] irm = new IntResourceManager [2];
irm [0] = new IntResourceManager ( 1 );
irm [1] = new IntResourceManager ( 3 );
Transaction.Current = ct;
irm [0].Type = ResourceManagerType.Durable;
irm [0].FailSPC = true;
irm [0].FailWithException = true;
for ( int i = 0; i < 2; i++ )
irm [i].UseSingle = true;
/* Durable RM irm[2] does on SPC, so
* all volatile RMs get Rollback */
using ( TransactionScope scope = new TransactionScope () ) {
irm [0].Value = 2;
irm [1].Value = 6;
scope.Complete ();
}
try {
ct.Commit ();
}
catch ( TransactionAbortedException e ) {
Assert.IsNotNull ( e.InnerException, "Expected e.InnerException == NotSupportedException, but got None" );
Assert.AreEqual ( typeof ( NotSupportedException ), e.InnerException.GetType (), "Expected e.InnerException == NotSupportedException, but got " + e.GetType () );
irm [0].Check ( 1, 0, 0, 0, 0, 0, 0, "irm [0]" );
irm [1].Check ( 0, 1, 0, 1, 0, 0, 0, "irm [1]" );
try {
ct.Commit ();
}
catch (InvalidOperationException x ) {
Assert.IsNull ( x.InnerException);
Transaction.Current = null;
return;
}
Assert.Fail ( "Should not be reached" );
}
Assert.Fail ( "Expected TransactionAbortedException" );
}
#endregion
#region Promotable Single Phase Enlistment
[Test]
public void Vol0_Dur0_Pspe1 ()
{
IntResourceManager irm = new IntResourceManager (1);
irm.Type = ResourceManagerType.Promotable;
using (TransactionScope scope = new TransactionScope ()) {
irm.Value = 2;
scope.Complete ();
}
irm.Check ( 1, 0, 0, 0, 0, 1, 0, "irm" );
}
[Test]
public void Vol1_Dur0_Pspe1 ()
{
IntResourceManager irm0 = new IntResourceManager (1);
IntResourceManager irm1 = new IntResourceManager (1);
irm1.Type = ResourceManagerType.Promotable;
using (TransactionScope scope = new TransactionScope ()) {
irm0.Value = 2;
irm1.Value = 8;
scope.Complete ();
}
irm1.Check ( 1, 0, 0, 0, 0, 1, 0, "irm1" );
}
[Test]
public void Vol0_Dur1_Pspe1 ()
{
IntResourceManager irm0 = new IntResourceManager (1);
IntResourceManager irm1 = new IntResourceManager (1);
irm0.Type = ResourceManagerType.Durable;
irm0.UseSingle = true;
irm1.Type = ResourceManagerType.Promotable;
using (TransactionScope scope = new TransactionScope ()) {
irm0.Value = 8;
irm1.Value = 2;
Assert.AreEqual(0, irm1.NumEnlistFailed, "PSPE enlist did not fail although durable RM was already enlisted");
}
}
[Test]
public void Vol0_Dur0_Pspe2 ()
{
IntResourceManager irm0 = new IntResourceManager (1);
IntResourceManager irm1 = new IntResourceManager (1);
irm0.Type = ResourceManagerType.Promotable;
irm1.Type = ResourceManagerType.Promotable;
using (TransactionScope scope = new TransactionScope ()) {
irm0.Value = 8;
irm1.Value = 2;
Assert.AreEqual(0, irm1.NumEnlistFailed, "PSPE enlist did not fail although PSPE RM was already enlisted");
}
}
#endregion
#region Others
/* >1vol
* > 1 durable, On .net this becomes a distributed transaction
* We don't support this in mono yet.
*/
[Test]
[Category ("NotWorking")]
public void Vol0_Dur2 ()
{
IntResourceManager [] irm = new IntResourceManager [2];
irm [0] = new IntResourceManager ( 1 );
irm [1] = new IntResourceManager ( 3 );
irm [0].Type = ResourceManagerType.Durable;
irm [1].Type = ResourceManagerType.Durable;
for ( int i = 0; i < 2; i++ )
irm [i].UseSingle = true;
using (TransactionScope scope = new TransactionScope ()) {
irm [0].Value = 2;
irm [1].Value = 6;
scope.Complete ();
}
}
[Test]
public void TransactionDispose ()
{
CommittableTransaction ct = new CommittableTransaction ();
IntResourceManager irm = new IntResourceManager (1);
irm.Type = ResourceManagerType.Durable;
ct.Dispose ();
irm.Check (0, 0, 0, 0, "Dispose transaction");
}
[Test]
public void TransactionDispose2 ()
{
CommittableTransaction ct = new CommittableTransaction ();
IntResourceManager irm = new IntResourceManager (1);
Transaction.Current = ct;
irm.Value = 5;
try {
ct.Dispose ();
} finally {
Transaction.Current = null;
}
irm.Check (0, 0, 1, 0, "Dispose transaction");
Assert.AreEqual (1, irm.Value);
}
[Test]
public void TransactionDispose3 ()
{
CommittableTransaction ct = new CommittableTransaction ();
IntResourceManager irm = new IntResourceManager (1);
try {
Transaction.Current = ct;
irm.Value = 5;
ct.Commit ();
ct.Dispose ();
} finally {
Transaction.Current = null;
}
irm.Check (1, 1, 0, 0, "Dispose transaction");
Assert.AreEqual (5, irm.Value);
}
#endregion
#region TransactionCompleted
[Test]
public void TransactionCompleted_Committed ()
{
bool called = false;
using (var ts = new TransactionScope ())
{
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => called = true;
ts.Complete ();
}
Assert.IsTrue (called, "TransactionCompleted event handler not called!");
}
[Test]
public void TransactionCompleted_Rollback ()
{
bool called = false;
using (var ts = new TransactionScope ())
{
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => called = true;
// Not calling ts.Complete() on purpose..
}
Assert.IsTrue (called, "TransactionCompleted event handler not called!");
}
#endregion
#region Success/Failure behavior tests
#region Success/Failure behavior Vol1_Dur0 Cases
[Test]
public void Vol1SPC_Committed()
{
bool called = false;
TransactionStatus status = TransactionStatus.Active;
var rm = new IntResourceManager(1)
{
UseSingle = true,
Type = ResourceManagerType.Volatile
};
using (var ts = new TransactionScope())
{
rm.Value = 2;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
ts.Complete();
}
rm.Check(1, 0, 0, 0, 0, 0, 0, "rm");
Assert.IsTrue(called, "TransactionCompleted event handler not called!");
Assert.AreEqual(TransactionStatus.Committed, status, "TransactionStatus != Commited");
}
[Test]
public void Vol1_Committed()
{
bool called = false;
TransactionStatus status = TransactionStatus.Active;
var rm = new IntResourceManager(1)
{
Type = ResourceManagerType.Volatile,
};
using (var ts = new TransactionScope())
{
rm.Value = 2;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
ts.Complete();
}
rm.Check(0, 1, 1, 0, 0, 0, 0, "rm");
Assert.IsTrue(called, "TransactionCompleted event handler not called!");
Assert.AreEqual(TransactionStatus.Committed, status, "TransactionStatus != Commited");
}
[Test]
public void Vol1_Rollback()
{
bool called = false;
TransactionStatus status = TransactionStatus.Active;
var rm = new IntResourceManager(1)
{
Type = ResourceManagerType.Volatile,
};
using (var ts = new TransactionScope())
{
rm.Value = 2;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
// Not calling ts.Complete() on purpose..
}
rm.Check(0, 0, 0, 1, 0, 0, 0, "rm");
Assert.IsTrue(called, "TransactionCompleted event handler not called!");
Assert.AreEqual(TransactionStatus.Aborted, status, "TransactionStatus != Aborted");
}
[Test]
public void Vol1SPC_Throwing_On_Commit()
{
bool called = false;
Exception ex = null;
TransactionStatus status = TransactionStatus.Active;
var rm = new IntResourceManager(1)
{
UseSingle = true,
FailSPC = true,
FailWithException = true,
Type = ResourceManagerType.Volatile
};
try
{
using (var ts = new TransactionScope())
{
rm.Value = 2;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
ts.Complete();
}
}
catch (Exception _ex)
{
ex = _ex;
}
rm.Check(1, 0, 0, 0, 0, 0, 0, "rm");
Assert.IsTrue(called, "TransactionCompleted event handler not called!");
Assert.AreEqual(TransactionStatus.Aborted, status, "TransactionStatus != Aborted");
Assert.IsNotNull(ex, "Exception not thrown");
Assert.That (ex, InstanceOf( typeof(TransactionAbortedException)), "Invalid exception thrown");
Assert.IsNotNull(ex.InnerException, "InnerException is null");
Assert.That (ex.InnerException, InstanceOf( typeof(NotSupportedException)), "Invalid inner exception thrown");
}
[Test]
public void Vol1_Throwing_On_Commit()
{
bool called = false;
TransactionStatus status = TransactionStatus.Active;
Exception ex = null;
var rm = new IntResourceManager(1)
{
FailCommit = true,
FailWithException = true,
Type = ResourceManagerType.Volatile
};
try
{
using (var ts = new TransactionScope())
{
rm.Value = 2;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
ts.Complete();
}
}
catch (Exception _ex)
{
ex = _ex;
}
rm.Check(0, 1, 1, 0, 0, 0, 0, "rm");
// MS.NET wont call TransactionCompleted event in this particular case.
Assert.IsFalse(called, "TransactionCompleted event handler _was_ called!?!?!");
Assert.IsNotNull(ex, "Exception not thrown");
#if MS_EXCEPTIONS_BEHAVIOR
// MS.NET will relay the exception thrown by RM instead of wrapping it on a TransactionAbortedException.
InstanceOf(typeof(NotSupportedException), ex, "Invalid exception thrown");
#else
// Mono wrapps the exception into a TransactionAbortedException.
Assert.That (ex, InstanceOf( typeof(TransactionAbortedException)), "Invalid type of exception thrown");
Assert.IsNotNull(ex.InnerException, "InnerException not thrown");
Assert.That (ex.InnerException, InstanceOf( typeof(NotSupportedException)), "Invalid inner exception thrown");
#endif
}
[Test]
public void Vol1_Throwing_On_Rollback()
{
bool called = false;
TransactionStatus status = TransactionStatus.Active;
Exception ex = null;
var rm = new IntResourceManager(1)
{
FailRollback = true,
FailWithException = true,
Type = ResourceManagerType.Volatile
};
try
{
using (var ts = new TransactionScope())
{
rm.Value = 2;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
// Not calling ts.Complete() on purpose..
}
}
catch (Exception _ex)
{
ex = _ex;
}
rm.Check(0, 0, 0, 1, 0, 0, 0, "rm");
// MS.NET wont call TransactionCompleted event in this particular case.
Assert.IsFalse(called, "TransactionCompleted event handler _was_ called!?!?!");
Assert.IsNotNull(ex, "Exception not thrown");
// MS.NET will relay the exception thrown by RM instead of wrapping it on a TransactionAbortedException.
Assert.That (ex, InstanceOf( typeof(NotSupportedException)), "Invalid exception thrown");
}
[Test]
public void Vol1_Throwing_On_Prepare()
{
bool called = false;
TransactionStatus status = TransactionStatus.Active;
Exception ex = null;
var rm = new IntResourceManager(1)
{
FailPrepare = true,
FailWithException = true,
Type = ResourceManagerType.Volatile
};
try
{
using (var ts = new TransactionScope())
{
rm.Value = 2;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
ts.Complete();
}
}
catch (Exception _ex)
{
ex = _ex;
}
rm.Check(0, 1, 0, 0, 0, 0, 0, "rm");
Assert.IsTrue(called, "TransactionCompleted event handler not called!");
Assert.IsNotNull(ex, "Exception not thrown");
Assert.That (ex, InstanceOf( typeof(TransactionAbortedException)), "Invalid exception thrown");
Assert.IsNotNull(ex.InnerException, "InnerException is null");
Assert.That (ex.InnerException, InstanceOf( typeof(NotSupportedException)), "Invalid inner exception thrown");
Assert.AreEqual(TransactionStatus.Aborted, status, "TransactionStatus != Aborted");
}
#endregion
#region Success/Failure behavior Vol2_Dur0 Cases
[Test]
public void Vol2SPC_Committed()
{
TransactionStatus status = TransactionStatus.Active;
bool called = false;
var rm1 = new IntResourceManager(1)
{
UseSingle = true,
Type = ResourceManagerType.Volatile
};
var rm2 = new IntResourceManager(2)
{
UseSingle = true,
Type = ResourceManagerType.Volatile
};
using (var ts = new TransactionScope())
{
rm1.Value = 11;
rm2.Value = 22;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
ts.Complete();
}
// There can be only one *Single* PC enlistment,
// so TM will downgrade both to normal enlistments.
rm1.Check(0, 1, 1, 0, 0, 0, 0, "rm1");
rm2.Check(0, 1, 1, 0, 0, 0, 0, "rm2");
Assert.IsTrue(called, "TransactionCompleted event handler not called!");
Assert.AreEqual(TransactionStatus.Committed, status, "TransactionStatus != Committed");
}
[Test]
public void Vol2_Committed()
{
TransactionStatus status = TransactionStatus.Active;
bool called = false;
var rm1 = new IntResourceManager(1)
{
Type = ResourceManagerType.Volatile
};
var rm2 = new IntResourceManager(1)
{
Type = ResourceManagerType.Volatile
};
using (var ts = new TransactionScope())
{
rm1.Value = 11;
rm2.Value = 22;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
ts.Complete();
}
rm1.Check(0, 1, 1, 0, 0, 0, 0, "rm1");
rm2.Check(0, 1, 1, 0, 0, 0, 0, "rm2");
Assert.IsTrue(called, "TransactionCompleted event handler not called!");
Assert.AreEqual(TransactionStatus.Committed, status, "TransactionStatus != Committed");
}
[Test]
public void Vol2_Rollback()
{
TransactionStatus status = TransactionStatus.Active;
bool called = false;
var rm1 = new IntResourceManager(1)
{
Type = ResourceManagerType.Volatile
};
var rm2 = new IntResourceManager(1)
{
Type = ResourceManagerType.Volatile
};
using (var ts = new TransactionScope())
{
rm1.Value = 11;
rm2.Value = 22;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
// Not calling ts.Complete() on purpose..
}
rm1.Check(0, 0, 0, 1, 0, 0, 0, "rm1");
rm2.Check(0, 0, 0, 1, 0, 0, 0, "rm2");
Assert.IsTrue(called, "TransactionCompleted event handler not called!");
Assert.AreEqual(TransactionStatus.Aborted, status, "TransactionStatus != Aborted");
}
[Test]
public void Vol2SPC_Throwing_On_Commit()
{
TransactionStatus status = TransactionStatus.Active;
bool called = false;
Exception ex = null;
var rm1 = new IntResourceManager(1)
{
UseSingle = true,
FailCommit = true,
FailWithException = true,
ThrowThisException = new InvalidOperationException("rm1"),
Type = ResourceManagerType.Volatile,
};
var rm2 = new IntResourceManager(2)
{
UseSingle = true,
Type = ResourceManagerType.Volatile,
};
try
{
using (var ts = new TransactionScope())
{
rm1.Value = 11;
rm2.Value = 22;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
ts.Complete();
}
}
catch (Exception _ex)
{
ex = _ex;
}
// There can be only one *Single* PC enlistment,
// so TM will downgrade both to normal enlistments.
rm1.Check(0, 1, 1, 0, 0, 0, 0, "rm1");
rm2.Check(0, 1, 0, 0, 0, 0, 0, "rm2");
// MS.NET wont call TransactionCompleted event in this particular case.
Assert.IsFalse(called, "TransactionCompleted event handler _was_ called!?!?!");
Assert.IsNotNull(ex, "Exception not thrown");
#if MS_EXCEPTIONS_BEHAVIOR
// MS.NET will relay the exception thrown by RM instead of wrapping it on a TransactionAbortedException.
Assert.AreEqual(rm1.ThrowThisException, ex, "Exception does not come from the expected RM");
#else
// Mono wrapps the exception into a TransactionAbortedException.
Assert.That (ex, InstanceOf( typeof(TransactionAbortedException)), "Invalid type of exception thrown");
Assert.IsNotNull(ex.InnerException, "InnerException not thrown");
Assert.AreEqual(rm1.ThrowThisException, ex.InnerException, "Exception does not come from the expected RM \n Ex: {0}", ex);
#endif
}
[Test]
public void Vol2_Throwing_On_Commit()
{
bool called = false;
Exception ex = null;
var rm1 = new IntResourceManager(1)
{
FailCommit = true,
FailWithException = true,
ThrowThisException = new InvalidOperationException("rm1"),
Type = ResourceManagerType.Volatile
};
var rm2 = new IntResourceManager(2)
{
Type = ResourceManagerType.Volatile
};
try
{
using (var ts = new TransactionScope())
{
rm1.Value = 11;
rm2.Value = 22;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => called = true;
ts.Complete();
}
}
catch (Exception _ex)
{
ex = _ex;
}
rm1.Check(0, 1, 1, 0, 0, 0, 0, "rm1");
rm2.Check(0, 1, 0, 0, 0, 0, 0, "rm2");
// MS.NET wont call TransactionCompleted event in this particular case.
Assert.IsFalse(called, "TransactionCompleted event handler _was_ called!?!?!");
Assert.IsNotNull(ex, "Exception not thrown");
#if MS_EXCEPTIONS_BEHAVIOR
// MS.NET will relay the exception thrown by RM instead of wrapping it on a TransactionAbortedException.
Assert.AreEqual(rm1.ThrowThisException, ex, "Exception does not come from the expected RM \n Ex: {0}", ex);
#else
// Mono wrapps the exception into a TransactionAbortedException.
Assert.That (ex, InstanceOf( typeof(TransactionAbortedException)), "Invalid type of exception thrown");
Assert.IsNotNull(ex.InnerException, "InnerException not thrown");
Assert.AreEqual(rm1.ThrowThisException, ex.InnerException, "Exception does not come from the expected RM \n Ex: {0}", ex);
#endif
}
[Test]
public void Vol2_Throwing_On_Rollback()
{
bool called = false;
Exception ex = null;
var rm1 = new IntResourceManager(1)
{
FailRollback = true,
FailWithException = true,
ThrowThisException = new InvalidOperationException("rm1"),
Type = ResourceManagerType.Volatile
};
var rm2 = new IntResourceManager(2)
{
Type = ResourceManagerType.Volatile
};
try
{
using (var ts = new TransactionScope())
{
rm1.Value = 11;
rm2.Value = 22;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => called = true;
// Not calling ts.Complete() on purpose..
}
}
catch (Exception _ex)
{
ex = _ex;
}
rm1.Check(0, 0, 0, 1, 0, 0, 0, "rm1");
rm2.Check(0, 0, 0, 0, 0, 0, 0, "rm2");
// MS.NET wont call TransactionCompleted event in this particular case.
Assert.IsFalse(called, "TransactionCompleted event handler _was_ called!?!?!");
Assert.IsNotNull(ex, "Exception not thrown");
// MS.NET will relay the exception thrown by RM instead of wrapping it on a TransactionAbortedException.
Assert.AreEqual(rm1.ThrowThisException, ex, "Exception does not come from the expected RM \n Ex: {0}", ex);
}
[Test]
public void Vol2_Throwing_On_First_Prepare()
{
TransactionStatus status = TransactionStatus.Active;
bool called = false;
Exception ex = null;
var rm1 = new IntResourceManager(1)
{
FailPrepare = true,
FailWithException = true,
ThrowThisException = new InvalidOperationException("rm1"),
Type = ResourceManagerType.Volatile
};
var rm2 = new IntResourceManager(2)
{
Type = ResourceManagerType.Volatile
};
try
{
using (var ts = new TransactionScope())
{
rm1.Value = 11;
rm2.Value = 22;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
ts.Complete();
}
}
catch (Exception _ex)
{
ex = _ex;
}
rm1.Check(0, 1, 0, 0, 0, 0, 0, "rm1");
rm2.Check(0, 0, 0, 1, 0, 0, 0, "rm2");
Assert.IsTrue(called, "TransactionCompleted event handler not called!");
Assert.IsNotNull(ex, "Exception not thrown");
Assert.That (ex, InstanceOf( typeof(TransactionAbortedException)), "Invalid exception thrown");
Assert.IsNotNull(ex.InnerException, "InnerException is null");
Assert.That (ex.InnerException, InstanceOf( typeof(InvalidOperationException)), "Invalid inner exception thrown");
Assert.AreEqual(TransactionStatus.Aborted, status, "TransactionStatus != Aborted");
}
[Test]
public void Vol2_Throwing_On_Second_Prepare()
{
TransactionStatus status = TransactionStatus.Active;
bool called = false;
Exception ex = null;
var rm1 = new IntResourceManager(1)
{
Type = ResourceManagerType.Volatile
};
var rm2 = new IntResourceManager(2)
{
FailPrepare = true,
FailWithException = true,
Type = ResourceManagerType.Volatile
};
try
{
using (var ts = new TransactionScope())
{
rm1.Value = 11;
rm2.Value = 22;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
ts.Complete();
}
}
catch (Exception _ex)
{
ex = _ex;
}
rm1.Check(0, 1, 0, 1, 0, 0, 0, "rm1");
rm2.Check(0, 1, 0, 0, 0, 0, 0, "rm2");
Assert.IsTrue(called, "TransactionCompleted event handler not called!");
Assert.IsNotNull(ex, "Exception not thrown");
Assert.That (ex, InstanceOf( typeof(TransactionAbortedException)), "Invalid exception thrown");
Assert.IsNotNull(ex.InnerException, "InnerException is null");
Assert.That (ex.InnerException, InstanceOf( typeof(NotSupportedException)), "Invalid inner exception thrown");
Assert.AreEqual(TransactionStatus.Aborted, status, "TransactionStatus != Aborted");
}
[Test]
public void Vol2_Throwing_On_First_Prepare_And_Second_Rollback()
{
TransactionStatus status = TransactionStatus.Active;
bool called = false;
Exception ex = null;
var rm1 = new IntResourceManager(1)
{
FailPrepare = true,
FailWithException = true,
ThrowThisException = new InvalidOperationException("rm1"),
Type = ResourceManagerType.Volatile
};
var rm2 = new IntResourceManager(2)
{
FailRollback = true,
FailWithException = true,
ThrowThisException = new InvalidOperationException("rm2"),
Type = ResourceManagerType.Volatile
};
try
{
using (var ts = new TransactionScope())
{
rm1.Value = 11;
rm2.Value = 22;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
ts.Complete();
}
}
catch (Exception _ex)
{
ex = _ex;
}
rm1.Check(0, 1, 0, 0, 0, 0, 0, "rm1");
rm2.Check(0, 0, 0, 1, 0, 0, 0, "rm2");
// MS.NET wont call TransactionCompleted event in this particular case.
Assert.IsFalse(called, "TransactionCompleted event handler _was_ called!?!?!");
Assert.IsNotNull(ex, "Exception not thrown");
#if MS_EXCEPTIONS_BEHAVIOR
// MS.NET will relay the exception thrown by RM instead of wrapping it on a TransactionAbortedException.
Assert.AreEqual(rm2.ThrowThisException, ex, "Exception does not come from the expected RM");
#else
// Mono wrapps the exception into a TransactionAbortedException.
Assert.That (ex, InstanceOf( typeof(TransactionAbortedException)), "Invalid type of exception thrown");
Assert.IsNotNull(ex.InnerException, "InnerException not thrown");
Assert.AreEqual(rm2.ThrowThisException, ex.InnerException, "Exception does not come from the expected RM \n Ex: {0}", ex.InnerException);
#endif
}
[Test]
public void Vol2_Throwing_On_First_Rollback_And_Second_Prepare()
{
TransactionStatus status = TransactionStatus.Active;
bool called = false;
Exception ex = null;
var rm1 = new IntResourceManager(1)
{
FailRollback = true,
FailWithException = true,
ThrowThisException = new InvalidOperationException("rm1"),
Type = ResourceManagerType.Volatile
};
var rm2 = new IntResourceManager(2)
{
FailPrepare = true,
FailWithException = true,
ThrowThisException = new InvalidOperationException("rm2"),
Type = ResourceManagerType.Volatile
};
try
{
using (var ts = new TransactionScope())
{
rm1.Value = 11;
rm2.Value = 22;
var tr = Transaction.Current;
tr.TransactionCompleted += (s, e) => { called = true; status = e.Transaction.TransactionInformation.Status; };
ts.Complete();
}
}
catch (Exception _ex)
{
ex = _ex;
}
rm1.Check(0, 1, 0, 1, 0, 0, 0, "rm1");
rm2.Check(0, 1, 0, 0, 0, 0, 0, "rm2");
// MS.NET wont call TransactionCompleted event in this particular case.
Assert.IsFalse(called, "TransactionCompleted event handler _was_ called!?!?!");
Assert.IsNotNull(ex, "Exception not thrown");
#if MS_EXCEPTIONS_BEHAVIOR
// MS.NET will relay the exception thrown by RM instead of wrapping it on a TransactionAbortedException.
Assert.AreEqual(rm1.ThrowThisException, ex, "Exception does not come from the expected RM");
#else
// Mono wrapps the exception into a TransactionAbortedException.
Assert.That (ex, InstanceOf( typeof(TransactionAbortedException)), "Invalid type of exception thrown");
Assert.IsNotNull(ex.InnerException, "InnerException not thrown");
Assert.AreEqual(rm1.ThrowThisException, ex.InnerException, "Exception does not come from the expected RM \n Ex: {0}", ex);
#endif
}
#endregion
#endregion
public static InstanceOfTypeConstraint InstanceOf (Type expectedType)
{
return new InstanceOfTypeConstraint (expectedType);
}
}
}