You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
688 lines
26 KiB
C#
688 lines
26 KiB
C#
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Data.Odbc;
|
|
using System.Data.OleDb;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using EntityFrameworkCore.Jet.Data;
|
|
using EntityFrameworkCore.Jet.FunctionalTests.TestUtilities;
|
|
using EntityFrameworkCore.Jet.Infrastructure;
|
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
using EntityFrameworkCore.Jet.Storage.Internal;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Storage;
|
|
using Microsoft.EntityFrameworkCore.TestUtilities;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
using Xunit;
|
|
using DbContext = Microsoft.EntityFrameworkCore.DbContext;
|
|
|
|
// ReSharper disable MethodSupportsCancellation
|
|
// ReSharper disable AccessToDisposedClosure
|
|
// ReSharper disable InconsistentNaming
|
|
#nullable disable
|
|
namespace EntityFrameworkCore.Jet.FunctionalTests
|
|
{
|
|
public class ExecutionStrategyTest : IClassFixture<ExecutionStrategyTest.ExecutionStrategyFixture>
|
|
{
|
|
public ExecutionStrategyTest(ExecutionStrategyFixture fixture)
|
|
{
|
|
Fixture = fixture;
|
|
Fixture.TestStore.CloseConnection();
|
|
Fixture.TestSqlLoggerFactory.Clear();
|
|
}
|
|
|
|
protected ExecutionStrategyFixture Fixture { get; }
|
|
|
|
[ConditionalTheory]
|
|
[MemberData(nameof(DataGenerator.GetBoolCombinations), 1, MemberType = typeof(DataGenerator))]
|
|
public void Handles_commit_failure(bool realFailure)
|
|
{
|
|
// Use all overloads of ExecuteInTransaction
|
|
Test_commit_failure(
|
|
realFailure, (e, db) => e.ExecuteInTransaction(
|
|
() => { db.SaveChanges(false); },
|
|
() => db.Products.AsNoTracking().Any()));
|
|
|
|
Test_commit_failure(
|
|
realFailure, (e, db) => e.ExecuteInTransaction(
|
|
() => db.SaveChanges(false),
|
|
() => db.Products.AsNoTracking().Any()));
|
|
|
|
Test_commit_failure(
|
|
realFailure, (e, db) => e.ExecuteInTransaction(
|
|
db,
|
|
c => { c.SaveChanges(false); },
|
|
c => c.Products.AsNoTracking().Any()));
|
|
|
|
Test_commit_failure(
|
|
realFailure, (e, db) => e.ExecuteInTransaction(
|
|
db,
|
|
c => c.SaveChanges(false),
|
|
c => c.Products.AsNoTracking().Any()));
|
|
|
|
Test_commit_failure(
|
|
realFailure, (e, db) => e.ExecuteInTransaction(
|
|
() => { db.SaveChanges(false); },
|
|
() => db.Products.AsNoTracking().Any(),
|
|
IsolationLevel.Serializable));
|
|
|
|
Test_commit_failure(
|
|
realFailure, (e, db) => e.ExecuteInTransaction(
|
|
() => db.SaveChanges(false),
|
|
() => db.Products.AsNoTracking().Any(),
|
|
IsolationLevel.Serializable));
|
|
|
|
Test_commit_failure(
|
|
realFailure, (e, db) => e.ExecuteInTransaction(
|
|
db,
|
|
c => { c.SaveChanges(false); },
|
|
c => c.Products.AsNoTracking().Any(),
|
|
IsolationLevel.Serializable));
|
|
|
|
Test_commit_failure(
|
|
realFailure, (e, db) => e.ExecuteInTransaction(
|
|
db,
|
|
c => c.SaveChanges(false),
|
|
c => c.Products.AsNoTracking().Any(),
|
|
IsolationLevel.Serializable));
|
|
}
|
|
|
|
private void Test_commit_failure(bool realFailure, Action<TestJetRetryingExecutionStrategy, ExecutionStrategyContext> execute)
|
|
{
|
|
CleanContext();
|
|
|
|
using (var context = CreateContext())
|
|
{
|
|
var connection = (TestJetConnection)context.GetService<IJetRelationalConnection>();
|
|
|
|
connection.CommitFailures.Enqueue([realFailure]);
|
|
Fixture.TestSqlLoggerFactory.Clear();
|
|
|
|
context.Products.Add(new Product());
|
|
execute(new TestJetRetryingExecutionStrategy(context), context);
|
|
context.ChangeTracker.AcceptAllChanges();
|
|
|
|
var retryMessage = (TestEnvironment.DataAccessProviderType == DataAccessProviderType.OleDb
|
|
? typeof(OleDbException)
|
|
: typeof(OdbcException)).FullName + " (0xFFFFFFFE): Bang!";
|
|
|
|
if (realFailure)
|
|
{
|
|
var logEntry = Fixture.TestSqlLoggerFactory.Log.Single(l => l.Id == CoreEventId.ExecutionStrategyRetrying);
|
|
Assert.Contains(retryMessage, logEntry.Message);
|
|
Assert.Equal(LogLevel.Information, logEntry.Level);
|
|
}
|
|
else
|
|
{
|
|
Assert.Empty(Fixture.TestSqlLoggerFactory.Log.Where(l => l.Id == CoreEventId.ExecutionStrategyRetrying));
|
|
}
|
|
|
|
Assert.Equal(realFailure ? 3 : 2, connection.OpenCount);
|
|
}
|
|
|
|
using (var context = CreateContext())
|
|
{
|
|
Assert.Equal(1, context.Products.Count());
|
|
}
|
|
}
|
|
|
|
[ConditionalTheory]
|
|
[MemberData(nameof(DataGenerator.GetBoolCombinations), 1, MemberType = typeof(DataGenerator))]
|
|
public async Task Handles_commit_failure_async(bool realFailure)
|
|
{
|
|
// Use all overloads of ExecuteInTransactionAsync
|
|
await Test_commit_failure_async(
|
|
realFailure, (e, db) => e.ExecuteInTransactionAsync(
|
|
() => db.SaveChangesAsync(false),
|
|
() => db.Products.AsNoTracking().AnyAsync()));
|
|
|
|
await Test_commit_failure_async(
|
|
realFailure, (e, db) => e.ExecuteInTransactionAsync(
|
|
async ct => { await db.SaveChangesAsync(false); },
|
|
ct => db.Products.AsNoTracking().AnyAsync(),
|
|
CancellationToken.None));
|
|
|
|
await Test_commit_failure_async(
|
|
realFailure, (e, db) => e.ExecuteInTransactionAsync(
|
|
ct => db.SaveChangesAsync(false, ct),
|
|
ct => db.Products.AsNoTracking().AnyAsync(),
|
|
CancellationToken.None));
|
|
|
|
await Test_commit_failure_async(
|
|
realFailure, (e, db) => e.ExecuteInTransactionAsync(
|
|
db,
|
|
async (c, ct) => { await c.SaveChangesAsync(false, ct); },
|
|
(c, ct) => c.Products.AsNoTracking().AnyAsync(),
|
|
CancellationToken.None));
|
|
|
|
await Test_commit_failure_async(
|
|
realFailure, (e, db) => e.ExecuteInTransactionAsync(
|
|
db,
|
|
(c, ct) => c.SaveChangesAsync(false, ct),
|
|
(c, ct) => c.Products.AsNoTracking().AnyAsync(),
|
|
CancellationToken.None));
|
|
|
|
await Test_commit_failure_async(
|
|
realFailure, (e, db) => e.ExecuteInTransactionAsync(
|
|
() => db.SaveChangesAsync(false),
|
|
() => db.Products.AsNoTracking().AnyAsync(),
|
|
IsolationLevel.Serializable));
|
|
|
|
await Test_commit_failure_async(
|
|
realFailure, (e, db) => e.ExecuteInTransactionAsync(
|
|
async ct => { await db.SaveChangesAsync(false, ct); },
|
|
ct => db.Products.AsNoTracking().AnyAsync(ct),
|
|
IsolationLevel.Serializable,
|
|
CancellationToken.None));
|
|
|
|
await Test_commit_failure_async(
|
|
realFailure, (e, db) => e.ExecuteInTransactionAsync(
|
|
ct => db.SaveChangesAsync(false, ct),
|
|
ct => db.Products.AsNoTracking().AnyAsync(ct),
|
|
IsolationLevel.Serializable,
|
|
CancellationToken.None));
|
|
|
|
await Test_commit_failure_async(
|
|
realFailure, (e, db) => e.ExecuteInTransactionAsync(
|
|
db,
|
|
async (c, ct) => { await c.SaveChangesAsync(false, ct); },
|
|
(c, ct) => c.Products.AsNoTracking().AnyAsync(ct),
|
|
IsolationLevel.Serializable,
|
|
CancellationToken.None));
|
|
|
|
await Test_commit_failure_async(
|
|
realFailure, (e, db) => e.ExecuteInTransactionAsync(
|
|
db,
|
|
(c, ct) => c.SaveChangesAsync(false, ct),
|
|
(c, ct) => c.Products.AsNoTracking().AnyAsync(ct),
|
|
IsolationLevel.Serializable,
|
|
CancellationToken.None));
|
|
}
|
|
|
|
private async Task Test_commit_failure_async(
|
|
bool realFailure, Func<TestJetRetryingExecutionStrategy, ExecutionStrategyContext, Task> execute)
|
|
{
|
|
CleanContext();
|
|
|
|
using (var context = CreateContext())
|
|
{
|
|
var connection = (TestJetConnection)context.GetService<IJetRelationalConnection>();
|
|
|
|
connection.CommitFailures.Enqueue([realFailure]);
|
|
Fixture.TestSqlLoggerFactory.Clear();
|
|
|
|
context.Products.Add(new Product());
|
|
await execute(new TestJetRetryingExecutionStrategy(context), context);
|
|
context.ChangeTracker.AcceptAllChanges();
|
|
|
|
var retryMessage = (TestEnvironment.DataAccessProviderType == DataAccessProviderType.OleDb
|
|
? typeof(OleDbException)
|
|
: typeof(OdbcException)).FullName + " (0xFFFFFFFE): Bang!";
|
|
|
|
if (realFailure)
|
|
{
|
|
var logEntry = Fixture.TestSqlLoggerFactory.Log.Single(l => l.Id == CoreEventId.ExecutionStrategyRetrying);
|
|
Assert.Contains(retryMessage, logEntry.Message);
|
|
Assert.Equal(LogLevel.Information, logEntry.Level);
|
|
}
|
|
else
|
|
{
|
|
Assert.Empty(Fixture.TestSqlLoggerFactory.Log.Where(l => l.Id == CoreEventId.ExecutionStrategyRetrying));
|
|
}
|
|
|
|
Assert.Equal(realFailure ? 3 : 2, connection.OpenCount);
|
|
}
|
|
|
|
using (var context = CreateContext())
|
|
{
|
|
Assert.Equal(1, await context.Products.CountAsync());
|
|
}
|
|
}
|
|
|
|
[ConditionalTheory]
|
|
[MemberData(nameof(DataGenerator.GetBoolCombinations), 1, MemberType = typeof(DataGenerator))]
|
|
public void Handles_commit_failure_multiple_SaveChanges(bool realFailure)
|
|
{
|
|
CleanContext();
|
|
|
|
using var context1 = CreateContext();
|
|
var connection = (TestJetConnection)context1.GetService<IJetRelationalConnection>();
|
|
|
|
using (var context2 = CreateContext())
|
|
{
|
|
connection.CommitFailures.Enqueue([realFailure]);
|
|
|
|
context1.Products.Add(new Product());
|
|
context2.Products.Add(new Product());
|
|
|
|
new TestJetRetryingExecutionStrategy(context1).ExecuteInTransaction(
|
|
context1,
|
|
c1 =>
|
|
{
|
|
context2.Database.UseTransaction(null);
|
|
context2.Database.UseTransaction(context1.Database.CurrentTransaction.GetDbTransaction());
|
|
|
|
c1.SaveChanges(false);
|
|
|
|
return context2.SaveChanges(false);
|
|
},
|
|
c => c.Products.AsNoTracking().Any());
|
|
|
|
context1.ChangeTracker.AcceptAllChanges();
|
|
context2.ChangeTracker.AcceptAllChanges();
|
|
}
|
|
|
|
using (var context = CreateContext())
|
|
{
|
|
Assert.Equal(2, context.Products.Count());
|
|
}
|
|
}
|
|
|
|
[ConditionalTheory]
|
|
[MemberData(nameof(DataGenerator.GetBoolCombinations), 4, MemberType = typeof(DataGenerator))]
|
|
public async Task Retries_SaveChanges_on_execution_failure(
|
|
bool realFailure, bool externalStrategy, bool openConnection, bool async)
|
|
{
|
|
CleanContext();
|
|
|
|
using (var context = CreateContext())
|
|
{
|
|
var connection = (TestJetConnection)context.GetService<IJetRelationalConnection>();
|
|
|
|
connection.ExecutionFailures.Enqueue([null, realFailure]);
|
|
|
|
Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State);
|
|
|
|
if (openConnection)
|
|
{
|
|
if (async)
|
|
{
|
|
await context.Database.OpenConnectionAsync();
|
|
}
|
|
else
|
|
{
|
|
context.Database.OpenConnection();
|
|
}
|
|
|
|
Assert.Equal(ConnectionState.Open, context.Database.GetDbConnection().State);
|
|
}
|
|
|
|
context.Products.Add(new Product());
|
|
context.Products.Add(new Product());
|
|
|
|
if (async)
|
|
{
|
|
if (externalStrategy)
|
|
{
|
|
await new TestJetRetryingExecutionStrategy(context).ExecuteInTransactionAsync(
|
|
context,
|
|
(c, ct) => c.SaveChangesAsync(false, ct),
|
|
(c, _) =>
|
|
{
|
|
Assert.True(false);
|
|
return Task.FromResult(false);
|
|
});
|
|
|
|
context.ChangeTracker.AcceptAllChanges();
|
|
}
|
|
else
|
|
{
|
|
await context.SaveChangesAsync();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (externalStrategy)
|
|
{
|
|
new TestJetRetryingExecutionStrategy(context).ExecuteInTransaction(
|
|
context,
|
|
c => c.SaveChanges(false),
|
|
c =>
|
|
{
|
|
Assert.True(false);
|
|
return false;
|
|
});
|
|
|
|
context.ChangeTracker.AcceptAllChanges();
|
|
}
|
|
else
|
|
{
|
|
context.SaveChanges();
|
|
}
|
|
}
|
|
|
|
Assert.Equal(2, connection.OpenCount);
|
|
Assert.Equal(4, connection.ExecutionCount);
|
|
|
|
Assert.Equal(
|
|
openConnection
|
|
? ConnectionState.Open
|
|
: ConnectionState.Closed, context.Database.GetDbConnection().State);
|
|
|
|
if (openConnection)
|
|
{
|
|
if (async)
|
|
{
|
|
context.Database.CloseConnection();
|
|
}
|
|
else
|
|
{
|
|
await context.Database.CloseConnectionAsync();
|
|
}
|
|
}
|
|
|
|
Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State);
|
|
}
|
|
|
|
using (var context = CreateContext())
|
|
{
|
|
Assert.Equal(2, context.Products.Count());
|
|
}
|
|
}
|
|
|
|
[ConditionalTheory]
|
|
[MemberData(nameof(DataGenerator.GetBoolCombinations), 2, MemberType = typeof(DataGenerator))]
|
|
public async Task Retries_query_on_execution_failure(bool externalStrategy, bool async)
|
|
{
|
|
CleanContext();
|
|
|
|
using (var context = CreateContext())
|
|
{
|
|
context.Products.Add(new Product());
|
|
context.Products.Add(new Product());
|
|
|
|
context.SaveChanges();
|
|
}
|
|
|
|
using (var context = CreateContext())
|
|
{
|
|
var connection = (TestJetConnection)context.GetService<IJetRelationalConnection>();
|
|
|
|
connection.ExecutionFailures.Enqueue([true]);
|
|
|
|
Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State);
|
|
|
|
List<Product> list;
|
|
if (async)
|
|
{
|
|
if (externalStrategy)
|
|
{
|
|
list = await new TestJetRetryingExecutionStrategy(context)
|
|
.ExecuteAsync(context, (c, ct) => c.Products.ToListAsync(ct), null);
|
|
}
|
|
else
|
|
{
|
|
list = await context.Products.ToListAsync();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (externalStrategy)
|
|
{
|
|
list = new TestJetRetryingExecutionStrategy(context)
|
|
.Execute(context, c => c.Products.ToList(), null);
|
|
}
|
|
else
|
|
{
|
|
list = [.. context.Products];
|
|
}
|
|
}
|
|
|
|
Assert.Equal(2, list.Count);
|
|
Assert.Equal(1, connection.OpenCount);
|
|
Assert.Equal(2, connection.ExecutionCount);
|
|
|
|
Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State);
|
|
}
|
|
}
|
|
|
|
[ConditionalTheory]
|
|
[MemberData(nameof(DataGenerator.GetBoolCombinations), 2, MemberType = typeof(DataGenerator))]
|
|
public async Task Retries_FromSqlRaw_on_execution_failure(bool externalStrategy, bool async)
|
|
{
|
|
CleanContext();
|
|
|
|
using (var context = CreateContext())
|
|
{
|
|
context.Products.Add(new Product());
|
|
context.Products.Add(new Product());
|
|
|
|
context.SaveChanges();
|
|
}
|
|
|
|
using (var context = CreateContext())
|
|
{
|
|
var connection = (TestJetConnection)context.GetService<IJetRelationalConnection>();
|
|
|
|
connection.ExecutionFailures.Enqueue([true]);
|
|
|
|
Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State);
|
|
|
|
List<Product> list;
|
|
if (async)
|
|
{
|
|
if (externalStrategy)
|
|
{
|
|
list = await new TestJetRetryingExecutionStrategy(context)
|
|
.ExecuteAsync(
|
|
context, (c, ct) => c.Set<Product>().FromSqlRaw(
|
|
"""
|
|
SELECT `ID`, `name`
|
|
FROM `Products`
|
|
""").ToListAsync(ct), null);
|
|
}
|
|
else
|
|
{
|
|
list = await context.Set<Product>().FromSqlRaw(
|
|
"""
|
|
SELECT `ID`, `name`
|
|
FROM `Products`
|
|
""").ToListAsync();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (externalStrategy)
|
|
{
|
|
list = new TestJetRetryingExecutionStrategy(context)
|
|
.Execute(
|
|
context, c => c.Set<Product>().FromSqlRaw(
|
|
"""
|
|
SELECT `ID`, `name`
|
|
FROM `Products`
|
|
""").ToList(), null);
|
|
}
|
|
else
|
|
{
|
|
list = [.. context.Set<Product>().FromSqlRaw(
|
|
"""
|
|
SELECT `ID`, `name`
|
|
FROM `Products`
|
|
""")];
|
|
}
|
|
}
|
|
|
|
Assert.Equal(2, list.Count);
|
|
Assert.Equal(1, connection.OpenCount);
|
|
Assert.Equal(2, connection.ExecutionCount);
|
|
|
|
Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State);
|
|
}
|
|
}
|
|
|
|
[ConditionalTheory]
|
|
[MemberData(nameof(DataGenerator.GetBoolCombinations), 2, MemberType = typeof(DataGenerator))]
|
|
public async Task Retries_OpenConnection_on_execution_failure(bool externalStrategy, bool async)
|
|
{
|
|
using var context = CreateContext();
|
|
var connection = (TestJetConnection)context.GetService<IJetRelationalConnection>();
|
|
|
|
connection.OpenFailures.Enqueue([true]);
|
|
|
|
Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State);
|
|
|
|
if (async)
|
|
{
|
|
if (externalStrategy)
|
|
{
|
|
await new TestJetRetryingExecutionStrategy(context).ExecuteAsync(
|
|
context,
|
|
c => c.Database.OpenConnectionAsync());
|
|
}
|
|
else
|
|
{
|
|
await context.Database.OpenConnectionAsync();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (externalStrategy)
|
|
{
|
|
new TestJetRetryingExecutionStrategy(context).Execute(
|
|
context,
|
|
c => c.Database.OpenConnection());
|
|
}
|
|
else
|
|
{
|
|
context.Database.OpenConnection();
|
|
}
|
|
}
|
|
|
|
Assert.Equal(2, connection.OpenCount);
|
|
|
|
if (async)
|
|
{
|
|
context.Database.CloseConnection();
|
|
}
|
|
else
|
|
{
|
|
await context.Database.CloseConnectionAsync();
|
|
}
|
|
|
|
Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State);
|
|
}
|
|
|
|
[ConditionalTheory]
|
|
[InlineData(false)]
|
|
[InlineData(true)]
|
|
public async Task Retries_BeginTransaction_on_execution_failure(bool async)
|
|
{
|
|
using var context = CreateContext();
|
|
var connection = (TestJetConnection)context.GetService<IJetRelationalConnection>();
|
|
|
|
connection.OpenFailures.Enqueue([true]);
|
|
|
|
Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State);
|
|
|
|
if (async)
|
|
{
|
|
var transaction = await new TestJetRetryingExecutionStrategy(context).ExecuteAsync(
|
|
context,
|
|
c => context.Database.BeginTransactionAsync());
|
|
|
|
transaction.Dispose();
|
|
}
|
|
else
|
|
{
|
|
var transaction = new TestJetRetryingExecutionStrategy(context).Execute(
|
|
context,
|
|
c => context.Database.BeginTransaction());
|
|
|
|
transaction.Dispose();
|
|
}
|
|
|
|
Assert.Equal(2, connection.OpenCount);
|
|
|
|
Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State);
|
|
}
|
|
|
|
[ConditionalFact]
|
|
public void Verification_is_retried_using_same_retry_limit()
|
|
{
|
|
CleanContext();
|
|
|
|
using (var context = CreateContext())
|
|
{
|
|
var connection = (TestJetConnection)context.GetService<IJetRelationalConnection>();
|
|
|
|
connection.ExecutionFailures.Enqueue([true, null, true, true]);
|
|
connection.CommitFailures.Enqueue([true, true, true, true]);
|
|
|
|
context.Products.Add(new Product());
|
|
Assert.Throws<RetryLimitExceededException>(
|
|
() =>
|
|
new TestJetRetryingExecutionStrategy(context, TimeSpan.FromMilliseconds(100))
|
|
.ExecuteInTransaction(
|
|
context,
|
|
c => c.SaveChanges(false),
|
|
c => false));
|
|
context.ChangeTracker.AcceptAllChanges();
|
|
|
|
Assert.Equal(7, connection.OpenCount);
|
|
Assert.Equal(7, connection.ExecutionCount);
|
|
}
|
|
|
|
using (var context = CreateContext())
|
|
{
|
|
Assert.Equal(0, context.Products.Count());
|
|
}
|
|
}
|
|
|
|
protected class ExecutionStrategyContext(DbContextOptions options) : DbContext(options)
|
|
{
|
|
public DbSet<Product> Products { get; set; }
|
|
}
|
|
|
|
protected class Product
|
|
{
|
|
public int Id { get; set; }
|
|
public string Name { get; set; }
|
|
}
|
|
|
|
protected virtual ExecutionStrategyContext CreateContext()
|
|
=> (ExecutionStrategyContext)Fixture.CreateContext();
|
|
|
|
private void CleanContext()
|
|
{
|
|
using var context = CreateContext();
|
|
foreach (var product in context.Products.ToList())
|
|
{
|
|
context.Remove(product);
|
|
context.SaveChanges();
|
|
}
|
|
}
|
|
|
|
public class ExecutionStrategyFixture : SharedStoreFixtureBase<DbContext>
|
|
{
|
|
protected override bool UsePooling => false;
|
|
protected override string StoreName { get; } = nameof(ExecutionStrategyTest);
|
|
public new RelationalTestStore TestStore => (RelationalTestStore)base.TestStore;
|
|
public TestSqlLoggerFactory TestSqlLoggerFactory => (TestSqlLoggerFactory)ListLoggerFactory;
|
|
protected override ITestStoreFactory TestStoreFactory => JetTestStoreFactory.Instance;
|
|
protected override Type ContextType { get; } = typeof(ExecutionStrategyContext);
|
|
|
|
protected override IServiceCollection AddServices(IServiceCollection serviceCollection)
|
|
=> base.AddServices(serviceCollection)
|
|
.AddSingleton<IRelationalTransactionFactory, TestRelationalTransactionFactory>()
|
|
.AddScoped<IJetRelationalConnection, TestJetConnection>()
|
|
.AddSingleton<IRelationalCommandBuilderFactory, TestRelationalCommandBuilderFactory>();
|
|
|
|
public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
|
|
{
|
|
var options = base.AddOptions(builder);
|
|
new JetDbContextOptionsBuilder(options).MaxBatchSize(1);
|
|
return options;
|
|
}
|
|
|
|
protected override bool ShouldLogCategory(string logCategory)
|
|
=> logCategory == DbLoggerCategory.Infrastructure.Name;
|
|
}
|
|
}
|
|
}
|