-
Notifications
You must be signed in to change notification settings - Fork 0
/
ApiConcurrencyTests.cs
98 lines (82 loc) · 3.7 KB
/
ApiConcurrencyTests.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
using System.Net;
using Database;
using DatabaseIntegrationTestSample;
using Entities;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.EntityFrameworkCore;
using Xunit.Extensions.AssemblyFixture;
namespace IntegrationTests;
public class ApiConcurrencyTests : IClassFixture<WebApplicationFactory<Program>>, IAssemblyFixture<MsSqlFixture>, IAsyncLifetime, ICommitInterceptor
{
private readonly WebApplicationFactory<Program> _factory;
public ApiConcurrencyTests(WebApplicationFactory<Program> factory, MsSqlFixture msSqlFixture)
{
_factory = factory.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration((context, configurationBuilder) =>
{
configurationBuilder.AddInMemoryCollection(new Dictionary<string, string?>()
{
["ConnectionStrings:SampleDb"] = msSqlFixture.GetConnectionString(Guid.NewGuid())
});
});
builder.ConfigureTestServices(collection =>
{
collection.BuildServiceProvider().GetRequiredService<SampleDbContext>().Database.Migrate();
collection.Remove(collection.Single(x => x.ImplementationType == typeof(SampleDbContext)));
collection.AddSampleDbContext<TestDbContext>();
collection.AddSingleton<ICommitInterceptor>(this);
});
});
}
[Fact]
public async Task GivenAttachmentIsInUseShouldNotBeAbleToDeleteIt()
{
var client = _factory.CreateClient();
var createAttachmentResponse = await client.PostAsync("attachment?url=example", null);
createAttachmentResponse.EnsureSuccessStatusCode();
var attachment = await createAttachmentResponse.Content.ReadFromJsonAsync<CreateAttachmentResponse>();
var deleteAttachmentResponse = await client.DeleteAsync($"attachment?id={attachment.Id}");
Assert.Equal(HttpStatusCode.BadRequest, deleteAttachmentResponse.StatusCode);
}
// ReSharper disable once ClassNeverInstantiated.Local
private record CreateAttachmentResponse(int Id);
public async Task InitializeAsync()
{
}
public async Task DisposeAsync()
{
await _factory.DisposeAsync();
}
private class TestDbContext(DbContextOptions<SampleDbContext> options, ICommitInterceptor commitInterceptor) : SampleDbContext(options)
{
public Task<int> TestSaveChangesAsync(CancellationToken cancellationToken = new()) => base.SaveChangesAsync(cancellationToken);
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new())
{
var deletedAttachments = ChangeTracker.Entries<Attachment>()
.Where(x => x.State == EntityState.Deleted)
.Select(x => x.Entity);
await commitInterceptor.OnAttachmentsDeleted(deletedAttachments);
return await base.SaveChangesAsync(cancellationToken);
}
}
async Task ICommitInterceptor.OnAttachmentsDeleted(IEnumerable<Attachment> deletedAttachments)
{
await using var scope = _factory.Services.CreateAsyncScope();
var dbContext = scope.ServiceProvider.GetRequiredService<TestDbContext>();
foreach (var deletedAttachment in deletedAttachments)
{
await dbContext.MessageAttachments.AddAsync(new MessageAttachment
{
AttachmentId = deletedAttachment.Id,
Message = new Message { Body = "test" }
});
}
await dbContext.TestSaveChangesAsync();
}
}
internal interface ICommitInterceptor
{
Task OnAttachmentsDeleted(IEnumerable<Attachment> deletedAttachments);
}