Simplify infrastructure services and move all recurring jobs to Hangfire
This commit is contained in:
@@ -18,7 +18,7 @@ public sealed class AlbumEndpointsTests(ApiTestFixture fixture)
|
||||
private async Task<Guid> CreatePictureIntentAsync(HttpClient client)
|
||||
{
|
||||
fixture.StorageService
|
||||
.GetUploadUrlAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<TimeSpan>(), Arg.Any<CancellationToken>())
|
||||
.GetUploadUrlAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<TimeSpan>(), Arg.Any<bool>(), Arg.Any<CancellationToken>())
|
||||
.Returns("https://storage.musify.test/presigned-upload");
|
||||
fixture.StorageService
|
||||
.HeadObjectAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<CancellationToken>())
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ public sealed class RequestAlbumPictureUploadCommandHandlerTests : HandlerTestBa
|
||||
private RequestAlbumPictureUploadCommandHandler CreateHandler(UploadIntentConfiguration? uploadIntentConfig = null)
|
||||
{
|
||||
storageService
|
||||
.GetUploadUrlAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<TimeSpan>(), Arg.Any<CancellationToken>())
|
||||
.GetUploadUrlAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<TimeSpan>(), Arg.Any<bool>(), Arg.Any<CancellationToken>())
|
||||
.Returns("https://storage.musify.test/presigned-upload");
|
||||
|
||||
var config = uploadIntentConfig ?? TestConfigurations.UploadIntent();
|
||||
|
||||
+3
-9
@@ -17,9 +17,7 @@ public sealed class GenerateMixesForUserCommandHandlerTests : HandlerTestBase
|
||||
var user = TestEntities.User();
|
||||
await SeedAsync(user);
|
||||
|
||||
var result = await CreateHandler().Handle(new GenerateMixesForUserCommand(user.Id), TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.False(result.IsError);
|
||||
await CreateHandler().Handle(new GenerateMixesForUserCommand(user.Id), TestContext.Current.CancellationToken);
|
||||
Assert.Empty(await Database.Mixes.ToListAsync(TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
@@ -32,9 +30,7 @@ public sealed class GenerateMixesForUserCommandHandlerTests : HandlerTestBase
|
||||
user, track,
|
||||
TestEntities.ListeningHistory(user.Id, track.Id));
|
||||
|
||||
var result = await CreateHandler().Handle(new GenerateMixesForUserCommand(user.Id), TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.False(result.IsError);
|
||||
await CreateHandler().Handle(new GenerateMixesForUserCommand(user.Id), TestContext.Current.CancellationToken);
|
||||
var mixes = await Database.Mixes.ToListAsync(TestContext.Current.CancellationToken);
|
||||
Assert.Single(mixes);
|
||||
Assert.Equal(MixKind.Daily, mixes[0].Kind);
|
||||
@@ -54,9 +50,7 @@ public sealed class GenerateMixesForUserCommandHandlerTests : HandlerTestBase
|
||||
user, listenedTrack, unheardTrack, staleMix, staleItem,
|
||||
TestEntities.ListeningHistory(user.Id, listenedTrack.Id));
|
||||
|
||||
var result = await CreateHandler().Handle(new GenerateMixesForUserCommand(user.Id), TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.False(result.IsError);
|
||||
await CreateHandler().Handle(new GenerateMixesForUserCommand(user.Id), TestContext.Current.CancellationToken);
|
||||
var mixes = await Database.Mixes.ToListAsync(TestContext.Current.CancellationToken);
|
||||
Assert.DoesNotContain(mixes, mix => mix.Id == staleMix.Id);
|
||||
Assert.Contains(mixes, mix => mix.Kind == MixKind.Discovery);
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ public sealed class RequestPlayListPictureUploadCommandHandlerTests : HandlerTes
|
||||
private RequestPlayListPictureUploadCommandHandler CreateHandler(UploadIntentConfiguration? uploadIntentConfig = null)
|
||||
{
|
||||
storageService
|
||||
.GetUploadUrlAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<TimeSpan>(), Arg.Any<CancellationToken>())
|
||||
.GetUploadUrlAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<TimeSpan>(), Arg.Any<bool>(), Arg.Any<CancellationToken>())
|
||||
.Returns("https://storage.musify.test/presigned-upload");
|
||||
|
||||
var config = uploadIntentConfig ?? TestConfigurations.UploadIntent();
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ public sealed class RequestTrackUploadUrlsCommandHandlerTests : HandlerTestBase
|
||||
private RequestTrackUploadUrlsCommandHandler CreateHandler(UploadIntentConfiguration? uploadIntentConfig = null)
|
||||
{
|
||||
storageService
|
||||
.GetUploadUrlAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<TimeSpan>(), Arg.Any<CancellationToken>())
|
||||
.GetUploadUrlAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<TimeSpan>(), Arg.Any<bool>(), Arg.Any<CancellationToken>())
|
||||
.Returns("https://storage.musify.test/presigned-upload");
|
||||
|
||||
var config = uploadIntentConfig ?? TestConfigurations.UploadIntent();
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Musify.Application.Contracts;
|
||||
using Musify.Application.Tests.TestSupport;
|
||||
using Musify.Application.UploadIntents;
|
||||
using Musify.Domain.ValueObjects;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Musify.Application.Tests.UploadIntents;
|
||||
|
||||
public sealed class UploadIntentJobsCommandHandlerTests : HandlerTestBase
|
||||
{
|
||||
[Fact]
|
||||
public async Task ExpireUploadIntents_OverdueIssuedIntent_IsMarkedExpired()
|
||||
{
|
||||
var owner = TestEntities.User();
|
||||
var overdue = TestEntities.UploadIntent(owner.Id, expiresAt: DateTime.UtcNow.AddMinutes(-5));
|
||||
var active = TestEntities.UploadIntent(owner.Id, expiresAt: DateTime.UtcNow.AddMinutes(5));
|
||||
await SeedAsync(owner, overdue, active);
|
||||
var handler = new ExpireUploadIntentsCommandHandler(
|
||||
Database, TestConfigurations.UploadIntent(), NoOpLogger<ExpireUploadIntentsCommandHandler>());
|
||||
|
||||
var changed = await handler.Handle(new ExpireUploadIntentsCommand(), TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal(1, changed);
|
||||
var stored = await Database.UploadIntents.AsNoTracking().ToListAsync(TestContext.Current.CancellationToken);
|
||||
Assert.Equal(UploadIntentStatus.Expired, stored.Single(intent => intent.Id == overdue.Id).Status);
|
||||
Assert.Equal(UploadIntentStatus.Issued, stored.Single(intent => intent.Id == active.Id).Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExpireUploadIntents_IntentExpiredLongAgo_IsDeleted()
|
||||
{
|
||||
var owner = TestEntities.User();
|
||||
var old = TestEntities.UploadIntent(
|
||||
owner.Id, status: UploadIntentStatus.Expired, expiresAt: DateTime.UtcNow.AddDays(-30));
|
||||
await SeedAsync(owner, old);
|
||||
var handler = new ExpireUploadIntentsCommandHandler(
|
||||
Database, TestConfigurations.UploadIntent(), NoOpLogger<ExpireUploadIntentsCommandHandler>());
|
||||
|
||||
await handler.Handle(new ExpireUploadIntentsCommand(), TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Empty(await Database.UploadIntents.ToListAsync(TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteStaleTempUploads_RemovesOnlyObjectsOlderThanTheRetention()
|
||||
{
|
||||
var storage = Substitute.For<IStorageService>();
|
||||
storage.ListObjectsAsync("test-bucket", "temp", Arg.Any<CancellationToken>()).Returns(Objects(
|
||||
new StorageObject("temp/old", DateTime.UtcNow.AddDays(-10)),
|
||||
new StorageObject("temp/new", DateTime.UtcNow)));
|
||||
var handler = new DeleteStaleTempUploadsCommandHandler(
|
||||
storage, TestConfigurations.Storage("test-bucket"), TestConfigurations.UploadIntent(),
|
||||
NoOpLogger<DeleteStaleTempUploadsCommandHandler>());
|
||||
|
||||
var deleted = await handler.Handle(new DeleteStaleTempUploadsCommand(), TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal(1, deleted);
|
||||
await storage.Received(1).RemoveFileAsync("test-bucket", "temp/old", Arg.Any<CancellationToken>());
|
||||
await storage.DidNotReceive().RemoveFileAsync("test-bucket", "temp/new", Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
private static async IAsyncEnumerable<StorageObject> Objects(params StorageObject[] objects)
|
||||
{
|
||||
foreach (var item in objects)
|
||||
yield return item;
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,7 @@ public sealed class StorageServiceTests(InfrastructureTestFixture fixture) : IAs
|
||||
var key = $"tests/{Guid.NewGuid():N}/presigned.txt";
|
||||
|
||||
var uploadUrl = await service.GetUploadUrlAsync(
|
||||
InfrastructureTestFixture.S3Bucket, key, "text/plain", TimeSpan.FromMinutes(5), TestContext.Current.CancellationToken);
|
||||
InfrastructureTestFixture.S3Bucket, key, "text/plain", TimeSpan.FromMinutes(5), cancellationToken: TestContext.Current.CancellationToken);
|
||||
|
||||
using var httpClient = new HttpClient();
|
||||
using var request = new HttpRequestMessage(HttpMethod.Put, uploadUrl)
|
||||
|
||||
Reference in New Issue
Block a user