Migrate backend test suite from xUnit v2 to v3

- Directory.Packages.props: xunit 2.9.3 -> xunit.v3 4.0.0, bump
  xunit.runner.visualstudio to the matching 4.0.0
- All 5 test csproj: xunit -> xunit.v3 package reference, add
  <OutputType>Exe</OutputType> (v3 test projects are standalone
  executables)
- backend/global.json: opt dotnet test into the new MTP-native mode
  (.NET 10 SDK removed the old VSTest bridge for MTP-based test
  projects like xunit v3)
- IAsyncLifetime implementations (HandlerTestBase, ApiTestFixture,
  InfrastructureTestFixture, StorageServiceTests): v3's IAsyncLifetime
  now IS IAsyncDisposable, so InitializeAsync/DisposeAsync return
  ValueTask instead of Task. ApiTestFixture specifically now overrides
  WebApplicationFactory.DisposeAsync instead of implementing
  IAsyncLifetime.DisposeAsync explicitly, since v3 collapses both to
  the same single DisposeAsync slot
- Replaced CancellationToken.None with TestContext.Current.CancellationToken
  across the suite (a v3-only API) and added it to every call that
  was silently omitting a CancellationToken argument, per the new
  xUnit1051 analyzer warnings that came with the v3 package

Verified: dotnet build (0 warnings, 0 errors) and dotnet test, 250/250
passing under the new MTP runner.
This commit is contained in:
2026-09-09 22:11:29 +02:00
parent b57949a6bc
commit 98e6dfc4c4
62 changed files with 286 additions and 272 deletions
@@ -24,7 +24,7 @@ public sealed class AlbumEndpointsTests(ApiTestFixture fixture)
public async Task PostAlbums_NoAuthHeader_ReturnsUnauthorized()
{
var response = await fixture.CreateAnonymousClient()
.PostAsJsonAsync("/albums", new CreateAlbumRequest("Unauthorized Album", null, null));
.PostAsJsonAsync("/albums", new CreateAlbumRequest("Unauthorized Album", null, null), TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
@@ -35,10 +35,10 @@ public sealed class AlbumEndpointsTests(ApiTestFixture fixture)
var userId = await CreateUserAsync();
var client = fixture.CreateAuthenticatedClient(userId);
var response = await client.PostAsJsonAsync("/albums", new CreateAlbumRequest("My Album", "desc", 2024));
var response = await client.PostAsJsonAsync("/albums", new CreateAlbumRequest("My Album", "desc", 2024), TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
var body = await response.Content.ReadFromJsonAsync<AlbumApplicationResponse>();
var body = await response.Content.ReadFromJsonAsync<AlbumApplicationResponse>(TestContext.Current.CancellationToken);
Assert.NotNull(body);
Assert.Equal("My Album", body.Title);
Assert.Equal(userId, body.OwnerUserId);
@@ -50,7 +50,7 @@ public sealed class AlbumEndpointsTests(ApiTestFixture fixture)
var userId = await CreateUserAsync();
var client = fixture.CreateAuthenticatedClient(userId);
var response = await client.PostAsJsonAsync("/albums", new CreateAlbumRequest("", null, null));
var response = await client.PostAsJsonAsync("/albums", new CreateAlbumRequest("", null, null), TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
@@ -60,10 +60,10 @@ public sealed class AlbumEndpointsTests(ApiTestFixture fixture)
{
var userId = await CreateUserAsync();
var client = fixture.CreateAuthenticatedClient(userId);
var created = await (await client.PostAsJsonAsync("/albums", new CreateAlbumRequest("Findable", null, null)))
.Content.ReadFromJsonAsync<AlbumApplicationResponse>();
var created = await (await client.PostAsJsonAsync("/albums", new CreateAlbumRequest("Findable", null, null), TestContext.Current.CancellationToken))
.Content.ReadFromJsonAsync<AlbumApplicationResponse>(TestContext.Current.CancellationToken);
var response = await fixture.CreateAnonymousClient().GetAsync($"/albums/{created!.Id}");
var response = await fixture.CreateAnonymousClient().GetAsync($"/albums/{created!.Id}", TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
@@ -73,10 +73,10 @@ public sealed class AlbumEndpointsTests(ApiTestFixture fixture)
{
var owner = await CreateUserAsync();
var stranger = await CreateUserAsync();
var created = await (await fixture.CreateAuthenticatedClient(owner).PostAsJsonAsync("/albums", new CreateAlbumRequest("Owned", null, null)))
.Content.ReadFromJsonAsync<AlbumApplicationResponse>();
var created = await (await fixture.CreateAuthenticatedClient(owner).PostAsJsonAsync("/albums", new CreateAlbumRequest("Owned", null, null), TestContext.Current.CancellationToken))
.Content.ReadFromJsonAsync<AlbumApplicationResponse>(TestContext.Current.CancellationToken);
var response = await fixture.CreateAuthenticatedClient(stranger).DeleteAsync($"/albums/{created!.Id}");
var response = await fixture.CreateAuthenticatedClient(stranger).DeleteAsync($"/albums/{created!.Id}", TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
@@ -86,11 +86,11 @@ public sealed class AlbumEndpointsTests(ApiTestFixture fixture)
{
var userId = await CreateUserAsync();
var client = fixture.CreateAuthenticatedClient(userId);
var created = await (await client.PostAsJsonAsync("/albums", new CreateAlbumRequest("Deletable", null, null)))
.Content.ReadFromJsonAsync<AlbumApplicationResponse>();
var created = await (await client.PostAsJsonAsync("/albums", new CreateAlbumRequest("Deletable", null, null), TestContext.Current.CancellationToken))
.Content.ReadFromJsonAsync<AlbumApplicationResponse>(TestContext.Current.CancellationToken);
var deleteResponse = await client.DeleteAsync($"/albums/{created!.Id}");
var getResponse = await fixture.CreateAnonymousClient().GetAsync($"/albums/{created.Id}");
var deleteResponse = await client.DeleteAsync($"/albums/{created!.Id}", TestContext.Current.CancellationToken);
var getResponse = await fixture.CreateAnonymousClient().GetAsync($"/albums/{created.Id}", TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.NoContent, deleteResponse.StatusCode);
Assert.Equal(HttpStatusCode.NotFound, getResponse.StatusCode);
@@ -16,11 +16,11 @@ public sealed class UserEndpointsTests(ApiTestFixture fixture)
var client = fixture.CreateAnonymousClient();
var userId = Random.Shared.NextInt64(1, long.MaxValue);
var response = await client.PostAsJsonAsync("/users", new CreateUserRequest(userId, "Jane Doe", "Jane", "Doe"));
var response = await client.PostAsJsonAsync("/users", new CreateUserRequest(userId, "Jane Doe", "Jane", "Doe"), TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
Assert.Equal($"/users/{userId}", response.Headers.Location?.OriginalString);
var body = await response.Content.ReadFromJsonAsync<UserApplicationResponse>();
var body = await response.Content.ReadFromJsonAsync<UserApplicationResponse>(TestContext.Current.CancellationToken);
Assert.NotNull(body);
Assert.Equal("Jane Doe", body.Name);
}
@@ -30,7 +30,7 @@ public sealed class UserEndpointsTests(ApiTestFixture fixture)
{
var client = fixture.CreateAnonymousClient();
var response = await client.PostAsJsonAsync("/users", new CreateUserRequest(Random.Shared.NextInt64(1, long.MaxValue), "", null, null));
var response = await client.PostAsJsonAsync("/users", new CreateUserRequest(Random.Shared.NextInt64(1, long.MaxValue), "", null, null), TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
}
@@ -40,9 +40,9 @@ public sealed class UserEndpointsTests(ApiTestFixture fixture)
{
var client = fixture.CreateAnonymousClient();
var userId = Random.Shared.NextInt64(1, long.MaxValue);
await client.PostAsJsonAsync("/users", new CreateUserRequest(userId, "First", null, null));
await client.PostAsJsonAsync("/users", new CreateUserRequest(userId, "First", null, null), TestContext.Current.CancellationToken);
var response = await client.PostAsJsonAsync("/users", new CreateUserRequest(userId, "Second", null, null));
var response = await client.PostAsJsonAsync("/users", new CreateUserRequest(userId, "Second", null, null), TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.Conflict, response.StatusCode);
}
@@ -52,12 +52,12 @@ public sealed class UserEndpointsTests(ApiTestFixture fixture)
{
var client = fixture.CreateAnonymousClient();
var userId = Random.Shared.NextInt64(1, long.MaxValue);
await client.PostAsJsonAsync("/users", new CreateUserRequest(userId, "Findable User", null, null));
await client.PostAsJsonAsync("/users", new CreateUserRequest(userId, "Findable User", null, null), TestContext.Current.CancellationToken);
var response = await client.GetAsync($"/users/{userId}");
var response = await client.GetAsync($"/users/{userId}", TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadFromJsonAsync<UserApplicationResponse>();
var body = await response.Content.ReadFromJsonAsync<UserApplicationResponse>(TestContext.Current.CancellationToken);
Assert.Equal("Findable User", body?.Name);
}
@@ -66,7 +66,7 @@ public sealed class UserEndpointsTests(ApiTestFixture fixture)
{
var client = fixture.CreateAnonymousClient();
var response = await client.GetAsync($"/users/{Random.Shared.NextInt64(1, long.MaxValue)}");
var response = await client.GetAsync($"/users/{Random.Shared.NextInt64(1, long.MaxValue)}", TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
@@ -3,6 +3,7 @@
<PropertyGroup>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
@@ -10,7 +11,7 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="NSubstitute" />
<PackageReference Include="Testcontainers.PostgreSql" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.v3" />
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
@@ -37,7 +37,7 @@ public sealed class ApiTestFixture : WebApplicationFactory<Program>, IAsyncLifet
public IStreamTicketService StreamTicketService { get; } = Substitute.For<IStreamTicketService>();
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await postgres.StartAsync();
@@ -46,7 +46,11 @@ public sealed class ApiTestFixture : WebApplicationFactory<Program>, IAsyncLifet
await database.Database.MigrateAsync();
}
async Task IAsyncLifetime.DisposeAsync()
// xUnit v3's IAsyncLifetime IS System.IAsyncDisposable (rather than declaring its own
// Task-returning DisposeAsync as in v2), so there is a single DisposeAsync slot to fill —
// override the one WebApplicationFactory already provides instead of implementing the
// interface explicitly alongside it.
public override async ValueTask DisposeAsync()
{
await base.DisposeAsync();
await postgres.DisposeAsync();
@@ -19,10 +19,10 @@ public sealed class AddTrackToAlbumCommandHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, album, track);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(owner.Id, album.Id, track.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(owner.Id, album.Id, track.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var link = Assert.Single(await Database.AlbumHasTracks.ToListAsync());
var link = Assert.Single(await Database.AlbumHasTracks.ToListAsync(TestContext.Current.CancellationToken));
Assert.Equal(1, link.TrackNumber);
}
@@ -33,7 +33,7 @@ public sealed class AddTrackToAlbumCommandHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, track);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(owner.Id, Guid.NewGuid(), track.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(owner.Id, Guid.NewGuid(), track.Id), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -47,7 +47,7 @@ public sealed class AddTrackToAlbumCommandHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, stranger, album, track);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(stranger.Id, album.Id, track.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(stranger.Id, album.Id, track.Id), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
}
@@ -59,7 +59,7 @@ public sealed class AddTrackToAlbumCommandHandlerTests : HandlerTestBase
var album = TestEntities.UserAlbum(owner.Id);
await SeedAsync(owner, album);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(owner.Id, album.Id, Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(owner.Id, album.Id, Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -73,7 +73,7 @@ public sealed class AddTrackToAlbumCommandHandlerTests : HandlerTestBase
var foreignTrack = TestEntities.LocalTrack(otherOwner);
await SeedAsync(owner, otherOwner, album, foreignTrack);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(owner.Id, album.Id, foreignTrack.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(owner.Id, album.Id, foreignTrack.Id), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
}
@@ -87,7 +87,7 @@ public sealed class AddTrackToAlbumCommandHandlerTests : HandlerTestBase
var link = new AlbumHasTrack { AlbumId = album.Id, TrackId = track.Id, TrackNumber = 1 };
await SeedAsync(owner, album, track, link);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(owner.Id, album.Id, track.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(owner.Id, album.Id, track.Id), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
@@ -102,10 +102,10 @@ public sealed class AddTrackToAlbumCommandHandlerTests : HandlerTestBase
var existingLink = new AlbumHasTrack { AlbumId = album.Id, TrackId = firstTrack.Id, TrackNumber = 3 };
await SeedAsync(owner, album, firstTrack, secondTrack, existingLink);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(owner.Id, album.Id, secondTrack.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new AddTrackToAlbumCommand(owner.Id, album.Id, secondTrack.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var newLink = await Database.AlbumHasTracks.SingleAsync(l => l.TrackId == secondTrack.Id);
var newLink = await Database.AlbumHasTracks.SingleAsync(l => l.TrackId == secondTrack.Id, TestContext.Current.CancellationToken);
Assert.Equal(4, newLink.TrackNumber);
}
}
@@ -17,7 +17,7 @@ public sealed class CreateAlbumCommandHandlerTests : HandlerTestBase
var command = new CreateAlbumCommand(owner.Id, " My Album ", "A description", 2024);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("My Album", result.Value.Title);
@@ -26,7 +26,7 @@ public sealed class CreateAlbumCommandHandlerTests : HandlerTestBase
Assert.Equal(owner.Id, result.Value.OwnerUserId);
Assert.Equal(0, result.Value.TrackCount);
var stored = await Database.UserAlbums.FindAsync(result.Value.Id);
var stored = await Database.UserAlbums.FindAsync([result.Value.Id], TestContext.Current.CancellationToken);
Assert.NotNull(stored);
Assert.Equal("MY ALBUM", stored.NormalizedTitle);
}
@@ -36,7 +36,7 @@ public sealed class CreateAlbumCommandHandlerTests : HandlerTestBase
{
var command = new CreateAlbumCommand(UserId: 404, "Orphan Album", Description: null, ReleaseYear: null);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -16,16 +16,16 @@ public sealed class DeleteAlbumCommandHandlerTests : HandlerTestBase
var album = TestEntities.UserAlbum(owner.Id);
await SeedAsync(owner, album);
var result = await CreateHandler().Handle(new DeleteAlbumCommand(owner.Id, album.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new DeleteAlbumCommand(owner.Id, album.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Null(await Database.UserAlbums.FindAsync(album.Id));
Assert.Null(await Database.UserAlbums.FindAsync([album.Id], TestContext.Current.CancellationToken));
}
[Fact]
public async Task Handle_AlbumMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new DeleteAlbumCommand(1, Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new DeleteAlbumCommand(1, Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -38,9 +38,9 @@ public sealed class DeleteAlbumCommandHandlerTests : HandlerTestBase
var album = TestEntities.UserAlbum(owner.Id);
await SeedAsync(owner, stranger, album);
var result = await CreateHandler().Handle(new DeleteAlbumCommand(stranger.Id, album.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new DeleteAlbumCommand(stranger.Id, album.Id), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
Assert.NotNull(await Database.UserAlbums.FindAsync(album.Id));
Assert.NotNull(await Database.UserAlbums.FindAsync([album.Id], TestContext.Current.CancellationToken));
}
}
@@ -18,7 +18,7 @@ public sealed class GetAlbumByIdQueryHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, album, track, new AlbumHasTrack { AlbumId = album.Id, TrackId = track.Id, TrackNumber = 1 });
var result = await CreateHandler().Handle(new GetAlbumByIdQuery(album.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GetAlbumByIdQuery(album.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(album.Id, result.Value.Id);
@@ -29,7 +29,7 @@ public sealed class GetAlbumByIdQueryHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_AlbumMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new GetAlbumByIdQuery(Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new GetAlbumByIdQuery(Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -22,7 +22,7 @@ public sealed class GetAlbumTracksQueryHandlerTests : HandlerTestBase
new AlbumHasTrack { AlbumId = album.Id, TrackId = second.Id, TrackNumber = 2 },
new AlbumHasTrack { AlbumId = album.Id, TrackId = first.Id, TrackNumber = 1 });
var result = await CreateHandler().Handle(new GetAlbumTracksQuery(album.Id, PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetAlbumTracksQuery(album.Id, PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(["First", "Second"], result.Value.Items.Select(track => track.Title));
@@ -31,7 +31,7 @@ public sealed class GetAlbumTracksQueryHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_AlbumMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new GetAlbumTracksQuery(Guid.NewGuid(), PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetAlbumTracksQuery(Guid.NewGuid(), PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -16,7 +16,7 @@ public sealed class GetAlbumsByUserIdQueryHandlerTests : HandlerTestBase
var other = TestEntities.User(2, "other");
await SeedAsync(owner, other, TestEntities.UserAlbum(owner.Id, "Mine"), TestEntities.UserAlbum(other.Id, "Theirs"));
var result = await CreateHandler().Handle(new GetAlbumsByUserIdQuery(owner.Id, PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetAlbumsByUserIdQuery(owner.Id, PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var album = Assert.Single(result.Value.Items);
@@ -26,7 +26,7 @@ public sealed class GetAlbumsByUserIdQueryHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_UserMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new GetAlbumsByUserIdQuery(404, PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetAlbumsByUserIdQuery(404, PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -14,7 +14,7 @@ public sealed class GetAlbumsQueryHandlerTests : HandlerTestBase
var owner = TestEntities.User();
await SeedAsync(owner, TestEntities.UserAlbum(owner.Id, "Alpha"), TestEntities.UserAlbum(owner.Id, "Beta"));
var result = await CreateHandler().Handle(new GetAlbumsQuery(Title: null, PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetAlbumsQuery(Title: null, PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(2, result.Value.TotalItemCount);
@@ -26,7 +26,7 @@ public sealed class GetAlbumsQueryHandlerTests : HandlerTestBase
var owner = TestEntities.User();
await SeedAsync(owner, TestEntities.UserAlbum(owner.Id, "Rock Classics"), TestEntities.UserAlbum(owner.Id, "Jazz Favorites"));
var result = await CreateHandler().Handle(new GetAlbumsQuery(Title: "rock", PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetAlbumsQuery(Title: "rock", PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var album = Assert.Single(result.Value.Items);
@@ -39,7 +39,7 @@ public sealed class GetAlbumsQueryHandlerTests : HandlerTestBase
var owner = TestEntities.User();
await SeedAsync(owner, TestEntities.UserAlbum(owner.Id, "One"), TestEntities.UserAlbum(owner.Id, "Two"), TestEntities.UserAlbum(owner.Id, "Three"));
var result = await CreateHandler().Handle(new GetAlbumsQuery(Title: null, PageNumber: 1, PageSize: 2), CancellationToken.None);
var result = await CreateHandler().Handle(new GetAlbumsQuery(Title: null, PageNumber: 1, PageSize: 2), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(2, result.Value.Items.Count);
@@ -24,7 +24,7 @@ public sealed class GetRecentlyListenedAlbumsQueryHandlerTests : HandlerTestBase
TestEntities.ListeningHistory(owner.Id, olderTrack.Id, DateTime.UtcNow.AddDays(-2)),
TestEntities.ListeningHistory(owner.Id, newerTrack.Id, DateTime.UtcNow.AddDays(-1)));
var result = await CreateHandler().Handle(new GetRecentlyListenedAlbumsQuery(owner.Id, Limit: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetRecentlyListenedAlbumsQuery(owner.Id, Limit: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(["Newer", "Older"], result.Value.Select(album => album.Title));
@@ -36,7 +36,7 @@ public sealed class GetRecentlyListenedAlbumsQueryHandlerTests : HandlerTestBase
var owner = TestEntities.User();
await SeedAsync(owner);
var result = await CreateHandler().Handle(new GetRecentlyListenedAlbumsQuery(owner.Id, Limit: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetRecentlyListenedAlbumsQuery(owner.Id, Limit: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Empty(result.Value);
@@ -52,7 +52,7 @@ public sealed class GetRecentlyListenedAlbumsQueryHandlerTests : HandlerTestBase
var histories = tracks.Select((track, i) => TestEntities.ListeningHistory(owner.Id, track.Id, DateTime.UtcNow.AddMinutes(-i))).ToList();
await SeedAsync([owner, .. albums, .. tracks, .. links, .. histories]);
var result = await CreateHandler().Handle(new GetRecentlyListenedAlbumsQuery(owner.Id, Limit: 2), CancellationToken.None);
var result = await CreateHandler().Handle(new GetRecentlyListenedAlbumsQuery(owner.Id, Limit: 2), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(2, result.Value.Count);
@@ -26,13 +26,13 @@ public sealed class RemoveTrackFromAlbumCommandHandlerTests : HandlerTestBase
new AlbumHasTrack { AlbumId = album.Id, TrackId = second.Id, TrackNumber = 2 },
new AlbumHasTrack { AlbumId = album.Id, TrackId = third.Id, TrackNumber = 3 });
var result = await CreateHandler().Handle(new RemoveTrackFromAlbumCommand(owner.Id, album.Id, second.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new RemoveTrackFromAlbumCommand(owner.Id, album.Id, second.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var remaining = await Database.AlbumHasTracks
.Where(link => link.AlbumId == album.Id)
.OrderBy(link => link.TrackNumber)
.ToListAsync();
.ToListAsync(TestContext.Current.CancellationToken);
Assert.Equal([first.Id, third.Id], remaining.Select(link => link.TrackId));
Assert.Equal([1, 2], remaining.Select(link => link.TrackNumber));
}
@@ -40,7 +40,7 @@ public sealed class RemoveTrackFromAlbumCommandHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_AlbumMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new RemoveTrackFromAlbumCommand(1, Guid.NewGuid(), Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new RemoveTrackFromAlbumCommand(1, Guid.NewGuid(), Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -53,7 +53,7 @@ public sealed class RemoveTrackFromAlbumCommandHandlerTests : HandlerTestBase
var album = TestEntities.UserAlbum(owner.Id);
await SeedAsync(owner, stranger, album);
var result = await CreateHandler().Handle(new RemoveTrackFromAlbumCommand(stranger.Id, album.Id, Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new RemoveTrackFromAlbumCommand(stranger.Id, album.Id, Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
}
@@ -65,7 +65,7 @@ public sealed class RemoveTrackFromAlbumCommandHandlerTests : HandlerTestBase
var album = TestEntities.UserAlbum(owner.Id);
await SeedAsync(owner, album);
var result = await CreateHandler().Handle(new RemoveTrackFromAlbumCommand(owner.Id, album.Id, Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new RemoveTrackFromAlbumCommand(owner.Id, album.Id, Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -18,14 +18,14 @@ public sealed class UpdateAlbumCommandHandlerTests : HandlerTestBase
var command = new UpdateAlbumCommand(owner.Id, album.Id, " New Title ", "New description", 2025);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("New Title", result.Value.Title);
Assert.Equal("New description", result.Value.Description);
Assert.Equal(2025, result.Value.ReleaseYear);
var stored = await Database.UserAlbums.FindAsync(album.Id);
var stored = await Database.UserAlbums.FindAsync([album.Id], TestContext.Current.CancellationToken);
Assert.NotNull(stored);
Assert.Equal("NEW TITLE", stored.NormalizedTitle);
}
@@ -35,7 +35,7 @@ public sealed class UpdateAlbumCommandHandlerTests : HandlerTestBase
{
var command = new UpdateAlbumCommand(1, Guid.NewGuid(), "Title", null, null);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -50,7 +50,7 @@ public sealed class UpdateAlbumCommandHandlerTests : HandlerTestBase
var command = new UpdateAlbumCommand(stranger.Id, album.Id, "Hijacked", null, null);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
}
@@ -21,10 +21,10 @@ public sealed class GenerateMixesForUserCommandHandlerTests : HandlerTestBase
var user = TestEntities.User();
await SeedAsync(user);
var result = await CreateHandler().Handle(new GenerateMixesForUserCommand(user.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GenerateMixesForUserCommand(user.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Empty(await Database.Mixes.ToListAsync());
Assert.Empty(await Database.Mixes.ToListAsync(TestContext.Current.CancellationToken));
}
[Fact]
@@ -34,10 +34,10 @@ public sealed class GenerateMixesForUserCommandHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(user);
await SeedAsync(user, track, TestEntities.ListeningHistory(user.Id, track.Id));
var result = await CreateHandler().Handle(new GenerateMixesForUserCommand(user.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GenerateMixesForUserCommand(user.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Empty(await Database.Mixes.ToListAsync());
Assert.Empty(await Database.Mixes.ToListAsync(TestContext.Current.CancellationToken));
}
[Fact]
@@ -64,12 +64,12 @@ public sealed class GenerateMixesForUserCommandHandlerTests : HandlerTestBase
new TrackArtist { TrackId = otherTrackByArtist.Id, ArtistId = artist.Id, Position = 0 },
TestEntities.ListeningHistory(user.Id, listenedTrack.Id));
var result = await CreateHandler().Handle(new GenerateMixesForUserCommand(user.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GenerateMixesForUserCommand(user.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var mixes = await Database.Mixes.ToListAsync();
var mixes = await Database.Mixes.ToListAsync(TestContext.Current.CancellationToken);
Assert.NotEmpty(mixes);
Assert.DoesNotContain(mixes, mix => mix.Title == "Stale Mix");
Assert.Empty(await Database.MixItems.Where(item => item.MixId == staleMix.Id).ToListAsync());
Assert.Empty(await Database.MixItems.Where(item => item.MixId == staleMix.Id).ToListAsync(TestContext.Current.CancellationToken));
}
}
@@ -18,7 +18,7 @@ public sealed class GetMixByIdQueryHandlerTests : HandlerTestBase
var first = TestEntities.MixItem(mix.Id, position: 0, title: "First");
await SeedAsync(owner, mix, second, first);
var result = await CreateHandler().Handle(new GetMixByIdQuery(owner.Id, mix.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GetMixByIdQuery(owner.Id, mix.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("Discovery", result.Value.Title);
@@ -28,7 +28,7 @@ public sealed class GetMixByIdQueryHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_MixMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new GetMixByIdQuery(1, Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new GetMixByIdQuery(1, Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -40,7 +40,7 @@ public sealed class GetMixByIdQueryHandlerTests : HandlerTestBase
var mix = TestEntities.Mix(owner.Id);
await SeedAsync(owner, mix);
var result = await CreateHandler().Handle(new GetMixByIdQuery(2, mix.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GetMixByIdQuery(2, mix.Id), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -18,7 +18,7 @@ public sealed class GetMixesByUserIdQueryHandlerTests : HandlerTestBase
var theirs = TestEntities.Mix(other.Id, "Theirs");
await SeedAsync(owner, other, second, first, theirs);
var result = await CreateHandler().Handle(new GetMixesByUserIdQuery(owner.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GetMixesByUserIdQuery(owner.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(["First", "Second"], result.Value.Select(mix => mix.Title));
@@ -30,7 +30,7 @@ public sealed class GetMixesByUserIdQueryHandlerTests : HandlerTestBase
var owner = TestEntities.User();
await SeedAsync(owner);
var result = await CreateHandler().Handle(new GetMixesByUserIdQuery(owner.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GetMixesByUserIdQuery(owner.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Empty(result.Value);
@@ -3,6 +3,7 @@
<PropertyGroup>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
@@ -10,7 +11,7 @@
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="NSubstitute" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.v3" />
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
@@ -19,10 +19,10 @@ public sealed class AddTrackToPlayListCommandHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, playList, track);
var result = await CreateHandler().Handle(new AddTrackToPlayListCommand(owner.Id, playList.Id, track.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new AddTrackToPlayListCommand(owner.Id, playList.Id, track.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var link = Assert.Single(await Database.PlayListHasTracks.ToListAsync());
var link = Assert.Single(await Database.PlayListHasTracks.ToListAsync(TestContext.Current.CancellationToken));
Assert.Equal(0, link.Position);
}
@@ -37,17 +37,17 @@ public sealed class AddTrackToPlayListCommandHandlerTests : HandlerTestBase
owner, playList, existingTrack, newTrack,
new PlayListHasTrack { PlayListId = playList.Id, TrackId = existingTrack.Id, Position = 0 });
var result = await CreateHandler().Handle(new AddTrackToPlayListCommand(owner.Id, playList.Id, newTrack.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new AddTrackToPlayListCommand(owner.Id, playList.Id, newTrack.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var newLink = await Database.PlayListHasTracks.SingleAsync(link => link.TrackId == newTrack.Id);
var newLink = await Database.PlayListHasTracks.SingleAsync(link => link.TrackId == newTrack.Id, TestContext.Current.CancellationToken);
Assert.Equal(1, newLink.Position);
}
[Fact]
public async Task Handle_PlayListMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new AddTrackToPlayListCommand(1, Guid.NewGuid(), Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new AddTrackToPlayListCommand(1, Guid.NewGuid(), Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -60,7 +60,7 @@ public sealed class AddTrackToPlayListCommandHandlerTests : HandlerTestBase
var playList = TestEntities.PlayList(owner.Id);
await SeedAsync(owner, stranger, playList);
var result = await CreateHandler().Handle(new AddTrackToPlayListCommand(stranger.Id, playList.Id, Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new AddTrackToPlayListCommand(stranger.Id, playList.Id, Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
}
@@ -72,7 +72,7 @@ public sealed class AddTrackToPlayListCommandHandlerTests : HandlerTestBase
var playList = TestEntities.PlayList(owner.Id);
await SeedAsync(owner, playList);
var result = await CreateHandler().Handle(new AddTrackToPlayListCommand(owner.Id, playList.Id, Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new AddTrackToPlayListCommand(owner.Id, playList.Id, Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -85,7 +85,7 @@ public sealed class AddTrackToPlayListCommandHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, playList, track, new PlayListHasTrack { PlayListId = playList.Id, TrackId = track.Id, Position = 0 });
var result = await CreateHandler().Handle(new AddTrackToPlayListCommand(owner.Id, playList.Id, track.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new AddTrackToPlayListCommand(owner.Id, playList.Id, track.Id), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
@@ -42,10 +42,10 @@ public sealed class AddYouTubeTrackToPlayListCommandHandlerTests : HandlerTestBa
var track = TestEntities.ExternalTrack(externalId: "abc123");
await SeedAsync(owner, playList, track);
var result = await CreateHandler().Handle(new AddYouTubeTrackToPlayListCommand(owner.Id, playList.Id, "abc123"), CancellationToken.None);
var result = await CreateHandler().Handle(new AddYouTubeTrackToPlayListCommand(owner.Id, playList.Id, "abc123"), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Single(await Database.PlayListHasTracks.ToListAsync());
Assert.Single(await Database.PlayListHasTracks.ToListAsync(TestContext.Current.CancellationToken));
await eventBus.DidNotReceive().PublishAsync(Arg.Any<Musify.Application.Events.DownloadYouTubeTrackEvent>(), Arg.Any<CancellationToken>());
}
@@ -59,11 +59,11 @@ public sealed class AddYouTubeTrackToPlayListCommandHandlerTests : HandlerTestBa
var playList = TestEntities.PlayList(owner.Id);
await SeedAsync(owner, playList);
var result = await CreateHandler().Handle(new AddYouTubeTrackToPlayListCommand(owner.Id, playList.Id, "new-video"), CancellationToken.None);
var result = await CreateHandler().Handle(new AddYouTubeTrackToPlayListCommand(owner.Id, playList.Id, "new-video"), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("Song Title", result.Value.Title);
var track = await Database.ExternalTracks.SingleAsync(t => t.ExternalId == "new-video");
var track = await Database.ExternalTracks.SingleAsync(t => t.ExternalId == "new-video", TestContext.Current.CancellationToken);
Assert.True(track.Audio.DownloadRequested);
await eventBus.Received(1).PublishAsync(Arg.Any<Musify.Application.Events.DownloadYouTubeTrackEvent>(), Arg.Any<CancellationToken>());
}
@@ -71,7 +71,7 @@ public sealed class AddYouTubeTrackToPlayListCommandHandlerTests : HandlerTestBa
[Fact]
public async Task Handle_PlayListMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new AddYouTubeTrackToPlayListCommand(1, Guid.NewGuid(), "abc123"), CancellationToken.None);
var result = await CreateHandler().Handle(new AddYouTubeTrackToPlayListCommand(1, Guid.NewGuid(), "abc123"), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -84,7 +84,7 @@ public sealed class AddYouTubeTrackToPlayListCommandHandlerTests : HandlerTestBa
var playList = TestEntities.PlayList(owner.Id);
await SeedAsync(owner, stranger, playList);
var result = await CreateHandler().Handle(new AddYouTubeTrackToPlayListCommand(stranger.Id, playList.Id, "abc123"), CancellationToken.None);
var result = await CreateHandler().Handle(new AddYouTubeTrackToPlayListCommand(stranger.Id, playList.Id, "abc123"), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
}
@@ -97,7 +97,7 @@ public sealed class AddYouTubeTrackToPlayListCommandHandlerTests : HandlerTestBa
var track = TestEntities.ExternalTrack(externalId: "abc123");
await SeedAsync(owner, playList, track, new PlayListHasTrack { PlayListId = playList.Id, TrackId = track.Id, Position = 0 });
var result = await CreateHandler().Handle(new AddYouTubeTrackToPlayListCommand(owner.Id, playList.Id, "abc123"), CancellationToken.None);
var result = await CreateHandler().Handle(new AddYouTubeTrackToPlayListCommand(owner.Id, playList.Id, "abc123"), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
@@ -30,7 +30,7 @@ public sealed class CreatePlayListCommandHandlerTests : HandlerTestBase
var command = new CreatePlayListCommand(user.Id, "My Playlist", "A description", PictureIntentId: null);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("My Playlist", result.Value.Name);
@@ -51,10 +51,10 @@ public sealed class CreatePlayListCommandHandlerTests : HandlerTestBase
var command = new CreatePlayListCommand(user.Id, "My Playlist", null, intent.Id);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var stored = await Database.PlayLists.FindAsync(result.Value.Id);
var stored = await Database.PlayLists.FindAsync([result.Value.Id], TestContext.Current.CancellationToken);
Assert.NotNull(stored);
Assert.Equal("cover.webp", stored.Pictures.OriginalName);
await eventBus.Received(1).PublishAsync(Arg.Any<Musify.Application.Events.CreatePlayListResourcesEvent>(), Arg.Any<CancellationToken>());
@@ -65,7 +65,7 @@ public sealed class CreatePlayListCommandHandlerTests : HandlerTestBase
{
var command = new CreatePlayListCommand(404, "Orphan Playlist", null, null);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -78,7 +78,7 @@ public sealed class CreatePlayListCommandHandlerTests : HandlerTestBase
var command = new CreatePlayListCommand(user.Id, "My Playlist", null, Guid.NewGuid());
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.True(result.IsError);
}
@@ -21,10 +21,10 @@ public sealed class DeletePlayListCommandHandlerTests : HandlerTestBase
var playList = TestEntities.PlayList(owner.Id);
await SeedAsync(owner, playList);
var result = await CreateHandler().Handle(new DeletePlayListCommand(owner.Id, playList.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new DeletePlayListCommand(owner.Id, playList.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var stored = await Database.PlayLists.FindAsync(playList.Id);
var stored = await Database.PlayLists.FindAsync([playList.Id], TestContext.Current.CancellationToken);
Assert.NotNull(stored);
Assert.Equal(LifeCycleStatus.Removing, stored.LifeCycleStatus);
await eventBus.Received(1).PublishAsync(Arg.Any<Musify.Application.Events.DeletePlayListEvent>(), Arg.Any<CancellationToken>());
@@ -33,7 +33,7 @@ public sealed class DeletePlayListCommandHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_PlayListMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new DeletePlayListCommand(1, Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new DeletePlayListCommand(1, Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -46,7 +46,7 @@ public sealed class DeletePlayListCommandHandlerTests : HandlerTestBase
var playList = TestEntities.PlayList(owner.Id);
await SeedAsync(owner, stranger, playList);
var result = await CreateHandler().Handle(new DeletePlayListCommand(stranger.Id, playList.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new DeletePlayListCommand(stranger.Id, playList.Id), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
}
@@ -18,7 +18,7 @@ public sealed class GetPlayListByIdQueryHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, playList, track, new PlayListHasTrack { PlayListId = playList.Id, TrackId = track.Id, Position = 0 });
var result = await CreateHandler().Handle(new GetPlayListByIdQuery(playList.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GetPlayListByIdQuery(playList.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(playList.Name, result.Value.Name);
@@ -28,7 +28,7 @@ public sealed class GetPlayListByIdQueryHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_PlayListMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new GetPlayListByIdQuery(Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new GetPlayListByIdQuery(Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -20,7 +20,7 @@ public sealed class GetPlayListCoverQueryHandlerTests : HandlerTestBase
var playList = TestEntities.PlayList(owner.Id);
await SeedAsync(owner, playList);
var result = await CreateHandler().Handle(new GetPlayListCoverQuery(playList.Id, size), CancellationToken.None);
var result = await CreateHandler().Handle(new GetPlayListCoverQuery(playList.Id, size), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("covers-bucket", result.Value.Bucket);
@@ -30,7 +30,7 @@ public sealed class GetPlayListCoverQueryHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_PlayListMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new GetPlayListCoverQuery(Guid.NewGuid(), "small"), CancellationToken.None);
var result = await CreateHandler().Handle(new GetPlayListCoverQuery(Guid.NewGuid(), "small"), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -22,7 +22,7 @@ public sealed class GetPlayListTracksQueryHandlerTests : HandlerTestBase
new PlayListHasTrack { PlayListId = playList.Id, TrackId = second.Id, Position = 1 },
new PlayListHasTrack { PlayListId = playList.Id, TrackId = first.Id, Position = 0 });
var result = await CreateHandler().Handle(new GetPlayListTracksQuery(playList.Id, PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetPlayListTracksQuery(playList.Id, PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(["First", "Second"], result.Value.Items.Select(track => track.Title));
@@ -31,7 +31,7 @@ public sealed class GetPlayListTracksQueryHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_PlayListMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new GetPlayListTracksQuery(Guid.NewGuid(), PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetPlayListTracksQuery(Guid.NewGuid(), PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -20,7 +20,7 @@ public sealed class GetPlayListsByUserIdQueryHandlerTests : HandlerTestBase
TestEntities.PlayList(owner.Id, "Being removed", lifeCycleStatus: LifeCycleStatus.Removing),
TestEntities.PlayList(other.Id, "Theirs"));
var result = await CreateHandler().Handle(new GetPlayListsByUserIdQuery(owner.Id, Name: null, PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetPlayListsByUserIdQuery(owner.Id, Name: null, PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var playList = Assert.Single(result.Value.Items);
@@ -33,7 +33,7 @@ public sealed class GetPlayListsByUserIdQueryHandlerTests : HandlerTestBase
var owner = TestEntities.User();
await SeedAsync(owner, TestEntities.PlayList(owner.Id, "Road Trip"), TestEntities.PlayList(owner.Id, "Study Focus"));
var result = await CreateHandler().Handle(new GetPlayListsByUserIdQuery(owner.Id, Name: "road", PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetPlayListsByUserIdQuery(owner.Id, Name: "road", PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var playList = Assert.Single(result.Value.Items);
@@ -14,7 +14,7 @@ public sealed class GetPlayListsQueryHandlerTests : HandlerTestBase
var owner = TestEntities.User();
await SeedAsync(owner, TestEntities.PlayList(owner.Id, "One"), TestEntities.PlayList(owner.Id, "Two"));
var result = await CreateHandler().Handle(new GetPlayListsQuery(PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetPlayListsQuery(PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(2, result.Value.TotalItemCount);
@@ -23,7 +23,7 @@ public sealed class GetPlayListsQueryHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_NoPlayLists_ReturnsEmptyPage()
{
var result = await CreateHandler().Handle(new GetPlayListsQuery(PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetPlayListsQuery(PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Empty(result.Value.Items);
@@ -18,7 +18,7 @@ public sealed class RemoveTrackFromPlayListCommandHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, playList, track, new PlayListHasTrack { PlayListId = playList.Id, TrackId = track.Id, Position = 0 });
var result = await CreateHandler().Handle(new RemoveTrackFromPlayListCommand(owner.Id, playList.Id, track.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new RemoveTrackFromPlayListCommand(owner.Id, playList.Id, track.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Empty(Database.PlayListHasTracks);
@@ -27,7 +27,7 @@ public sealed class RemoveTrackFromPlayListCommandHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_PlayListMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new RemoveTrackFromPlayListCommand(1, Guid.NewGuid(), Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new RemoveTrackFromPlayListCommand(1, Guid.NewGuid(), Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -40,7 +40,7 @@ public sealed class RemoveTrackFromPlayListCommandHandlerTests : HandlerTestBase
var playList = TestEntities.PlayList(owner.Id);
await SeedAsync(owner, stranger, playList);
var result = await CreateHandler().Handle(new RemoveTrackFromPlayListCommand(stranger.Id, playList.Id, Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new RemoveTrackFromPlayListCommand(stranger.Id, playList.Id, Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
}
@@ -52,7 +52,7 @@ public sealed class RemoveTrackFromPlayListCommandHandlerTests : HandlerTestBase
var playList = TestEntities.PlayList(owner.Id);
await SeedAsync(owner, playList);
var result = await CreateHandler().Handle(new RemoveTrackFromPlayListCommand(owner.Id, playList.Id, Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new RemoveTrackFromPlayListCommand(owner.Id, playList.Id, Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -38,11 +38,11 @@ public sealed class RequestPlayListPictureUploadCommandHandlerTests : HandlerTes
var command = new RequestPlayListPictureUploadCommand(user.Id, "webp", "image/webp");
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("https://storage.musify.test/presigned-upload", result.Value.UploadUrl);
Assert.Single(await Database.UploadIntents.ToListAsync());
Assert.Single(await Database.UploadIntents.ToListAsync(TestContext.Current.CancellationToken));
}
[Fact]
@@ -50,7 +50,7 @@ public sealed class RequestPlayListPictureUploadCommandHandlerTests : HandlerTes
{
var command = new RequestPlayListPictureUploadCommand(404, "webp", "image/webp");
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -66,9 +66,9 @@ public sealed class RequestPlayListPictureUploadCommandHandlerTests : HandlerTes
var command = new RequestPlayListPictureUploadCommand(user.Id, "webp", "image/webp", ExpectedSizeBytes: 1_000_000);
var result = await CreateHandler(config).Handle(command, CancellationToken.None);
var result = await CreateHandler(config).Handle(command, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Validation, result.FirstError.Type);
Assert.Empty(await Database.UploadIntents.ToListAsync());
Assert.Empty(await Database.UploadIntents.ToListAsync(TestContext.Current.CancellationToken));
}
}
@@ -31,7 +31,7 @@ public sealed class UpdatePlayListCommandHandlerTests : HandlerTestBase
var command = new UpdatePlayListCommand(owner.Id, playList.Id, "New Name", null, null);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("New Name", result.Value.Name);
@@ -42,7 +42,7 @@ public sealed class UpdatePlayListCommandHandlerTests : HandlerTestBase
{
var command = new UpdatePlayListCommand(1, Guid.NewGuid(), "New Name", null, null);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -57,7 +57,7 @@ public sealed class UpdatePlayListCommandHandlerTests : HandlerTestBase
var command = new UpdatePlayListCommand(stranger.Id, playList.Id, "Hijacked", null, null);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
}
@@ -71,7 +71,7 @@ public sealed class UpdatePlayListCommandHandlerTests : HandlerTestBase
var command = new UpdatePlayListCommand(owner.Id, playList.Id, " ", " ", null);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("Original Name", result.Value.Name);
@@ -22,7 +22,7 @@ public sealed class TrackStreamIssuerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, track);
var response = await CreateIssuer().IssueAsync(track.Id, "folder-42", userId: 7, CancellationToken.None);
var response = await CreateIssuer().IssueAsync(track.Id, "folder-42", userId: 7, TestContext.Current.CancellationToken);
Assert.Equal("signed-token", response.Ticket);
Assert.Equal(120, response.ExpiresInSeconds);
@@ -30,7 +30,7 @@ public sealed class TrackStreamIssuerTests : HandlerTestBase
"https://stream.musify.test/media/Tracks/ProcessedAudios/folder-42/audio.m4a",
response.ManifestUrl);
var history = Assert.Single(await Database.ListeningHistories.ToListAsync());
var history = Assert.Single(await Database.ListeningHistories.ToListAsync(TestContext.Current.CancellationToken));
Assert.Equal(7, history.UserId);
Assert.Equal(track.Id, history.TrackId);
}
@@ -43,7 +43,7 @@ public sealed class TrackStreamIssuerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, track);
await CreateIssuer().IssueAsync(track.Id, "folder-42", userId: 1, CancellationToken.None);
await CreateIssuer().IssueAsync(track.Id, "folder-42", userId: 1, TestContext.Current.CancellationToken);
ticketService.Received(1).IssueTicket(1, "Tracks/ProcessedAudios/folder-42/");
}
@@ -25,7 +25,7 @@ public sealed class UploadIntentValidatorTests : HandlerTestBase
var intent = TestEntities.UploadIntent(owner.Id, bucket: "bucket", key: "temp/object.webp");
await SeedAsync(owner, intent);
var result = await CreateValidator().ValidateAndLoadAsync(TestConfigurations.UploadIntent(), intent.Id, owner.Id, CancellationToken.None);
var result = await CreateValidator().ValidateAndLoadAsync(TestConfigurations.UploadIntent(), intent.Id, owner.Id, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(intent.Id, result.Value.Id);
@@ -34,7 +34,7 @@ public sealed class UploadIntentValidatorTests : HandlerTestBase
[Fact]
public async Task ValidateAndLoadAsync_IntentMissing_ReturnsNotFound()
{
var result = await CreateValidator().ValidateAndLoadAsync(TestConfigurations.UploadIntent(), Guid.NewGuid(), owner.Id, CancellationToken.None);
var result = await CreateValidator().ValidateAndLoadAsync(TestConfigurations.UploadIntent(), Guid.NewGuid(), owner.Id, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -46,7 +46,7 @@ public sealed class UploadIntentValidatorTests : HandlerTestBase
var intent = TestEntities.UploadIntent(owner.Id);
await SeedAsync(owner, stranger, intent);
var result = await CreateValidator().ValidateAndLoadAsync(TestConfigurations.UploadIntent(), intent.Id, stranger.Id, CancellationToken.None);
var result = await CreateValidator().ValidateAndLoadAsync(TestConfigurations.UploadIntent(), intent.Id, stranger.Id, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -57,7 +57,7 @@ public sealed class UploadIntentValidatorTests : HandlerTestBase
var intent = TestEntities.UploadIntent(owner.Id, status: UploadIntentStatus.Consumed);
await SeedAsync(owner, intent);
var result = await CreateValidator().ValidateAndLoadAsync(TestConfigurations.UploadIntent(), intent.Id, owner.Id, CancellationToken.None);
var result = await CreateValidator().ValidateAndLoadAsync(TestConfigurations.UploadIntent(), intent.Id, owner.Id, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
@@ -68,7 +68,7 @@ public sealed class UploadIntentValidatorTests : HandlerTestBase
var intent = TestEntities.UploadIntent(owner.Id, expiresAt: DateTime.UtcNow.AddMinutes(-1));
await SeedAsync(owner, intent);
var result = await CreateValidator().ValidateAndLoadAsync(TestConfigurations.UploadIntent(), intent.Id, owner.Id, CancellationToken.None);
var result = await CreateValidator().ValidateAndLoadAsync(TestConfigurations.UploadIntent(), intent.Id, owner.Id, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Validation, result.FirstError.Type);
}
@@ -83,7 +83,7 @@ public sealed class UploadIntentValidatorTests : HandlerTestBase
var intent = TestEntities.UploadIntent(owner.Id);
await SeedAsync(owner, intent);
var result = await CreateValidator().ValidateAndLoadAsync(TestConfigurations.UploadIntent(), intent.Id, owner.Id, CancellationToken.None);
var result = await CreateValidator().ValidateAndLoadAsync(TestConfigurations.UploadIntent(), intent.Id, owner.Id, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -101,7 +101,7 @@ public sealed class UploadIntentValidatorTests : HandlerTestBase
var intent = TestEntities.UploadIntent(owner.Id);
await SeedAsync(owner, intent);
var result = await CreateValidator().ValidateAndLoadAsync(config, intent.Id, owner.Id, CancellationToken.None);
var result = await CreateValidator().ValidateAndLoadAsync(config, intent.Id, owner.Id, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Validation, result.FirstError.Type);
}
@@ -111,7 +111,7 @@ public sealed class UploadIntentValidatorTests : HandlerTestBase
{
await SeedAsync(owner);
var result = await CreateValidator().CheckQuotaAsync(TestConfigurations.UploadIntent(), owner.Id, requiredBytes: 1024, requiredIntentCount: 1, CancellationToken.None);
var result = await CreateValidator().CheckQuotaAsync(TestConfigurations.UploadIntent(), owner.Id, requiredBytes: 1024, requiredIntentCount: 1, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
}
@@ -123,7 +123,7 @@ public sealed class UploadIntentValidatorTests : HandlerTestBase
config.MaxActiveUploadIntentsPerUser = 1;
await SeedAsync(owner, TestEntities.UploadIntent(owner.Id));
var result = await CreateValidator().CheckQuotaAsync(config, owner.Id, requiredBytes: 1, requiredIntentCount: 1, CancellationToken.None);
var result = await CreateValidator().CheckQuotaAsync(config, owner.Id, requiredBytes: 1, requiredIntentCount: 1, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Validation, result.FirstError.Type);
}
@@ -138,7 +138,7 @@ public sealed class UploadIntentValidatorTests : HandlerTestBase
TestEntities.UploadIntent(owner.Id, status: UploadIntentStatus.Expired),
TestEntities.UploadIntent(owner.Id, status: UploadIntentStatus.Consumed));
var result = await CreateValidator().CheckQuotaAsync(config, owner.Id, requiredBytes: 1, requiredIntentCount: 1, CancellationToken.None);
var result = await CreateValidator().CheckQuotaAsync(config, owner.Id, requiredBytes: 1, requiredIntentCount: 1, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
}
@@ -17,7 +17,7 @@ public sealed class YouTubeTrackProvisionerTests : HandlerTestBase
[Fact]
public async Task FindAsync_UnknownVideo_ReturnsNull()
{
var track = await CreateProvisioner().FindAsync("missing-video", CancellationToken.None);
var track = await CreateProvisioner().FindAsync("missing-video", TestContext.Current.CancellationToken);
Assert.Null(track);
}
@@ -28,11 +28,11 @@ public sealed class YouTubeTrackProvisionerTests : HandlerTestBase
var existing = TestEntities.ExternalTrack(externalId: "known-video");
await SeedAsync(existing);
var result = await CreateProvisioner().GetOrCreateAsync("known-video", CancellationToken.None);
var result = await CreateProvisioner().GetOrCreateAsync("known-video", TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(existing.Id, result.Value.Track.Id);
await youTubeMusicService.DidNotReceiveWithAnyArgs().GetSongAsync(default!, default);
await youTubeMusicService.DidNotReceiveWithAnyArgs().GetSongAsync(default!, TestContext.Current.CancellationToken);
}
[Fact]
@@ -43,12 +43,12 @@ public sealed class YouTubeTrackProvisionerTests : HandlerTestBase
"new-video", "New Song", "New Artist", "Album", 210, "https://img/thumb.jpg", false,
[new YouTubeArtistRef(null, "New Artist"), new YouTubeArtistRef(null, "new artist")]));
var result = await CreateProvisioner().GetOrCreateAsync("new-video", CancellationToken.None);
var result = await CreateProvisioner().GetOrCreateAsync("new-video", TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("New Song", result.Value.Track.Title);
Assert.Single(await Database.Artists.ToListAsync());
Assert.Single(await Database.TrackArtists.ToListAsync());
Assert.Single(await Database.Artists.ToListAsync(TestContext.Current.CancellationToken));
Assert.Single(await Database.TrackArtists.ToListAsync(TestContext.Current.CancellationToken));
}
[Fact]
@@ -57,7 +57,7 @@ public sealed class YouTubeTrackProvisionerTests : HandlerTestBase
youTubeMusicService.GetSongAsync("bad-video", Arg.Any<CancellationToken>())
.Returns(ErrorOr.Error.NotFound(description: "Video not found"));
var result = await CreateProvisioner().GetOrCreateAsync("bad-video", CancellationToken.None);
var result = await CreateProvisioner().GetOrCreateAsync("bad-video", TestContext.Current.CancellationToken);
Assert.True(result.IsError);
}
@@ -76,11 +76,11 @@ public sealed class YouTubeTrackProvisionerTests : HandlerTestBase
new YouTubeAlbumTrack("track-2", "Track Two", 200, 2, false)
]);
await CreateProvisioner().MaterializeAlbumAsync("album-1", detail, CancellationToken.None);
await CreateProvisioner().MaterializeAlbumAsync("album-1", detail, TestContext.Current.CancellationToken);
Assert.Equal(2, await Database.ExternalTracks.CountAsync());
Assert.Equal(2, await Database.AlbumHasTracks.CountAsync());
Assert.Single(await Database.ExternalAlbums.ToListAsync());
Assert.Equal(2, await Database.ExternalTracks.CountAsync(TestContext.Current.CancellationToken));
Assert.Equal(2, await Database.AlbumHasTracks.CountAsync(TestContext.Current.CancellationToken));
Assert.Single(await Database.ExternalAlbums.ToListAsync(TestContext.Current.CancellationToken));
}
[Fact]
@@ -93,11 +93,11 @@ public sealed class YouTubeTrackProvisionerTests : HandlerTestBase
Tracks: [new YouTubeAlbumTrack("track-1", "Track One", 200, 1, false)]);
var provisioner = CreateProvisioner();
await provisioner.MaterializeAlbumAsync("album-1", detail, CancellationToken.None);
await provisioner.MaterializeAlbumAsync("album-1", detail, CancellationToken.None);
await provisioner.MaterializeAlbumAsync("album-1", detail, TestContext.Current.CancellationToken);
await provisioner.MaterializeAlbumAsync("album-1", detail, TestContext.Current.CancellationToken);
Assert.Single(await Database.ExternalTracks.ToListAsync());
Assert.Single(await Database.AlbumHasTracks.ToListAsync());
Assert.Single(await Database.ExternalAlbums.ToListAsync());
Assert.Single(await Database.ExternalTracks.ToListAsync(TestContext.Current.CancellationToken));
Assert.Single(await Database.AlbumHasTracks.ToListAsync(TestContext.Current.CancellationToken));
Assert.Single(await Database.ExternalAlbums.ToListAsync(TestContext.Current.CancellationToken));
}
}
@@ -16,9 +16,9 @@ public abstract class HandlerTestBase : IAsyncLifetime
protected TestDatabase Database => database;
public async Task InitializeAsync() => database = await TestDatabase.CreateAsync();
public async ValueTask InitializeAsync() => database = await TestDatabase.CreateAsync();
public Task DisposeAsync() => database.DisposeAsync().AsTask();
public ValueTask DisposeAsync() => database.DisposeAsync();
protected static ILogger<T> NoOpLogger<T>() => NullLogger<T>.Instance;
@@ -43,14 +43,14 @@ public sealed class CreateTrackCommandHandlerTests : HandlerTestBase
var command = new CreateTrackCommand(user.Id, "My Song", picture.Id, audio.Id);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("My Song", result.Value.Title);
Assert.Equal(user.Id, result.Value.OwnerUserId);
await eventBus.Received(1).PublishAsync(Arg.Any<Musify.Application.Events.CreateTrackResourcesEvent>(), Arg.Any<CancellationToken>());
var stored = await Database.LocalTracks.FindAsync(result.Value.Id);
var stored = await Database.LocalTracks.FindAsync([result.Value.Id], TestContext.Current.CancellationToken);
Assert.NotNull(stored);
Assert.Equal(ProcessingStatus.Pending, stored.Audio.TranscodeStatus);
}
@@ -60,7 +60,7 @@ public sealed class CreateTrackCommandHandlerTests : HandlerTestBase
{
var command = new CreateTrackCommand(404, "Orphan Song", Guid.NewGuid(), Guid.NewGuid());
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -75,7 +75,7 @@ public sealed class CreateTrackCommandHandlerTests : HandlerTestBase
var command = new CreateTrackCommand(user.Id, "My Song", picture.Id, audio.Id);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.True(result.IsError);
await eventBus.DidNotReceive().PublishAsync(Arg.Any<Musify.Application.Events.CreateTrackResourcesEvent>(), Arg.Any<CancellationToken>());
@@ -91,7 +91,7 @@ public sealed class CreateTrackCommandHandlerTests : HandlerTestBase
var command = new CreateTrackCommand(user.Id, "My Song", picture.Id, audio.Id);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
@@ -21,10 +21,10 @@ public sealed class DeleteTrackCommandHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, track);
var result = await CreateHandler().Handle(new DeleteTrackCommand(owner.Id, track.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new DeleteTrackCommand(owner.Id, track.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var stored = await Database.Tracks.FindAsync(track.Id);
var stored = await Database.Tracks.FindAsync([track.Id], TestContext.Current.CancellationToken);
Assert.NotNull(stored);
Assert.Equal(LifeCycleStatus.Removing, stored.LifeCycleStatus);
await eventBus.Received(1).PublishAsync(Arg.Any<Musify.Application.Events.DeleteTrackEvent>(), Arg.Any<CancellationToken>());
@@ -33,7 +33,7 @@ public sealed class DeleteTrackCommandHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_TrackMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new DeleteTrackCommand(1, Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new DeleteTrackCommand(1, Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -46,7 +46,7 @@ public sealed class DeleteTrackCommandHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, stranger, track);
var result = await CreateHandler().Handle(new DeleteTrackCommand(stranger.Id, track.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new DeleteTrackCommand(stranger.Id, track.Id), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
}
@@ -57,7 +57,7 @@ public sealed class DeleteTrackCommandHandlerTests : HandlerTestBase
var externalTrack = TestEntities.ExternalTrack();
await SeedAsync(externalTrack);
var result = await CreateHandler().Handle(new DeleteTrackCommand(1, externalTrack.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new DeleteTrackCommand(1, externalTrack.Id), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Unauthorized, result.FirstError.Type);
}
@@ -69,7 +69,7 @@ public sealed class DeleteTrackCommandHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner, audio: TestEntities.PendingAudio());
await SeedAsync(owner, track);
var result = await CreateHandler().Handle(new DeleteTrackCommand(owner.Id, track.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new DeleteTrackCommand(owner.Id, track.Id), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
@@ -20,7 +20,7 @@ public sealed class GetListeningHistoryQueryHandlerTests : HandlerTestBase
TestEntities.ListeningHistory(owner.Id, older.Id, DateTime.UtcNow.AddMinutes(-5)),
TestEntities.ListeningHistory(owner.Id, newer.Id, DateTime.UtcNow));
var result = await CreateHandler().Handle(new GetListeningHistoryQuery(owner.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GetListeningHistoryQuery(owner.Id), TestContext.Current.CancellationToken);
Assert.Equal(["Newer listen", "Older listen"], result.Select(track => track.Title));
}
@@ -31,7 +31,7 @@ public sealed class GetListeningHistoryQueryHandlerTests : HandlerTestBase
var owner = TestEntities.User();
await SeedAsync(owner);
var result = await CreateHandler().Handle(new GetListeningHistoryQuery(owner.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GetListeningHistoryQuery(owner.Id), TestContext.Current.CancellationToken);
Assert.Empty(result);
}
@@ -16,7 +16,7 @@ public sealed class GetTrackByIdQueryHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner, "My Song");
await SeedAsync(owner, track);
var result = await CreateHandler().Handle(new GetTrackByIdQuery(track.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GetTrackByIdQuery(track.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("My Song", result.Value.Title);
@@ -27,7 +27,7 @@ public sealed class GetTrackByIdQueryHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_TrackMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new GetTrackByIdQuery(Guid.NewGuid()), CancellationToken.None);
var result = await CreateHandler().Handle(new GetTrackByIdQuery(Guid.NewGuid()), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -21,7 +21,7 @@ public sealed class GetTrackCoverQueryHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, track);
var result = await CreateHandler().Handle(new GetTrackCoverQuery(track.Id, size), CancellationToken.None);
var result = await CreateHandler().Handle(new GetTrackCoverQuery(track.Id, size), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("covers-bucket", result.Value.Bucket);
@@ -32,7 +32,7 @@ public sealed class GetTrackCoverQueryHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_TrackMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new GetTrackCoverQuery(Guid.NewGuid(), "small"), CancellationToken.None);
var result = await CreateHandler().Handle(new GetTrackCoverQuery(Guid.NewGuid(), "small"), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -44,7 +44,7 @@ public sealed class GetTrackCoverQueryHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner, pictures: TestEntities.PendingPictures());
await SeedAsync(owner, track);
var result = await CreateHandler().Handle(new GetTrackCoverQuery(track.Id, "small"), CancellationToken.None);
var result = await CreateHandler().Handle(new GetTrackCoverQuery(track.Id, "small"), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -33,14 +33,14 @@ public sealed class GetTrackStreamQueryHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, track);
var result = await CreateHandler().Handle(new GetTrackStreamQuery(track.Id, owner.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GetTrackStreamQuery(track.Id, owner.Id), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("ticket-token", result.Value.Ticket);
Assert.Equal(60, result.Value.ExpiresInSeconds);
Assert.Contains("audio-folder", result.Value.ManifestUrl);
var history = Assert.Single(await Database.ListeningHistories.ToListAsync());
var history = Assert.Single(await Database.ListeningHistories.ToListAsync(TestContext.Current.CancellationToken));
Assert.Equal(owner.Id, history.UserId);
Assert.Equal(track.Id, history.TrackId);
}
@@ -48,7 +48,7 @@ public sealed class GetTrackStreamQueryHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_TrackMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new GetTrackStreamQuery(Guid.NewGuid(), 1), CancellationToken.None);
var result = await CreateHandler().Handle(new GetTrackStreamQuery(Guid.NewGuid(), 1), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -60,7 +60,7 @@ public sealed class GetTrackStreamQueryHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner, audio: TestEntities.PendingAudio());
await SeedAsync(owner, track);
var result = await CreateHandler().Handle(new GetTrackStreamQuery(track.Id, owner.Id), CancellationToken.None);
var result = await CreateHandler().Handle(new GetTrackStreamQuery(track.Id, owner.Id), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
@@ -21,7 +21,7 @@ public sealed class GetTracksByUserIdQueryHandlerTests : HandlerTestBase
new UserHasTrack { UserId = owner.Id, TrackId = mine.Id },
new UserHasTrack { UserId = other.Id, TrackId = theirs.Id });
var result = await CreateHandler().Handle(new GetTracksByUserIdQuery(owner.Id, Name: null, PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetTracksByUserIdQuery(owner.Id, Name: null, PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var track = Assert.Single(result.Value.Items);
@@ -37,7 +37,7 @@ public sealed class GetTracksByUserIdQueryHandlerTests : HandlerTestBase
var track = TestEntities.LocalTrack(owner);
await SeedAsync(owner, track, new UserHasTrack { UserId = owner.Id, TrackId = track.Id });
var result = await CreateHandler().Handle(new GetTracksByUserIdQuery(owner.Id, Name: null, PageNumber: requestedPageNumber, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetTracksByUserIdQuery(owner.Id, Name: null, PageNumber: requestedPageNumber, PageSize: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(expectedPageNumber, result.Value.PageNumber);
@@ -19,7 +19,7 @@ public sealed class GetTracksQueryHandlerTests : HandlerTestBase
new Musify.Domain.Entities.UserHasTrack { UserId = owner.Id, TrackId = trackA.Id },
new Musify.Domain.Entities.UserHasTrack { UserId = owner.Id, TrackId = trackB.Id });
var result = await CreateHandler().Handle(new GetTracksQuery(Name: null, PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetTracksQuery(Name: null, PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(2, result.Value.TotalItemCount);
@@ -36,7 +36,7 @@ public sealed class GetTracksQueryHandlerTests : HandlerTestBase
new Musify.Domain.Entities.UserHasTrack { UserId = owner.Id, TrackId = match.Id },
new Musify.Domain.Entities.UserHasTrack { UserId = owner.Id, TrackId = other.Id });
var result = await CreateHandler().Handle(new GetTracksQuery(Name: "rhapsody", PageNumber: 1, PageSize: 10), CancellationToken.None);
var result = await CreateHandler().Handle(new GetTracksQuery(Name: "rhapsody", PageNumber: 1, PageSize: 10), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var track = Assert.Single(result.Value.Items);
@@ -39,13 +39,13 @@ public sealed class RequestTrackUploadUrlsCommandHandlerTests : HandlerTestBase
var command = new RequestTrackUploadUrlsCommand(user.Id, "webp", "image/webp", "mp3", "audio/mpeg");
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("https://storage.musify.test/presigned-upload", result.Value.PictureUploadUrl);
Assert.Equal("https://storage.musify.test/presigned-upload", result.Value.AudioUploadUrl);
var intents = await Database.UploadIntents.Where(intent => intent.UserId == user.Id).ToListAsync();
var intents = await Database.UploadIntents.Where(intent => intent.UserId == user.Id).ToListAsync(TestContext.Current.CancellationToken);
Assert.Equal(2, intents.Count);
Assert.Contains(intents, intent => intent.Purpose == UploadIntentPurpose.TrackPicture);
Assert.Contains(intents, intent => intent.Purpose == UploadIntentPurpose.TrackAudio);
@@ -56,7 +56,7 @@ public sealed class RequestTrackUploadUrlsCommandHandlerTests : HandlerTestBase
{
var command = new RequestTrackUploadUrlsCommand(404, "webp", "image/webp", "mp3", "audio/mpeg");
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -72,9 +72,9 @@ public sealed class RequestTrackUploadUrlsCommandHandlerTests : HandlerTestBase
var command = new RequestTrackUploadUrlsCommand(user.Id, "webp", "image/webp", "mp3", "audio/mpeg");
var result = await CreateHandler(config).Handle(command, CancellationToken.None);
var result = await CreateHandler(config).Handle(command, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Validation, result.FirstError.Type);
Assert.Equal(1, await Database.UploadIntents.CountAsync());
Assert.Equal(1, await Database.UploadIntents.CountAsync(TestContext.Current.CancellationToken));
}
}
@@ -14,13 +14,13 @@ public sealed class CreateUserCommandHandlerTests : HandlerTestBase
{
var command = new CreateUserCommand(1, "Jane Doe", "Jane", "Doe");
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("Jane Doe", result.Value.Name);
Assert.Equal(1, result.Value.Id);
var stored = await Database.Users.FindAsync(1L);
var stored = await Database.Users.FindAsync([1L], TestContext.Current.CancellationToken);
Assert.NotNull(stored);
Assert.Equal("JANE DOE", stored.NormalizedName);
}
@@ -33,7 +33,7 @@ public sealed class CreateUserCommandHandlerTests : HandlerTestBase
var command = new CreateUserCommand(1, "Someone Else", null, null);
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Conflict, result.FirstError.Type);
}
@@ -15,7 +15,7 @@ public sealed class GetUserByIdQueryHandlerTests : HandlerTestBase
var user = TestEntities.User(1, "Jane Doe");
await SeedAsync(user);
var result = await CreateHandler().Handle(new GetUserByIdQuery(1), CancellationToken.None);
var result = await CreateHandler().Handle(new GetUserByIdQuery(1), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal("Jane Doe", result.Value.Name);
@@ -24,7 +24,7 @@ public sealed class GetUserByIdQueryHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_UserMissing_ReturnsNotFound()
{
var result = await CreateHandler().Handle(new GetUserByIdQuery(404), CancellationToken.None);
var result = await CreateHandler().Handle(new GetUserByIdQuery(404), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.NotFound, result.FirstError.Type);
}
@@ -13,7 +13,7 @@ public sealed class GetUsersQueryHandlerTests : HandlerTestBase
{
await SeedAsync(TestEntities.User(1, "alice"), TestEntities.User(2, "bob"));
var result = await CreateHandler().Handle(new GetUsersQuery(PageNumber: 1, PageSize: 10, UsernameSearch: null), CancellationToken.None);
var result = await CreateHandler().Handle(new GetUsersQuery(PageNumber: 1, PageSize: 10, UsernameSearch: null), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(2, result.Value.TotalItemCount);
@@ -24,7 +24,7 @@ public sealed class GetUsersQueryHandlerTests : HandlerTestBase
{
await SeedAsync(TestEntities.User(1, "alice-wonderland"), TestEntities.User(2, "bob-builder"));
var result = await CreateHandler().Handle(new GetUsersQuery(PageNumber: 1, PageSize: 10, UsernameSearch: "alice"), CancellationToken.None);
var result = await CreateHandler().Handle(new GetUsersQuery(PageNumber: 1, PageSize: 10, UsernameSearch: "alice"), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var user = Assert.Single(result.Value.Items);
@@ -13,10 +13,10 @@ public sealed class SyncUserCommandHandlerTests : HandlerTestBase
{
var command = new SyncUserCommand(1, "Jane Doe", "Jane", "Doe", "https://avatar.example/jane.png");
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var stored = await Database.Users.FindAsync(1L);
var stored = await Database.Users.FindAsync([1L], TestContext.Current.CancellationToken);
Assert.NotNull(stored);
Assert.Equal("Jane Doe", stored.Name);
Assert.Equal("https://avatar.example/jane.png", stored.ProfilePictureUrl);
@@ -30,10 +30,10 @@ public sealed class SyncUserCommandHandlerTests : HandlerTestBase
var command = new SyncUserCommand(1, "New Name", "New", "Name", "https://avatar.example/new.png");
var result = await CreateHandler().Handle(command, CancellationToken.None);
var result = await CreateHandler().Handle(command, TestContext.Current.CancellationToken);
Assert.False(result.IsError);
var stored = await Database.Users.FindAsync(1L);
var stored = await Database.Users.FindAsync([1L], TestContext.Current.CancellationToken);
Assert.NotNull(stored);
Assert.Equal("New Name", stored.Name);
Assert.Equal("NEW NAME", stored.NormalizedName);
@@ -30,7 +30,7 @@ public sealed class GetYouTubeAlbumQueryHandlerTests : HandlerTestBase
[Fact]
public async Task Handle_EmptyAlbumId_ReturnsValidationError()
{
var result = await CreateHandler().Handle(new GetYouTubeAlbumQuery(string.Empty), CancellationToken.None);
var result = await CreateHandler().Handle(new GetYouTubeAlbumQuery(string.Empty), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Validation, result.FirstError.Type);
}
@@ -41,11 +41,11 @@ public sealed class GetYouTubeAlbumQueryHandlerTests : HandlerTestBase
var detail = BuildDetail();
youTubeMusicService.GetAlbumAsync("album-1", Arg.Any<CancellationToken>()).Returns(detail);
var result = await CreateHandler().Handle(new GetYouTubeAlbumQuery("album-1"), CancellationToken.None);
var result = await CreateHandler().Handle(new GetYouTubeAlbumQuery("album-1"), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Same(detail, result.Value);
Assert.NotEmpty(await Database.ExternalAlbums.ToListAsync());
Assert.NotEmpty(await Database.ExternalAlbums.ToListAsync(TestContext.Current.CancellationToken));
}
[Fact]
@@ -54,7 +54,7 @@ public sealed class GetYouTubeAlbumQueryHandlerTests : HandlerTestBase
youTubeMusicService.GetAlbumAsync("missing", Arg.Any<CancellationToken>())
.Returns(Error.NotFound(description: "Album not found"));
var result = await CreateHandler().Handle(new GetYouTubeAlbumQuery("missing"), CancellationToken.None);
var result = await CreateHandler().Handle(new GetYouTubeAlbumQuery("missing"), TestContext.Current.CancellationToken);
Assert.True(result.IsError);
}
@@ -34,12 +34,12 @@ public sealed class ResolveYouTubeTrackStreamCommandHandlerTests : HandlerTestBa
var track = TestEntities.ExternalTrack(externalId: "abc123");
await SeedAsync(user, track);
var result = await CreateHandler().Handle(new ResolveYouTubeTrackStreamCommand("abc123", 1), CancellationToken.None);
var result = await CreateHandler().Handle(new ResolveYouTubeTrackStreamCommand("abc123", 1), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(YouTubeStreamMode.Server, result.Value.Mode);
Assert.Equal("token", result.Value.Ticket);
await youTubeMusicService.DidNotReceiveWithAnyArgs().GetAudioStreamAsync(default!, default);
await youTubeMusicService.DidNotReceiveWithAnyArgs().GetAudioStreamAsync(default!, TestContext.Current.CancellationToken);
}
[Fact]
@@ -52,14 +52,14 @@ public sealed class ResolveYouTubeTrackStreamCommandHandlerTests : HandlerTestBa
youTubeMusicService.ResolveArtworkUrl(Arg.Any<string>()).Returns(callInfo => callInfo.Arg<string>());
await SeedAsync(TestEntities.User(42));
var result = await CreateHandler().Handle(new ResolveYouTubeTrackStreamCommand("new-video", 42), CancellationToken.None);
var result = await CreateHandler().Handle(new ResolveYouTubeTrackStreamCommand("new-video", 42), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Equal(YouTubeStreamMode.YouTube, result.Value.Mode);
Assert.Equal("https://youtube.example/stream", result.Value.StreamUrl);
Assert.NotNull(result.Value.TrackId);
var history = Assert.Single(await Database.ListeningHistories.ToListAsync());
var history = Assert.Single(await Database.ListeningHistories.ToListAsync(TestContext.Current.CancellationToken));
Assert.Equal(42, history.UserId);
}
}
@@ -15,11 +15,11 @@ public sealed class SearchYouTubeAlbumsQueryHandlerTests
[Fact]
public async Task Handle_EmptyQuery_ReturnsValidationErrorWithoutCallingTheService()
{
var result = await CreateHandler().Handle(new SearchYouTubeAlbumsQuery(string.Empty, string.Empty), CancellationToken.None);
var result = await CreateHandler().Handle(new SearchYouTubeAlbumsQuery(string.Empty, string.Empty), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Validation, result.FirstError.Type);
await youTubeMusicService.DidNotReceiveWithAnyArgs()
.SearchAlbumsAsync(default!, default!, default);
.SearchAlbumsAsync(default!, default!, TestContext.Current.CancellationToken);
}
[Fact]
@@ -28,7 +28,7 @@ public sealed class SearchYouTubeAlbumsQueryHandlerTests
var expected = new YouTubeAlbumSearchResult([], "next-token");
youTubeMusicService.SearchAlbumsAsync("query", "token", Arg.Any<CancellationToken>()).Returns(expected);
var result = await CreateHandler().Handle(new SearchYouTubeAlbumsQuery("query", "token"), CancellationToken.None);
var result = await CreateHandler().Handle(new SearchYouTubeAlbumsQuery("query", "token"), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Same(expected, result.Value);
@@ -15,11 +15,11 @@ public sealed class SearchYouTubeTracksQueryHandlerTests
[Fact]
public async Task Handle_EmptyQuery_ReturnsValidationErrorWithoutCallingTheService()
{
var result = await CreateHandler().Handle(new SearchYouTubeTracksQuery(string.Empty, string.Empty), CancellationToken.None);
var result = await CreateHandler().Handle(new SearchYouTubeTracksQuery(string.Empty, string.Empty), TestContext.Current.CancellationToken);
Assert.Equal(ErrorType.Validation, result.FirstError.Type);
await youTubeMusicService.DidNotReceiveWithAnyArgs()
.SearchSongsAsync(default!, default!, default);
.SearchSongsAsync(default!, default!, TestContext.Current.CancellationToken);
}
[Fact]
@@ -28,7 +28,7 @@ public sealed class SearchYouTubeTracksQueryHandlerTests
var expected = new YouTubeSearchResult([], "next-token");
youTubeMusicService.SearchSongsAsync("query", "token", Arg.Any<CancellationToken>()).Returns(expected);
var result = await CreateHandler().Handle(new SearchYouTubeTracksQuery("query", "token"), CancellationToken.None);
var result = await CreateHandler().Handle(new SearchYouTubeTracksQuery("query", "token"), TestContext.Current.CancellationToken);
Assert.False(result.IsError);
Assert.Same(expected, result.Value);
@@ -3,11 +3,12 @@
<PropertyGroup>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.v3" />
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
@@ -3,6 +3,7 @@
<PropertyGroup>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
@@ -14,7 +15,7 @@
<PackageReference Include="NSubstitute" />
<PackageReference Include="Testcontainers" />
<PackageReference Include="Testcontainers.PostgreSql" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.v3" />
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
@@ -14,8 +14,8 @@ public sealed class AuditableEntityInterceptorTests(InfrastructureTestFixture fi
var before = DateTime.UtcNow;
var user = new User { Id = Random.Shared.NextInt64(1, long.MaxValue), Name = "audit-user", NormalizedName = "AUDIT-USER" };
await database.Users.AddAsync(user);
await database.SaveChangesAsync(CancellationToken.None);
await database.Users.AddAsync(user, TestContext.Current.CancellationToken);
await database.SaveChangesAsync(TestContext.Current.CancellationToken);
var after = DateTime.UtcNow;
@@ -29,14 +29,14 @@ public sealed class AuditableEntityInterceptorTests(InfrastructureTestFixture fi
await using var database = fixture.CreateDatabase();
var user = new User { Id = Random.Shared.NextInt64(1, long.MaxValue), Name = "audit-user-2", NormalizedName = "AUDIT-USER-2" };
await database.Users.AddAsync(user);
await database.SaveChangesAsync(CancellationToken.None);
await database.Users.AddAsync(user, TestContext.Current.CancellationToken);
await database.SaveChangesAsync(TestContext.Current.CancellationToken);
var originalCreatedAt = user.CreatedAt;
await Task.Delay(TimeSpan.FromMilliseconds(50));
await Task.Delay(TimeSpan.FromMilliseconds(50), TestContext.Current.CancellationToken);
user.Name = "audit-user-2-renamed";
await database.SaveChangesAsync(CancellationToken.None);
await database.SaveChangesAsync(TestContext.Current.CancellationToken);
Assert.Equal(originalCreatedAt, user.CreatedAt);
Assert.True(user.UpdatedAt > originalCreatedAt,
@@ -15,7 +15,7 @@ public sealed class DatabaseTests(InfrastructureTestFixture fixture)
await using var database = fixture.CreateDatabase();
var user = new User { Id = Random.Shared.NextInt64(1, long.MaxValue), Name = "roundtrip-user", NormalizedName = "ROUNDTRIP-USER" };
await database.Users.AddAsync(user);
await database.Users.AddAsync(user, TestContext.Current.CancellationToken);
var track = new LocalTrack
{
@@ -27,11 +27,11 @@ public sealed class DatabaseTests(InfrastructureTestFixture fixture)
Pictures = new TrackPictures { OriginalName = "cover.webp", ProcessingStatus = ProcessingStatus.Pending },
Audio = new TrackAudio { OriginalName = "song.mp3", TranscodeStatus = ProcessingStatus.Pending }
};
await database.LocalTracks.AddAsync(track);
await database.SaveChangesAsync(CancellationToken.None);
await database.LocalTracks.AddAsync(track, TestContext.Current.CancellationToken);
await database.SaveChangesAsync(TestContext.Current.CancellationToken);
await using var reloaded = fixture.CreateDatabase();
var stored = await reloaded.Tracks.AsNoTracking().SingleAsync(t => t.Id == track.Id);
var stored = await reloaded.Tracks.AsNoTracking().SingleAsync(t => t.Id == track.Id, TestContext.Current.CancellationToken);
Assert.IsType<LocalTrack>(stored);
Assert.Equal("Round Trip Track", stored.Title);
@@ -46,13 +46,13 @@ public sealed class DatabaseTests(InfrastructureTestFixture fixture)
await using var database = fixture.CreateDatabase();
var videoId = $"dup-{Guid.NewGuid():N}";
await database.ExternalTracks.AddAsync(BuildExternalTrack(videoId));
await database.SaveChangesAsync(CancellationToken.None);
await database.ExternalTracks.AddAsync(BuildExternalTrack(videoId), TestContext.Current.CancellationToken);
await database.SaveChangesAsync(TestContext.Current.CancellationToken);
await using var second = fixture.CreateDatabase();
await second.ExternalTracks.AddAsync(BuildExternalTrack(videoId));
await second.ExternalTracks.AddAsync(BuildExternalTrack(videoId), TestContext.Current.CancellationToken);
await Assert.ThrowsAsync<DbUpdateException>(() => second.SaveChangesAsync(CancellationToken.None));
await Assert.ThrowsAsync<DbUpdateException>(() => second.SaveChangesAsync(TestContext.Current.CancellationToken));
}
[Fact]
@@ -66,16 +66,16 @@ public sealed class DatabaseTests(InfrastructureTestFixture fixture)
var link = new AlbumHasTrack { AlbumId = album.Id, TrackId = track.Id, TrackNumber = 1 };
await database.AddRangeAsync(user, album, track, link);
await database.SaveChangesAsync(CancellationToken.None);
await database.SaveChangesAsync(TestContext.Current.CancellationToken);
await using var deleter = fixture.CreateDatabase();
var albumToDelete = await deleter.UserAlbums.SingleAsync(a => a.Id == album.Id);
var albumToDelete = await deleter.UserAlbums.SingleAsync(a => a.Id == album.Id, TestContext.Current.CancellationToken);
deleter.UserAlbums.Remove(albumToDelete);
await deleter.SaveChangesAsync(CancellationToken.None);
await deleter.SaveChangesAsync(TestContext.Current.CancellationToken);
await using var verifier = fixture.CreateDatabase();
Assert.False(await verifier.AlbumHasTracks.AnyAsync(l => l.AlbumId == album.Id));
Assert.True(await verifier.ExternalTracks.AnyAsync(t => t.Id == track.Id));
Assert.False(await verifier.AlbumHasTracks.AnyAsync(l => l.AlbumId == album.Id, TestContext.Current.CancellationToken));
Assert.True(await verifier.ExternalTracks.AnyAsync(t => t.Id == track.Id, TestContext.Current.CancellationToken));
}
private static ExternalTrack BuildExternalTrack(string externalId) => new()
@@ -24,9 +24,9 @@ public sealed class PictureServiceTests
{
using var source = CreateSourceImage(800, 600);
await using var resized = await CreateService().ResizePictureAsWebpAsync(source, 200, 200, CancellationToken.None);
await using var resized = await CreateService().ResizePictureAsWebpAsync(source, 200, 200, TestContext.Current.CancellationToken);
using var result = await Image.LoadAsync(resized);
using var result = await Image.LoadAsync(resized, TestContext.Current.CancellationToken);
Assert.InRange(result.Width, 1, 200);
Assert.InRange(result.Height, 1, 200);
Assert.True(result.Width == 200 || result.Height == 200, "expected the longer side to land exactly on the target box");
@@ -37,9 +37,9 @@ public sealed class PictureServiceTests
{
using var source = CreateSourceImage(100, 100);
await using var resized = await CreateService().ResizePictureAsWebpAsync(source, 50, 50, CancellationToken.None);
await using var resized = await CreateService().ResizePictureAsWebpAsync(source, 50, 50, TestContext.Current.CancellationToken);
var format = await Image.DetectFormatAsync(resized);
var format = await Image.DetectFormatAsync(resized, TestContext.Current.CancellationToken);
Assert.Equal("WEBP", format?.Name, ignoreCase: true);
}
@@ -48,9 +48,9 @@ public sealed class PictureServiceTests
{
using var source = CreateSourceImage(400, 200);
await using var resized = await CreateService().ResizePictureAsWebpAsync(source, 100, 100, CancellationToken.None);
await using var resized = await CreateService().ResizePictureAsWebpAsync(source, 100, 100, TestContext.Current.CancellationToken);
using var result = await Image.LoadAsync(resized);
using var result = await Image.LoadAsync(resized, TestContext.Current.CancellationToken);
Assert.Equal(100, result.Width);
Assert.Equal(50, result.Height);
}
@@ -45,7 +45,7 @@ public sealed class PlayListPresetSeederTests(InfrastructureTestFixture fixture)
private static async Task RunToCompletionAsync(PlayListPresetSeeder seeder)
{
await seeder.StartAsync(CancellationToken.None);
await seeder.StartAsync(TestContext.Current.CancellationToken);
await (seeder.ExecuteTask ?? Task.CompletedTask);
}
@@ -66,7 +66,7 @@ public sealed class PlayListPresetSeederTests(InfrastructureTestFixture fixture)
routes.PresetLargePicturePath
})
{
var metadata = await storage.HeadObjectAsync(InfrastructureTestFixture.S3Bucket, key, CancellationToken.None);
var metadata = await storage.HeadObjectAsync(InfrastructureTestFixture.S3Bucket, key, TestContext.Current.CancellationToken);
Assert.True(metadata is not null, $"expected {key} to have been seeded");
}
}
@@ -82,7 +82,7 @@ public sealed class PlayListPresetSeederTests(InfrastructureTestFixture fixture)
await RunToCompletionAsync(secondSeeder);
var metadata = await storage.HeadObjectAsync(
InfrastructureTestFixture.S3Bucket, configuration.Routes.PresetSmallPicturePath, CancellationToken.None);
InfrastructureTestFixture.S3Bucket, configuration.Routes.PresetSmallPicturePath, TestContext.Current.CancellationToken);
Assert.NotNull(metadata);
}
@@ -96,7 +96,7 @@ public sealed class PlayListPresetSeederTests(InfrastructureTestFixture fixture)
await RunToCompletionAsync(seeder);
var metadata = await storage.HeadObjectAsync(
InfrastructureTestFixture.S3Bucket, configuration.Routes.PresetSmallPicturePath, CancellationToken.None);
InfrastructureTestFixture.S3Bucket, configuration.Routes.PresetSmallPicturePath, TestContext.Current.CancellationToken);
Assert.Null(metadata);
}
}
@@ -16,7 +16,7 @@ public sealed class StorageServiceTests(InfrastructureTestFixture fixture) : IAs
private Database database = null!;
private StorageService service = null!;
public Task InitializeAsync()
public ValueTask InitializeAsync()
{
database = fixture.CreateDatabase();
var storageConfiguration = new InfrastructureStorageConfiguration
@@ -28,10 +28,10 @@ public sealed class StorageServiceTests(InfrastructureTestFixture fixture) : IAs
UseHttp = true,
};
service = new StorageService(database, fixture.CreateS3Client(), NullLogger<StorageService>.Instance, storageConfiguration);
return Task.CompletedTask;
return ValueTask.CompletedTask;
}
public Task DisposeAsync() => database.DisposeAsync().AsTask();
public ValueTask DisposeAsync() => database.DisposeAsync();
[Fact]
public async Task UploadThenGetFile_RoundTripsTheSameBytes()
@@ -39,11 +39,11 @@ public sealed class StorageServiceTests(InfrastructureTestFixture fixture) : IAs
var key = $"tests/{Guid.NewGuid():N}/round-trip.txt";
var content = "hello seaweedfs"u8.ToArray();
await service.UploadFileAsync(new MemoryStream(content), "text/plain", InfrastructureTestFixture.S3Bucket, key, CancellationToken.None);
await service.UploadFileAsync(new MemoryStream(content), "text/plain", InfrastructureTestFixture.S3Bucket, key, TestContext.Current.CancellationToken);
await using var stream = await service.GetFileAsync(InfrastructureTestFixture.S3Bucket, key, CancellationToken.None);
await using var stream = await service.GetFileAsync(InfrastructureTestFixture.S3Bucket, key, TestContext.Current.CancellationToken);
using var reader = new StreamReader(stream, Encoding.UTF8);
var readBack = await reader.ReadToEndAsync();
var readBack = await reader.ReadToEndAsync(TestContext.Current.CancellationToken);
Assert.Equal("hello seaweedfs", readBack);
}
@@ -52,9 +52,9 @@ public sealed class StorageServiceTests(InfrastructureTestFixture fixture) : IAs
public async Task HeadObjectAsync_ExistingObject_ReturnsMetadata()
{
var key = $"tests/{Guid.NewGuid():N}/head.txt";
await service.UploadFileAsync(new MemoryStream("x"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, key, CancellationToken.None);
await service.UploadFileAsync(new MemoryStream("x"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, key, TestContext.Current.CancellationToken);
var metadata = await service.HeadObjectAsync(InfrastructureTestFixture.S3Bucket, key, CancellationToken.None);
var metadata = await service.HeadObjectAsync(InfrastructureTestFixture.S3Bucket, key, TestContext.Current.CancellationToken);
Assert.NotNull(metadata);
Assert.Equal(1, metadata.ContentLength);
@@ -63,7 +63,7 @@ public sealed class StorageServiceTests(InfrastructureTestFixture fixture) : IAs
[Fact]
public async Task HeadObjectAsync_MissingObject_ReturnsNull()
{
var metadata = await service.HeadObjectAsync(InfrastructureTestFixture.S3Bucket, $"tests/{Guid.NewGuid():N}/missing.txt", CancellationToken.None);
var metadata = await service.HeadObjectAsync(InfrastructureTestFixture.S3Bucket, $"tests/{Guid.NewGuid():N}/missing.txt", TestContext.Current.CancellationToken);
Assert.Null(metadata);
}
@@ -72,11 +72,11 @@ public sealed class StorageServiceTests(InfrastructureTestFixture fixture) : IAs
public async Task RemoveFileAsync_ExistingObject_DeletesIt()
{
var key = $"tests/{Guid.NewGuid():N}/to-remove.txt";
await service.UploadFileAsync(new MemoryStream("x"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, key, CancellationToken.None);
await service.UploadFileAsync(new MemoryStream("x"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, key, TestContext.Current.CancellationToken);
await service.RemoveFileAsync(InfrastructureTestFixture.S3Bucket, key, CancellationToken.None);
await service.RemoveFileAsync(InfrastructureTestFixture.S3Bucket, key, TestContext.Current.CancellationToken);
Assert.Null(await service.HeadObjectAsync(InfrastructureTestFixture.S3Bucket, key, CancellationToken.None));
Assert.Null(await service.HeadObjectAsync(InfrastructureTestFixture.S3Bucket, key, TestContext.Current.CancellationToken));
}
[Fact]
@@ -84,22 +84,22 @@ public sealed class StorageServiceTests(InfrastructureTestFixture fixture) : IAs
{
var sourceKey = $"tests/{Guid.NewGuid():N}/source.txt";
var destinationKey = $"tests/{Guid.NewGuid():N}/destination.txt";
await service.UploadFileAsync(new MemoryStream("copy-me"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, sourceKey, CancellationToken.None);
await service.UploadFileAsync(new MemoryStream("copy-me"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, sourceKey, TestContext.Current.CancellationToken);
await service.CopyFileAsync(InfrastructureTestFixture.S3Bucket, sourceKey, InfrastructureTestFixture.S3Bucket, destinationKey, CancellationToken.None);
await service.CopyFileAsync(InfrastructureTestFixture.S3Bucket, sourceKey, InfrastructureTestFixture.S3Bucket, destinationKey, TestContext.Current.CancellationToken);
Assert.NotNull(await service.HeadObjectAsync(InfrastructureTestFixture.S3Bucket, destinationKey, CancellationToken.None));
Assert.NotNull(await service.HeadObjectAsync(InfrastructureTestFixture.S3Bucket, destinationKey, TestContext.Current.CancellationToken));
}
[Fact]
public async Task ListObjectsAsync_ReturnsEveryObjectUnderThePrefix()
{
var prefix = $"tests/{Guid.NewGuid():N}";
await service.UploadFileAsync(new MemoryStream("a"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, $"{prefix}/a.txt", CancellationToken.None);
await service.UploadFileAsync(new MemoryStream("b"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, $"{prefix}/b.txt", CancellationToken.None);
await service.UploadFileAsync(new MemoryStream("a"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, $"{prefix}/a.txt", TestContext.Current.CancellationToken);
await service.UploadFileAsync(new MemoryStream("b"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, $"{prefix}/b.txt", TestContext.Current.CancellationToken);
var keys = new List<string>();
await foreach (var item in service.ListObjectsAsync(InfrastructureTestFixture.S3Bucket, prefix, CancellationToken.None))
await foreach (var item in service.ListObjectsAsync(InfrastructureTestFixture.S3Bucket, prefix, TestContext.Current.CancellationToken))
keys.Add(item.Key);
Assert.Equal([$"{prefix}/a.txt", $"{prefix}/b.txt"], keys.Order());
@@ -109,13 +109,13 @@ public sealed class StorageServiceTests(InfrastructureTestFixture fixture) : IAs
public async Task RemoveFolderAsync_DeletesEveryObjectUnderThePrefix()
{
var prefix = $"tests/{Guid.NewGuid():N}";
await service.UploadFileAsync(new MemoryStream("a"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, $"{prefix}/a.txt", CancellationToken.None);
await service.UploadFileAsync(new MemoryStream("b"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, $"{prefix}/nested/b.txt", CancellationToken.None);
await service.UploadFileAsync(new MemoryStream("a"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, $"{prefix}/a.txt", TestContext.Current.CancellationToken);
await service.UploadFileAsync(new MemoryStream("b"u8.ToArray()), "text/plain", InfrastructureTestFixture.S3Bucket, $"{prefix}/nested/b.txt", TestContext.Current.CancellationToken);
await service.RemoveFolderAsync(InfrastructureTestFixture.S3Bucket, prefix, CancellationToken.None);
await service.RemoveFolderAsync(InfrastructureTestFixture.S3Bucket, prefix, TestContext.Current.CancellationToken);
var remaining = new List<string>();
await foreach (var item in service.ListObjectsAsync(InfrastructureTestFixture.S3Bucket, prefix, CancellationToken.None))
await foreach (var item in service.ListObjectsAsync(InfrastructureTestFixture.S3Bucket, prefix, TestContext.Current.CancellationToken))
remaining.Add(item.Key);
Assert.Empty(remaining);
}
@@ -126,7 +126,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), CancellationToken.None);
InfrastructureTestFixture.S3Bucket, key, "text/plain", TimeSpan.FromMinutes(5), TestContext.Current.CancellationToken);
using var httpClient = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Put, uploadUrl)
@@ -141,10 +141,10 @@ public sealed class StorageServiceTests(InfrastructureTestFixture fixture) : IAs
// this header (see StorageService.GetUploadUrlAsync) — the actual PUT has to send it too,
// or the signature no longer matches and the server answers 403.
request.Headers.TryAddWithoutValidation("If-None-Match", "*");
var response = await httpClient.SendAsync(request);
var response = await httpClient.SendAsync(request, TestContext.Current.CancellationToken);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var metadata = await service.HeadObjectAsync(InfrastructureTestFixture.S3Bucket, key, CancellationToken.None);
var metadata = await service.HeadObjectAsync(InfrastructureTestFixture.S3Bucket, key, TestContext.Current.CancellationToken);
Assert.NotNull(metadata);
Assert.Equal("presigned content".Length, metadata.ContentLength);
}
@@ -44,7 +44,7 @@ public sealed class InfrastructureTestFixture : IAsyncLifetime
public string S3ServiceUrl => $"http://{seaweedFs.Hostname}:{seaweedFs.GetMappedPublicPort(8333)}";
public async Task InitializeAsync()
public async ValueTask InitializeAsync()
{
await Task.WhenAll(postgres.StartAsync(), seaweedFs.StartAsync());
@@ -56,7 +56,7 @@ public sealed class InfrastructureTestFixture : IAsyncLifetime
await s3.PutBucketAsync(S3Bucket);
}
public async Task DisposeAsync()
public async ValueTask DisposeAsync()
{
await postgres.DisposeAsync();
await seaweedFs.DisposeAsync();
@@ -3,11 +3,12 @@
<PropertyGroup>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.v3" />
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>