From 335e1a785e621b2decb269a8c6f3ada5d6e3ce30 Mon Sep 17 00:00:00 2001 From: XShine555 Date: Fri, 29 May 2026 15:47:38 +0200 Subject: [PATCH] Remove tests --- Musify.WebApi.slnx | 3 - .../Extensions/ResultHttpExtensionsTests.cs | 122 ---------- .../Integration/ApiIntegrationTests.cs | 140 ------------ .../Integration/MusifyApiFactory.cs | 79 ------- .../Musify.WebApi.Tests.csproj | 34 --- .../Validators/ValidatorTests.cs | 214 ------------------ 6 files changed, 592 deletions(-) delete mode 100644 Tests/Musify.WebApi.Tests/Extensions/ResultHttpExtensionsTests.cs delete mode 100644 Tests/Musify.WebApi.Tests/Integration/ApiIntegrationTests.cs delete mode 100644 Tests/Musify.WebApi.Tests/Integration/MusifyApiFactory.cs delete mode 100644 Tests/Musify.WebApi.Tests/Musify.WebApi.Tests.csproj delete mode 100644 Tests/Musify.WebApi.Tests/Validators/ValidatorTests.cs diff --git a/Musify.WebApi.slnx b/Musify.WebApi.slnx index 5a8e7b9..c239259 100644 --- a/Musify.WebApi.slnx +++ b/Musify.WebApi.slnx @@ -1,6 +1,3 @@ - - - diff --git a/Tests/Musify.WebApi.Tests/Extensions/ResultHttpExtensionsTests.cs b/Tests/Musify.WebApi.Tests/Extensions/ResultHttpExtensionsTests.cs deleted file mode 100644 index 7aa73d9..0000000 --- a/Tests/Musify.WebApi.Tests/Extensions/ResultHttpExtensionsTests.cs +++ /dev/null @@ -1,122 +0,0 @@ -using Ardalis.Result; -using FluentAssertions; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.HttpResults; -using WebApi.Extensions; -using Xunit; -using IResult = Microsoft.AspNetCore.Http.IResult; - -namespace Musify.WebApi.Tests.Extensions; - -public sealed class ResultHttpExtensionsTests -{ - private static int StatusCodeOf(IResult result) => - ((IStatusCodeHttpResult)result).StatusCode ?? 0; - - [Fact] - public void Result_Ok_maps_to_204_no_content() - { - StatusCodeOf(Result.Success().ToHttpResult()).Should().Be(StatusCodes.Status204NoContent); - } - - [Fact] - public void Result_NoContent_maps_to_204() - { - StatusCodeOf(Result.NoContent().ToHttpResult()).Should().Be(StatusCodes.Status204NoContent); - } - - [Fact] - public void Result_NotFound_maps_to_404() - { - StatusCodeOf(Result.NotFound("nope").ToHttpResult()).Should().Be(StatusCodes.Status404NotFound); - } - - [Fact] - public void Result_Invalid_maps_to_validation_problem_400() - { - var result = Result.Invalid(new ValidationError("field", "bad")).ToHttpResult(); - result.Should().BeOfType(); - StatusCodeOf(result).Should().Be(StatusCodes.Status400BadRequest); - } - - [Fact] - public void Result_Unauthorized_maps_to_401() - { - StatusCodeOf(Result.Unauthorized().ToHttpResult()).Should().Be(StatusCodes.Status401Unauthorized); - } - - [Fact] - public void Result_Forbidden_maps_to_403() - { - StatusCodeOf(Result.Forbidden().ToHttpResult()).Should().Be(StatusCodes.Status403Forbidden); - } - - [Fact] - public void Result_Conflict_maps_to_409() - { - StatusCodeOf(Result.Conflict("dup").ToHttpResult()).Should().Be(StatusCodes.Status409Conflict); - } - - [Fact] - public void Result_Error_maps_to_problem_500() - { - var result = Result.Error("boom").ToHttpResult(); - result.Should().BeOfType(); - StatusCodeOf(result).Should().Be(StatusCodes.Status500InternalServerError); - } - - [Fact] - public void ResultT_Ok_maps_to_200_with_value() - { - var result = Result.Success("payload").ToHttpResult(); - result.Should().BeOfType>(); - result.As>().Value.Should().Be("payload"); - } - - [Fact] - public void ResultT_NotFound_maps_to_404() - { - StatusCodeOf(Result.NotFound("nope").ToHttpResult()).Should().Be(StatusCodes.Status404NotFound); - } - - [Fact] - public void ResultT_Invalid_maps_to_validation_problem_with_grouped_errors() - { - var result = Result.Invalid( - new ValidationError("Name", "required"), - new ValidationError("Name", "too short"), - new ValidationError("Age", "invalid")).ToHttpResult(); - - result.Should().BeOfType(); - var details = result.As().ProblemDetails.Should().BeOfType().Subject; - details.Errors.Should().ContainKey("Name"); - details.Errors["Name"].Should().BeEquivalentTo("required", "too short"); - details.Errors.Should().ContainKey("Age"); - } - - [Fact] - public void ResultT_Unauthorized_maps_to_401() - { - StatusCodeOf(Result.Unauthorized().ToHttpResult()).Should().Be(StatusCodes.Status401Unauthorized); - } - - [Fact] - public void ResultT_Forbidden_maps_to_403() - { - StatusCodeOf(Result.Forbidden().ToHttpResult()).Should().Be(StatusCodes.Status403Forbidden); - } - - [Fact] - public void ResultT_Conflict_maps_to_409() - { - StatusCodeOf(Result.Conflict("dup").ToHttpResult()).Should().Be(StatusCodes.Status409Conflict); - } - - [Fact] - public void ResultT_Error_maps_to_problem_500() - { - var result = Result.Error("boom").ToHttpResult(); - result.Should().BeOfType(); - StatusCodeOf(result).Should().Be(StatusCodes.Status500InternalServerError); - } -} diff --git a/Tests/Musify.WebApi.Tests/Integration/ApiIntegrationTests.cs b/Tests/Musify.WebApi.Tests/Integration/ApiIntegrationTests.cs deleted file mode 100644 index af7aae9..0000000 --- a/Tests/Musify.WebApi.Tests/Integration/ApiIntegrationTests.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System.Net; -using System.Net.Http.Json; -using FluentAssertions; -using Musify.Application.PlayLists.Responses; -using Musify.Application.Users.Responses; -using NSubstitute; -using WebApi.DataTransferObjects.PlayLists; -using WebApi.DataTransferObjects.Tracks; -using WebApi.DataTransferObjects.Users; -using Xunit; - -namespace Musify.WebApi.Tests.Integration; - -public sealed class ApiIntegrationTests(MusifyApiFactory factory) - : IClassFixture -{ - private sealed record ValidationProblemResponse(Dictionary Errors); - - private sealed record TrackUploadUrlsLikeResponse(string PictureUploadUrl, string AudioUploadUrl); - - private readonly HttpClient _client = factory.CreateClient(); - - private async Task CreateUserAsync(string name = "IntegrationUser") - { - var id = Guid.NewGuid(); - var response = await _client.PostAsJsonAsync("/users/", new CreateUserRequest(id, name, null, null)); - response.StatusCode.Should().Be(HttpStatusCode.Created); - return id; - } - - [Fact] - public async Task Create_then_get_user_roundtrips_through_the_real_pipeline() - { - var id = Guid.NewGuid(); - - var create = await _client.PostAsJsonAsync("/users/", new CreateUserRequest(id, "Alice", "Al", "Ice")); - create.StatusCode.Should().Be(HttpStatusCode.Created); - - var get = await _client.GetAsync($"/users/{id}"); - get.StatusCode.Should().Be(HttpStatusCode.OK); - UserApplicationResponse user = await get.Content.ReadFromJsonAsync() - ?? throw new InvalidOperationException("The response body was null."); - user.Id.Should().Be(id); - user.Name.Should().Be("Alice"); - } - - [Fact] - public async Task Create_user_with_invalid_body_returns_400_validation_problem() - { - var response = await _client.PostAsJsonAsync("/users/", new CreateUserRequest(Guid.Empty, "", null, null)); - - response.StatusCode.Should().Be(HttpStatusCode.BadRequest); - ValidationProblemResponse problem = await response.Content.ReadFromJsonAsync() - ?? throw new InvalidOperationException("The response body was null."); - problem.Errors.Should().ContainKey(nameof(CreateUserRequest.Name)); - } - - [Fact] - public async Task Create_duplicate_user_returns_409_conflict() - { - var id = await CreateUserAsync(); - - var duplicate = await _client.PostAsJsonAsync("/users/", new CreateUserRequest(id, "Other", null, null)); - - duplicate.StatusCode.Should().Be(HttpStatusCode.Conflict); - } - - [Fact] - public async Task Get_unknown_user_returns_404() - { - var response = await _client.GetAsync($"/users/{Guid.NewGuid()}"); - response.StatusCode.Should().Be(HttpStatusCode.NotFound); - } - - [Fact] - public async Task Create_playlist_without_picture_returns_201_and_persists() - { - var userId = await CreateUserAsync(); - - var response = await _client.PostAsJsonAsync( - $"/playLists/users/{userId}", - new CreatePlayListRequest("My Mix", "A description", null)); - - response.StatusCode.Should().Be(HttpStatusCode.Created); - PlayListApplicationResponse playList = await response.Content.ReadFromJsonAsync() - ?? throw new InvalidOperationException("The response body was null."); - playList.Name.Should().Be("My Mix"); - - var get = await _client.GetAsync($"/playLists/{playList.Id}"); - get.StatusCode.Should().Be(HttpStatusCode.OK); - } - - [Fact] - public async Task Create_playlist_for_unknown_user_returns_404() - { - var response = await _client.PostAsJsonAsync( - $"/playLists/users/{Guid.NewGuid()}", - new CreatePlayListRequest("Mix", "desc", null)); - - response.StatusCode.Should().Be(HttpStatusCode.NotFound); - } - - [Fact] - public async Task Create_playlist_with_invalid_body_returns_400() - { - var userId = await CreateUserAsync(); - - var response = await _client.PostAsJsonAsync( - $"/playLists/users/{userId}", - new CreatePlayListRequest("", "", null)); - - response.StatusCode.Should().Be(HttpStatusCode.BadRequest); - } - - [Fact] - public async Task Get_unknown_track_returns_404() - { - var response = await _client.GetAsync($"/tracks/{Guid.NewGuid()}"); - response.StatusCode.Should().Be(HttpStatusCode.NotFound); - } - - [Fact] - public async Task Request_track_upload_urls_issues_presigned_urls() - { - var userId = await CreateUserAsync(); - factory.Storage - .GetUploadUrlAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) - .Returns("https://signed.example/put"); - - var response = await _client.PostAsJsonAsync( - $"/tracks/upload-urls/users/{userId}", - new RequestTrackUploadUrlsRequest("png", "image/png", "mp3", "audio/mpeg")); - - response.StatusCode.Should().Be(HttpStatusCode.OK); - TrackUploadUrlsLikeResponse body = await response.Content.ReadFromJsonAsync() - ?? throw new InvalidOperationException("The response body was null."); - body.PictureUploadUrl.Should().Be("https://signed.example/put"); - body.AudioUploadUrl.Should().Be("https://signed.example/put"); - } -} diff --git a/Tests/Musify.WebApi.Tests/Integration/MusifyApiFactory.cs b/Tests/Musify.WebApi.Tests/Integration/MusifyApiFactory.cs deleted file mode 100644 index 71cb896..0000000 --- a/Tests/Musify.WebApi.Tests/Integration/MusifyApiFactory.cs +++ /dev/null @@ -1,79 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Hosting; -using Musify.Application.Contracts; -using Musify.Application.Tests.Infrastructure; -using NSubstitute; - -namespace Musify.WebApi.Tests.Integration; - -public sealed class MusifyApiFactory : WebApplicationFactory -{ - private readonly SqliteConnection _connection = new("DataSource=:memory:;Foreign Keys=False"); - - public IStorageService Storage { get; } = Substitute.For(); - public IEventBus EventBus { get; } = Substitute.For(); - - protected override void ConfigureWebHost(IWebHostBuilder builder) - { - builder.UseEnvironment("Testing"); - - builder.ConfigureAppConfiguration((_, config) => - { - config.AddInMemoryCollection(new Dictionary - { - ["Database:ConnectionString"] = "Host=localhost;Database=test;Username=test;Password=test", - ["ApplicationStorage:Bucket"] = TestData.Bucket, - ["PlayList:Routes:ParentFolders"] = "PlayLists", - ["Track:Routes:ParentFolder"] = "Tracks", - ["UploadIntent:TempRootPrefix"] = "temp", - ["InfrastructureStorage:Address"] = "http://localhost:9000", - ["InfrastructureStorage:AccessKey"] = "test", - ["InfrastructureStorage:SecretAccessKey"] = "test", - ["InfrastructureStorage:ForcePathStyle"] = "true", - ["InfrastructureStorage:UseHttp"] = "true", - ["MassTransit:Address"] = "rabbitmq://localhost", - ["MassTransit:Username"] = "guest", - ["MassTransit:Password"] = "guest", - ["OpenTelemetry:OtlpEndpoint"] = "http://localhost:4317", - } ); - } ); - - builder.ConfigureTestServices(services => - { - services.RemoveAll(); - - _connection.Open(); - - services.RemoveAll(); - services.AddScoped(_ => - { - var options = new DbContextOptionsBuilder() - .UseSqlite(_connection) - .Options; - var db = new TestDatabase(options); - db.Database.EnsureCreated(); - return db; - }); - - services.RemoveAll(); - services.AddScoped(_ => Storage); - - services.RemoveAll(); - services.AddScoped(_ => EventBus); - } ); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - _connection.Dispose(); - } -} diff --git a/Tests/Musify.WebApi.Tests/Musify.WebApi.Tests.csproj b/Tests/Musify.WebApi.Tests/Musify.WebApi.Tests.csproj deleted file mode 100644 index 356c23c..0000000 --- a/Tests/Musify.WebApi.Tests/Musify.WebApi.Tests.csproj +++ /dev/null @@ -1,34 +0,0 @@ - - - - net10.0 - enable - enable - false - Musify.WebApi.Tests - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - diff --git a/Tests/Musify.WebApi.Tests/Validators/ValidatorTests.cs b/Tests/Musify.WebApi.Tests/Validators/ValidatorTests.cs deleted file mode 100644 index 046f9ed..0000000 --- a/Tests/Musify.WebApi.Tests/Validators/ValidatorTests.cs +++ /dev/null @@ -1,214 +0,0 @@ -using FluentValidation.TestHelper; -using WebApi.DataTransferObjects.PlayLists; -using WebApi.DataTransferObjects.Tracks; -using WebApi.DataTransferObjects.Users; -using WebApi.Validators.PlayLists; -using WebApi.Validators.Tracks; -using WebApi.Validators.Users; -using Xunit; - -namespace Musify.WebApi.Tests.Validators; - -public sealed class CreateTrackRequestValidatorTests -{ - private readonly CreateTrackRequestValidator _validator = new(); - - [Fact] - public void Valid_request_passes() - { - var model = new CreateTrackRequest("Song", Guid.NewGuid(), Guid.NewGuid()); - _validator.TestValidate(model).ShouldNotHaveAnyValidationErrors(); - } - - [Theory] - [InlineData("")] - [InlineData(null)] - public void Empty_title_fails(string? title) - { - var model = new CreateTrackRequest(title!, Guid.NewGuid(), Guid.NewGuid()); - _validator.TestValidate(model).ShouldHaveValidationErrorFor(x => x.Title); - } - - [Fact] - public void Title_longer_than_50_fails() - { - var model = new CreateTrackRequest(new string('a', 51), Guid.NewGuid(), Guid.NewGuid()); - _validator.TestValidate(model).ShouldHaveValidationErrorFor(x => x.Title); - } - - [Fact] - public void Empty_intent_ids_fail() - { - var model = new CreateTrackRequest("Song", Guid.Empty, Guid.Empty); - var result = _validator.TestValidate(model); - result.ShouldHaveValidationErrorFor(x => x.PictureIntentId); - result.ShouldHaveValidationErrorFor(x => x.AudioIntentId); - } -} - -public sealed class RequestTrackUploadUrlsRequestValidatorTests -{ - private readonly RequestTrackUploadUrlsRequestValidator _validator = new(); - - private static RequestTrackUploadUrlsRequest Valid() => - new("png", "image/png", "mp3", "audio/mpeg"); - - [Fact] - public void Valid_request_passes() - { - _validator.TestValidate(Valid()).ShouldNotHaveAnyValidationErrors(); - } - - [Fact] - public void Missing_required_fields_fail() - { - var model = new RequestTrackUploadUrlsRequest("", "", "", ""); - var result = _validator.TestValidate(model); - result.ShouldHaveValidationErrorFor(x => x.PictureFileType); - result.ShouldHaveValidationErrorFor(x => x.PictureContentType); - result.ShouldHaveValidationErrorFor(x => x.AudioFileType); - result.ShouldHaveValidationErrorFor(x => x.AudioContentType); - } - - [Fact] - public void Non_positive_expected_sizes_fail_when_provided() - { - var model = Valid() with { ExpectedPictureSizeBytes = 0, ExpectedAudioSizeBytes = -1 }; - var result = _validator.TestValidate(model); - result.ShouldHaveValidationErrorFor(x => x.ExpectedPictureSizeBytes); - result.ShouldHaveValidationErrorFor(x => x.ExpectedAudioSizeBytes); - } - - [Fact] - public void Null_expected_sizes_are_allowed() - { - var model = Valid() with { ExpectedPictureSizeBytes = null, ExpectedAudioSizeBytes = null }; - var result = _validator.TestValidate(model); - result.ShouldNotHaveValidationErrorFor(x => x.ExpectedPictureSizeBytes); - result.ShouldNotHaveValidationErrorFor(x => x.ExpectedAudioSizeBytes); - } -} - -public sealed class CreatePlayListRequestValidatorTests -{ - private readonly CreatePlayListRequestValidator _validator = new(); - - [Fact] - public void Valid_request_passes() - { - var model = new CreatePlayListRequest("My List", "A description", null); - _validator.TestValidate(model).ShouldNotHaveAnyValidationErrors(); - } - - [Fact] - public void Empty_name_and_description_fail() - { - var model = new CreatePlayListRequest("", "", null); - var result = _validator.TestValidate(model); - result.ShouldHaveValidationErrorFor(x => x.Name); - result.ShouldHaveValidationErrorFor(x => x.Description); - } - - [Fact] - public void Over_length_name_and_description_fail() - { - var model = new CreatePlayListRequest(new string('n', 51), new string('d', 257), null); - var result = _validator.TestValidate(model); - result.ShouldHaveValidationErrorFor(x => x.Name); - result.ShouldHaveValidationErrorFor(x => x.Description); - } -} - -public sealed class UpdatePlayListRequestValidatorTests -{ - private readonly UpdatePlayListRequestValidator _validator = new(); - - [Fact] - public void All_null_is_valid() - { - _validator.TestValidate(new UpdatePlayListRequest(null, null, null)) - .ShouldNotHaveAnyValidationErrors(); - } - - [Fact] - public void Over_length_values_fail_only_when_provided() - { - var model = new UpdatePlayListRequest(new string('n', 51), new string('d', 257), null); - var result = _validator.TestValidate(model); - result.ShouldHaveValidationErrorFor(x => x.NewName); - result.ShouldHaveValidationErrorFor(x => x.NewDescription); - } - - [Fact] - public void Empty_string_name_is_allowed_by_length_rule() - { - var model = new UpdatePlayListRequest("", null, null); - _validator.TestValidate(model).ShouldNotHaveValidationErrorFor(x => x.NewName); - } -} - -public sealed class RequestPlayListPictureUploadRequestValidatorTests -{ - private readonly RequestPlayListPictureUploadRequestValidator _validator = new(); - - [Fact] - public void Valid_request_passes() - { - _validator.TestValidate(new RequestPlayListPictureUploadRequest("webp", "image/webp")) - .ShouldNotHaveAnyValidationErrors(); - } - - [Fact] - public void Missing_filetype_and_contenttype_fail() - { - var result = _validator.TestValidate(new RequestPlayListPictureUploadRequest("", "")); - result.ShouldHaveValidationErrorFor(x => x.FileType); - result.ShouldHaveValidationErrorFor(x => x.ContentType); - } - - [Fact] - public void Non_positive_size_fails_when_provided() - { - var result = _validator.TestValidate(new RequestPlayListPictureUploadRequest("webp", "image/webp", 0)); - result.ShouldHaveValidationErrorFor(x => x.ExpectedSizeBytes); - } -} - -public sealed class CreateUserRequestValidatorTests -{ - private readonly CreateUserRequestValidator _validator = new(); - - [Fact] - public void Valid_request_passes() - { - var model = new CreateUserRequest(Guid.NewGuid(), "Alice", "Al", "Ice"); - _validator.TestValidate(model).ShouldNotHaveAnyValidationErrors(); - } - - [Fact] - public void Empty_id_and_name_fail() - { - var model = new CreateUserRequest(Guid.Empty, "", null, null); - var result = _validator.TestValidate(model); - result.ShouldHaveValidationErrorFor(x => x.Id); - result.ShouldHaveValidationErrorFor(x => x.Name); - } - - [Fact] - public void Over_length_optional_names_fail_only_when_provided() - { - var model = new CreateUserRequest(Guid.NewGuid(), "Alice", new string('f', 49), new string('s', 49)); - var result = _validator.TestValidate(model); - result.ShouldHaveValidationErrorFor(x => x.FirstName); - result.ShouldHaveValidationErrorFor(x => x.SecondName); - } - - [Fact] - public void Null_optional_names_are_allowed() - { - var model = new CreateUserRequest(Guid.NewGuid(), "Alice", null, null); - var result = _validator.TestValidate(model); - result.ShouldNotHaveValidationErrorFor(x => x.FirstName); - result.ShouldNotHaveValidationErrorFor(x => x.SecondName); - } -}