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.
EntityFrameworkCore.Jet/test/EFCore.Jet.FunctionalTests/SaveChangesInterceptionJetT...

210 lines
8.1 KiB
C#

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
using EntityFrameworkCore.Jet.FunctionalTests.TestUtilities;
using EntityFrameworkCore.Jet.Infrastructure;
using EntityFrameworkCore.Jet.Storage.Internal;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.TestUtilities;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace EntityFrameworkCore.Jet.FunctionalTests;
#nullable disable
public abstract class SaveChangesInterceptionJetTestBase(
SaveChangesInterceptionJetTestBase.InterceptionJetFixtureBase fixture)
: SaveChangesInterceptionTestBase(fixture)
{
[ConditionalTheory]
[InlineData(false, false, false)]
[InlineData(true, false, false)]
[InlineData(false, true, false)]
[InlineData(true, true, false)]
[InlineData(false, false, true)]
[InlineData(true, false, true)]
[InlineData(false, true, true)]
[InlineData(true, true, true)]
public virtual async Task Intercept_concurrency_with_relational_specific_data(bool async, bool inject, bool noAcceptChanges)
{
var saveChangesInterceptor = new RelationalConcurrencySaveChangesInterceptor();
var commandInterceptor = new TestCommandInterceptor();
var context = await CreateContextAsync(saveChangesInterceptor, commandInterceptor);
using var _ = context;
using var transaction = context.Database.BeginTransaction();
var entry = context.Entry(new Singularity { Id = 35, Type = "Red Dwarf" });
entry.State = EntityState.Modified;
using var listener = Fixture.SubscribeToDiagnosticListener(context.ContextId);
Exception thrown = null;
try
{
var __ = noAcceptChanges
? async
? await context.SaveChangesAsync()
: context.SaveChanges()
: async
? await context.SaveChangesAsync(acceptAllChangesOnSuccess: false)
: context.SaveChanges(acceptAllChangesOnSuccess: false);
}
catch (Exception e)
{
thrown = e;
}
Assert.Equal(async, saveChangesInterceptor.AsyncCalled);
Assert.NotEqual(async, saveChangesInterceptor.SyncCalled);
Assert.NotEqual(saveChangesInterceptor.AsyncCalled, saveChangesInterceptor.SyncCalled);
Assert.False(saveChangesInterceptor.FailedCalled);
Assert.Same(context, saveChangesInterceptor.Context);
Assert.Same(thrown, saveChangesInterceptor.Exception);
Assert.True(saveChangesInterceptor.ConcurrencyExceptionCalled);
Assert.Equal(1, saveChangesInterceptor.Entries.Count);
Assert.Same(entry.Entity, saveChangesInterceptor.Entries[0].Entity);
Assert.Same(commandInterceptor.Connection, saveChangesInterceptor.Connection);
Assert.Same(commandInterceptor.Command, saveChangesInterceptor.Command);
Assert.Same(commandInterceptor.DataReader, saveChangesInterceptor.DataReader);
Assert.Equal(commandInterceptor.ConnectionId, saveChangesInterceptor.ConnectionId);
Assert.Equal(commandInterceptor.CommandId, saveChangesInterceptor.CommandId);
}
protected class RelationalConcurrencySaveChangesInterceptor : SaveChangesInterceptorBase
{
public DbConnection Connection { get; set; }
public DbCommand Command { get; set; }
public DbDataReader DataReader { get; set; }
public Guid CommandId { get; set; }
public Guid ConnectionId { get; set; }
public override InterceptionResult ThrowingConcurrencyException(ConcurrencyExceptionEventData eventData, InterceptionResult result)
{
RecordEventData((RelationalConcurrencyExceptionEventData)eventData);
return base.ThrowingConcurrencyException(eventData, result);
}
public override ValueTask<InterceptionResult> ThrowingConcurrencyExceptionAsync(
ConcurrencyExceptionEventData eventData,
InterceptionResult result,
CancellationToken cancellationToken = default)
{
RecordEventData((RelationalConcurrencyExceptionEventData)eventData);
return base.ThrowingConcurrencyExceptionAsync(eventData, result, cancellationToken);
}
private void RecordEventData(RelationalConcurrencyExceptionEventData eventData)
{
Assert.NotNull(eventData.Connection);
Assert.NotNull(eventData.Command);
Assert.NotNull(eventData.DataReader);
DataReader = eventData.DataReader;
Command = eventData.Command;
Connection = eventData.Connection;
ConnectionId = eventData.ConnectionId;
CommandId = eventData.CommandId;
}
}
protected class TestCommandInterceptor : IDbCommandInterceptor
{
public DbConnection Connection { get; set; }
public DbCommand Command { get; set; }
public DbDataReader DataReader { get; set; }
public Guid CommandId { get; set; }
public Guid ConnectionId { get; set; }
public virtual DbDataReader ReaderExecuted(
DbCommand command,
CommandExecutedEventData eventData,
DbDataReader result)
{
RecordEventData(command, eventData, result);
return result;
}
public virtual ValueTask<DbDataReader> ReaderExecutedAsync(
DbCommand command,
CommandExecutedEventData eventData,
DbDataReader result,
CancellationToken cancellationToken = default)
{
RecordEventData(command, eventData, result);
return ValueTask.FromResult(result);
}
private void RecordEventData(DbCommand command, CommandExecutedEventData eventData, DbDataReader result)
{
DataReader = result;
Command = command;
Connection = command.Connection;
ConnectionId = eventData.ConnectionId;
CommandId = eventData.CommandId;
}
}
public abstract class InterceptionJetFixtureBase : InterceptionFixtureBase
{
protected override ITestStoreFactory TestStoreFactory
=> JetTestStoreFactory.Instance;
protected override IServiceCollection InjectInterceptors(
IServiceCollection serviceCollection,
IEnumerable<IInterceptor> injectedInterceptors)
=> base.InjectInterceptors(serviceCollection.AddEntityFrameworkJet(), injectedInterceptors);
public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
{
new JetDbContextOptionsBuilder(base.AddOptions(builder))
.ExecutionStrategy(d => new JetExecutionStrategy(d));
return builder;
}
}
public class SaveChangesInterceptionJetTest(SaveChangesInterceptionJetTest.InterceptionJetFixture fixture)
: SaveChangesInterceptionJetTestBase(fixture),
IClassFixture<SaveChangesInterceptionJetTest.InterceptionJetFixture>
{
public class InterceptionJetFixture : InterceptionJetFixtureBase
{
protected override string StoreName
=> "SaveChangesInterception";
protected override bool ShouldSubscribeToDiagnosticListener
=> false;
}
}
public class SaveChangesInterceptionWithDiagnosticsJetTest(
SaveChangesInterceptionWithDiagnosticsJetTest.InterceptionJetFixture fixture)
: SaveChangesInterceptionJetTestBase(fixture),
IClassFixture<SaveChangesInterceptionWithDiagnosticsJetTest.InterceptionJetFixture>
{
public class InterceptionJetFixture : InterceptionJetFixtureBase
{
protected override string StoreName
=> "SaveChangesInterceptionWithDiagnostics";
protected override bool ShouldSubscribeToDiagnosticListener
=> true;
}
}
}