Skip to content

Commit 72a9db9

Browse files
NH-2176 - Additional tests and tests fixes for distributed transactions.
1 parent 8bb1de5 commit 72a9db9

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

src/NHibernate.Test/DebugSessionFactory.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ public bool CheckSessionsWereClosed()
6161

6262
if (txContext?.ShouldCloseSessionOnDistributedTransactionCompleted ?? false)
6363
{
64-
// Delayed transactions not having completed and closed their sessions? Give them a chance to complete.
64+
// Delayed rollback not having lock from prepare phase? Give it a chance to complete.
6565
Thread.Sleep(100);
66+
txContext.WaitOne();
6667
if (!session.IsOpen)
6768
{
6869
_log.Warn($"Test case had a delayed close of session {session.SessionId}.");

src/NHibernate.Test/NHSpecificTest/DtcFailures/DtcFailuresFixture.cs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ protected override void CreateSchema()
4949

5050
protected override void OnTearDown()
5151
{
52+
DodgeTransactionCompletionDelayIfRequired();
53+
5254
using (var s = OpenSession())
5355
using (var t = s.BeginTransaction())
5456
{
@@ -505,11 +507,53 @@ public void CanUseSessionOutsideOfScopeAfterScope([Values(false, true)] bool exp
505507
Assert.DoesNotThrow(() => count = s.Query<Person>().Count(), "Failed using the session after scope.");
506508
if (count != 1)
507509
// We are not testing that here, so just issue a warning. Do not use DodgeTransactionCompletionDelayIfRequired
508-
// before previous assert. We want to ascertain the session is usable in any cases.
510+
// before previous assert. We want to ascertain the session is usable in any cases.
509511
Assert.Warn("Unexpected entity count: {0} instead of {1}. The transaction seems to have a delayed commit.", count, 1);
510512
}
511513
}
512514

515+
[Test(Description = "Do not fail, but warn in case a delayed after scope disposal commit is made.")]
516+
public void DelayedTransactionCompletion([Values(false, true)] bool explicitFlush)
517+
{
518+
for (var i = 1; i <= 10; i++)
519+
{
520+
// Isolation level must be read committed on the control session: reading twice while expecting some data insert
521+
// in between due to a late commit. Repeatable read would block and read uncommitted would see the uncommitted data.
522+
using (var controlSession = OpenSession())
523+
using (controlSession.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
524+
{
525+
// We want to have the control session as ready to query as possible, thus beginning its
526+
// transaction early for acquiring the connection, even if we will not use it before
527+
// below scope completion.
528+
529+
using (var tx = new TransactionScope())
530+
{
531+
using (var s = OpenSession())
532+
{
533+
s.Save(new Person { CreatedAt = DateTime.Today });
534+
535+
ForceEscalationToDistributedTx.Escalate();
536+
537+
if (explicitFlush)
538+
s.Flush();
539+
}
540+
tx.Complete();
541+
}
542+
543+
var count = controlSession.Query<Person>().Count();
544+
if (count != i)
545+
{
546+
Thread.Sleep(100);
547+
var countSecondTry = controlSession.Query<Person>().Count();
548+
Assert.Warn($"Unexpected entity count: {count} instead of {i}. " +
549+
"This may mean current data provider has a delayed commit, occurring after scope disposal. " +
550+
$"After waiting, count is now {countSecondTry}. ");
551+
break;
552+
}
553+
}
554+
}
555+
}
556+
513557
private void AssertNoPersons()
514558
{
515559
using (var s = OpenSession())

0 commit comments

Comments
 (0)