Files
Musify/backend/Tests/Musify.Infrastructure.Tests/MassTransit/LifeCycleActivityTests.cs
T
2026-09-24 13:24:43 +02:00

187 lines
7.8 KiB
C#

using MassTransit;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging.Abstractions;
using Musify.Domain.Entities;
using Musify.Domain.ValueObjects;
using Musify.Infrastructure.MassTransit.Activities.LifeCycle;
using Musify.Infrastructure.MassTransit.Arguments;
using Musify.Infrastructure.Tests.TestSupport;
using NSubstitute;
using Xunit;
namespace Musify.Infrastructure.Tests.MassTransit
{
[Collection(InfrastructureCollection.Name)]
public sealed class LifeCycleActivityTests(InfrastructureTestFixture fixture)
{
private static CancellationToken Ct => TestContext.Current.CancellationToken;
[Fact]
public async Task MarkTrack_ExistingTrack_SetsTheStatus()
{
var track = await SeedTrackAsync();
await using var database = fixture.CreateDatabase();
var activity = new MarkTrackLifeCycleActivity(database, NullLogger<MarkTrackLifeCycleActivity>.Instance);
var context = ExecuteContextFor(new MarkLifeCycleArguments(track.Id, LifeCycleStatus.Removing));
await activity.Execute(context);
context.Received(1).Completed();
await using var verifier = fixture.CreateDatabase();
var stored = await verifier.Tracks.AsNoTracking().SingleAsync(t => t.Id == track.Id, Ct);
Assert.Equal(LifeCycleStatus.Removing, stored.LifeCycleStatus);
}
[Fact]
public async Task MarkAlbum_ExistingAlbum_SetsTheStatus()
{
var album = await SeedAlbumAsync();
await using var database = fixture.CreateDatabase();
var activity = new MarkAlbumLifeCycleActivity(database, NullLogger<MarkAlbumLifeCycleActivity>.Instance);
await activity.Execute(ExecuteContextFor(new MarkLifeCycleArguments(album.Id, LifeCycleStatus.Failed)));
await using var verifier = fixture.CreateDatabase();
Assert.Equal(LifeCycleStatus.Failed, (await verifier.Albums.AsNoTracking().SingleAsync(a => a.Id == album.Id, Ct)).LifeCycleStatus);
}
[Fact]
public async Task MarkPlayList_ExistingPlayList_SetsTheStatus()
{
var playList = await SeedPlayListAsync();
await using var database = fixture.CreateDatabase();
var activity = new MarkPlayListLifeCycleActivity(database, NullLogger<MarkPlayListLifeCycleActivity>.Instance);
await activity.Execute(ExecuteContextFor(new MarkLifeCycleArguments(playList.Id, LifeCycleStatus.Removing)));
await using var verifier = fixture.CreateDatabase();
Assert.Equal(LifeCycleStatus.Removing, (await verifier.PlayLists.AsNoTracking().SingleAsync(p => p.Id == playList.Id, Ct)).LifeCycleStatus);
}
[Fact]
public async Task Mark_MissingEntity_CompletesWithoutFailing()
{
await using var database = fixture.CreateDatabase();
var activity = new MarkTrackLifeCycleActivity(database, NullLogger<MarkTrackLifeCycleActivity>.Instance);
var context = ExecuteContextFor(new MarkLifeCycleArguments(Guid.NewGuid(), LifeCycleStatus.Failed));
await activity.Execute(context);
context.Received(1).Completed();
}
[Fact]
public async Task DeleteTrack_ExistingTrack_RemovesTheRow()
{
var track = await SeedTrackAsync();
await using var database = fixture.CreateDatabase();
var activity = new DeleteTrackActivity(database, NullLogger<DeleteTrackActivity>.Instance);
var context = ExecuteContextFor(new DeleteEntityArguments(track.Id));
await activity.Execute(context);
context.Received(1).Completed();
await using var verifier = fixture.CreateDatabase();
Assert.False(await verifier.Tracks.AnyAsync(t => t.Id == track.Id, Ct));
}
[Fact]
public async Task DeleteAlbum_ExistingAlbum_RemovesTheRow()
{
var album = await SeedAlbumAsync();
await using var database = fixture.CreateDatabase();
var activity = new DeleteAlbumActivity(database, NullLogger<DeleteAlbumActivity>.Instance);
await activity.Execute(ExecuteContextFor(new DeleteEntityArguments(album.Id)));
await using var verifier = fixture.CreateDatabase();
Assert.False(await verifier.Albums.AnyAsync(a => a.Id == album.Id, Ct));
}
[Fact]
public async Task DeletePlayList_ExistingPlayList_RemovesTheRow()
{
var playList = await SeedPlayListAsync();
await using var database = fixture.CreateDatabase();
var activity = new DeletePlayListActivity(database, NullLogger<DeletePlayListActivity>.Instance);
await activity.Execute(ExecuteContextFor(new DeleteEntityArguments(playList.Id)));
await using var verifier = fixture.CreateDatabase();
Assert.False(await verifier.PlayLists.AnyAsync(p => p.Id == playList.Id, Ct));
}
[Fact]
public async Task Delete_MissingEntity_CompletesWithoutFailing()
{
await using var database = fixture.CreateDatabase();
var activity = new DeleteTrackActivity(database, NullLogger<DeleteTrackActivity>.Instance);
var context = ExecuteContextFor(new DeleteEntityArguments(Guid.NewGuid()));
await activity.Execute(context);
context.Received(1).Completed();
}
private static ExecuteContext<TArguments> ExecuteContextFor<TArguments>(TArguments arguments)
where TArguments : class
{
var context = Substitute.For<ExecuteContext<TArguments>>();
context.Arguments.Returns(arguments);
context.CancellationToken.Returns(Ct);
return context;
}
private async Task<User> SeedUserAsync()
{
await using var database = fixture.CreateDatabase();
var name = $"lifecycle-{Guid.NewGuid():N}"[..30];
var user = new User { Id = Random.Shared.NextInt64(1, long.MaxValue), Name = name, NormalizedName = name.ToUpperInvariant() };
await database.Users.AddAsync(user, Ct);
await database.SaveChangesAsync(Ct);
return user;
}
private async Task<Track> SeedTrackAsync()
{
var user = await SeedUserAsync();
await using var database = fixture.CreateDatabase();
var title = $"track-{Guid.NewGuid():N}";
var track = new Track
{
Title = title,
NormalizedTitle = title.ToUpperInvariant(),
DurationSeconds = 10,
OwnerUserId = user.Id,
Pictures = new TrackPictures(),
Audio = new TrackAudio()
};
await database.Tracks.AddAsync(track, Ct);
await database.SaveChangesAsync(Ct);
return track;
}
private async Task<Album> SeedAlbumAsync()
{
var user = await SeedUserAsync();
await using var database = fixture.CreateDatabase();
var title = $"album-{Guid.NewGuid():N}";
var album = new Album { Title = title, NormalizedTitle = title.ToUpperInvariant(), OwnerUserId = user.Id };
await database.Albums.AddAsync(album, Ct);
await database.SaveChangesAsync(Ct);
return album;
}
private async Task<PlayList> SeedPlayListAsync()
{
var user = await SeedUserAsync();
await using var database = fixture.CreateDatabase();
var name = $"pl-{Guid.NewGuid():N}"[..30];
var playList = new PlayList { Name = name, NormalizedName = name.ToUpperInvariant(), OwnerUserId = user.Id };
await database.PlayLists.AddAsync(playList, Ct);
await database.SaveChangesAsync(Ct);
return playList;
}
}
}