Fixes deadlock issues and concurrent index drop issues
This commit is contained in:
@@ -53,11 +53,11 @@ namespace Umbraco.Tests.Integration.Extensions
|
||||
{
|
||||
case UmbracoTestOptions.Database.NewSchemaPerTest:
|
||||
|
||||
// Add teardown callback
|
||||
integrationTest.OnTestTearDown(() => db.Detach());
|
||||
|
||||
// New DB + Schema
|
||||
db.AttachSchema();
|
||||
var newSchemaDbId = db.AttachSchema();
|
||||
|
||||
// Add teardown callback
|
||||
integrationTest.OnTestTearDown(() => db.Detach(newSchemaDbId));
|
||||
|
||||
// We must re-configure our current factory since attaching a new LocalDb from the pool changes connection strings
|
||||
var dbFactory = app.ApplicationServices.GetRequiredService<IUmbracoDatabaseFactory>();
|
||||
@@ -89,22 +89,27 @@ namespace Umbraco.Tests.Integration.Extensions
|
||||
break;
|
||||
case UmbracoTestOptions.Database.NewEmptyPerTest:
|
||||
|
||||
// Add teardown callback
|
||||
integrationTest.OnTestTearDown(() => db.Detach());
|
||||
var newEmptyDbId = db.AttachEmpty();
|
||||
|
||||
// Add teardown callback
|
||||
integrationTest.OnTestTearDown(() => db.Detach(newEmptyDbId));
|
||||
|
||||
db.AttachEmpty();
|
||||
|
||||
break;
|
||||
case UmbracoTestOptions.Database.NewSchemaPerFixture:
|
||||
|
||||
// Add teardown callback
|
||||
integrationTest.OnFixtureTearDown(() => db.Detach());
|
||||
throw new NotImplementedException();
|
||||
|
||||
//// Add teardown callback
|
||||
//integrationTest.OnFixtureTearDown(() => db.Detach());
|
||||
|
||||
break;
|
||||
case UmbracoTestOptions.Database.NewEmptyPerFixture:
|
||||
|
||||
// Add teardown callback
|
||||
integrationTest.OnFixtureTearDown(() => db.Detach());
|
||||
throw new NotImplementedException();
|
||||
|
||||
//// Add teardown callback
|
||||
//integrationTest.OnFixtureTearDown(() => db.Detach());
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -78,27 +78,29 @@ namespace Umbraco.Tests.Integration.Testing
|
||||
_schemaPool = new DatabasePool(_localDb, _instance, DatabaseName + "-Schema", tempName, _filesPath, schemaSize, schemaParallel, delete: true, prepare: RebuildSchema);
|
||||
}
|
||||
|
||||
public void AttachEmpty()
|
||||
public int AttachEmpty()
|
||||
{
|
||||
if (_emptyPool == null)
|
||||
Create();
|
||||
|
||||
_currentCstr = _emptyPool.AttachDatabase();
|
||||
_currentCstr = _emptyPool.AttachDatabase(out var id);
|
||||
_currentPool = _emptyPool;
|
||||
return id;
|
||||
}
|
||||
|
||||
public void AttachSchema()
|
||||
public int AttachSchema()
|
||||
{
|
||||
if (_schemaPool == null)
|
||||
Create();
|
||||
|
||||
_currentCstr = _schemaPool.AttachDatabase();
|
||||
_currentCstr = _schemaPool.AttachDatabase(out var id);
|
||||
_currentPool = _schemaPool;
|
||||
return id;
|
||||
}
|
||||
|
||||
public void Detach()
|
||||
public void Detach(int id)
|
||||
{
|
||||
_currentPool.DetachDatabase();
|
||||
_currentPool.DetachDatabase(id);
|
||||
}
|
||||
|
||||
private void RebuildSchema(DbConnection conn, IDbCommand cmd)
|
||||
@@ -188,7 +190,25 @@ namespace Umbraco.Tests.Integration.Testing
|
||||
from sys.tables;
|
||||
exec sp_executesql @stmt;
|
||||
";
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
// rudimentary retry policy since a db can still be in use when we try to drop
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
cmd.ExecuteNonQuery();
|
||||
return;
|
||||
}
|
||||
catch (SqlException ex)
|
||||
{
|
||||
// This can occur when there's a transaction deadlock which means (i think) that the database is still in use and hasn't been closed properly yet
|
||||
// so we need to just wait a little bit
|
||||
Thread.Sleep(1000);
|
||||
if (i == 4)
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void KillLocalDb()
|
||||
@@ -266,22 +286,19 @@ namespace Umbraco.Tests.Integration.Testing
|
||||
}
|
||||
}
|
||||
|
||||
public string AttachDatabase()
|
||||
public string AttachDatabase(out int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
_current = _readyQueue.Take();
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
_current = 0;
|
||||
return null;
|
||||
}
|
||||
_current = _readyQueue.Take();
|
||||
id = _current;
|
||||
|
||||
return ConnectionString(_current);
|
||||
}
|
||||
|
||||
public void DetachDatabase()
|
||||
public void DetachDatabase(int id)
|
||||
{
|
||||
if (id != _current)
|
||||
throw new InvalidOperationException("Cannot detatch the non-current db");
|
||||
|
||||
_prepareQueue.Add(_current);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using NPoco.Expressions;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
@@ -70,37 +71,29 @@ namespace Umbraco.Tests.Integration.Testing
|
||||
private static readonly object _dbLocker = new object();
|
||||
private static LocalDbTestDatabase _dbInstance;
|
||||
|
||||
private readonly List<Action> _testTeardown = new List<Action>();
|
||||
private readonly List<Action> _fixtureTeardown = new List<Action>();
|
||||
private Action _testTeardown = null;
|
||||
private Action _fixtureTeardown = null;
|
||||
|
||||
public void OnTestTearDown(Action tearDown)
|
||||
{
|
||||
_testTeardown.Add(tearDown);
|
||||
_testTeardown = tearDown;
|
||||
}
|
||||
|
||||
public void OnFixtureTearDown(Action tearDown)
|
||||
{
|
||||
_fixtureTeardown.Add(tearDown);
|
||||
_fixtureTeardown = tearDown;
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void FixtureTearDown()
|
||||
{
|
||||
// call all registered callbacks
|
||||
foreach (var action in _fixtureTeardown)
|
||||
{
|
||||
action();
|
||||
}
|
||||
_fixtureTeardown?.Invoke();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
// call all registered callbacks
|
||||
foreach (var action in _testTeardown)
|
||||
{
|
||||
action();
|
||||
}
|
||||
_testTeardown?.Invoke();
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
|
||||
Reference in New Issue
Block a user