using System.Net; using OpenNest.Data; namespace OpenNest.Tests.Data; public class RemoteDrawingSetStoreTests { private static RemoteDrawingSetStore Store(StubHandler handler) => new(new HttpClient(handler), "http://server:8090/base/"); private static DrawingSetRecord Set(Guid? drawing = null) => new() { Id = Guid.NewGuid(), Name = "Synthetic kit", Members = new[] { new DrawingSetMember { DrawingId = drawing ?? Guid.NewGuid(), Quantity = 2 } }, }; [Fact] public async Task QueryAsync_SendsEscapedFilters() { var handler = new StubHandler(_ => StubHandler.Json(new { items = Array.Empty(), total = 0, offset = 5, limit = 5 })); using var store = Store(handler); await store.QueryAsync(new DrawingSetQuery { Search = " 50%_ ", Customer = "A&B", IncludeArchived = true, Sort = DrawingSetSortField.Customer, Descending = false, Offset = 5, Limit = 5, }); Assert.Equal( "http://server:8090/base/api/sets/query?search=50%25_&sort=customer&order=asc&offset=5&limit=5&customer=A%26B&includeArchived=true", handler.Requests.Single().RequestUri!.AbsoluteUri); } [Fact] public async Task OldServer_RaisesServerTooOld() { using var store = Store(new StubHandler(_ => new HttpResponseMessage(HttpStatusCode.NotFound))); var query = await Assert.ThrowsAsync(() => store.QueryAsync(new DrawingSetQuery())); await Assert.ThrowsAsync(() => store.GetAsync(Guid.NewGuid())); var releases = await Assert.ThrowsAsync(() => store.QueryReleasesAsync(nestId: Guid.NewGuid())); await Assert.ThrowsAsync(() => store.GetReleaseAsync(Guid.NewGuid())); Assert.Contains("several drawing sets", releases.Message); Assert.Contains("drawing sets", query.Message); } [Fact] public async Task ServerWithoutDrawingsOnTheirOwn_RefusesTheDrawingFilter_AndTheSupportCheck() { // A server from before drawings on their own refuses the unknown query parameter. var handler = new StubHandler(request => request.RequestUri!.Query.Contains("drawingId=") ? new HttpResponseMessage(HttpStatusCode.BadRequest) : StubHandler.Json(new { items = Array.Empty(), total = 0, offset = 0, limit = 100 })); using var store = Store(handler); var check = await Assert.ThrowsAsync(() => store.EnsureDrawingReleasesSupportedAsync()); await Assert.ThrowsAsync(() => store.QueryReleasesAsync(drawingId: Guid.NewGuid())); await store.QueryReleasesAsync(setId: Guid.NewGuid()); Assert.Contains("releasing library drawings on their own", check.Message); Assert.Contains("api/releases/query?drawingId=", handler.Requests[0].RequestUri!.AbsoluteUri); using var missing = Store(new StubHandler(_ => new HttpResponseMessage(HttpStatusCode.NotFound))); await Assert.ThrowsAsync(() => missing.EnsureDrawingReleasesSupportedAsync()); using var current = Store(new StubHandler(_ => StubHandler.Json(new { items = Array.Empty(), total = 0, offset = 0, limit = 1 }))); await current.EnsureDrawingReleasesSupportedAsync(); } [Fact] public async Task UnknownSet_OnASetAwareServer_IsNull() { var handler = new StubHandler(request => request.RequestUri!.AbsolutePath.EndsWith("/api/sets/query") ? StubHandler.Json(new { items = Array.Empty(), total = 0, offset = 0, limit = 1 }) : new HttpResponseMessage(HttpStatusCode.NotFound)); using var store = Store(handler); Assert.Null(await store.GetAsync(Guid.NewGuid())); Assert.EndsWith("api/sets/query?limit=1", handler.Requests[1].RequestUri!.AbsoluteUri); } [Fact] public async Task InvalidSet_IsRefusedBeforeSending() { var handler = new StubHandler(_ => throw new InvalidOperationException("Nothing may be sent.")); using var store = Store(handler); var duplicate = Set(); duplicate.Members = duplicate.Members.Concat(duplicate.Members).ToList(); await Assert.ThrowsAsync(() => store.CreateAsync(duplicate)); await Assert.ThrowsAsync(() => store.PostReleaseAsync(new SetReleaseRecord { Id = Guid.NewGuid(), Sets = new[] { new SetReleaseLine { SetId = Guid.NewGuid(), SetRevision = 1, Quantity = 0 } }, })); await Assert.ThrowsAsync(() => store.UndoReleaseAsync(Guid.NewGuid(), new SetReleaseUndoRequest { SkipNests = new[] { Guid.Empty } })); Assert.Empty(handler.Requests); } [Fact] public async Task CreateAsync_SendsMembersWithoutJoinedDrawingsAndChecksTheReply() { var drawing = Guid.NewGuid(); var set = Set(drawing); set.Members[0].Drawing = new DrawingLibraryRecord { Id = drawing, Name = "Synthetic joined" }; var handler = new StubHandler(_ => StubHandler.Json(new { id = set.Id, revision = 1, name = set.Name, members = new[] { new { drawingId = drawing, quantity = 3 } }, })); using var store = Store(handler); await Assert.ThrowsAsync(() => store.CreateAsync(set)); Assert.DoesNotContain("Synthetic joined", handler.RequestBodies.Single()); } [Fact] public async Task PostReleaseAsync_ReplyForOtherNests_IsRefused() { var setId = Guid.NewGuid(); var release = new SetReleaseRecord { Id = Guid.NewGuid(), Sets = new[] { new SetReleaseLine { SetId = setId, SetRevision = 1, Quantity = 1 } }, Nests = new[] { new SetReleaseNest { NestId = Guid.NewGuid(), RevisionAfter = 1, MaterialName = "Synthetic Steel" } }, }; var handler = new StubHandler(_ => StubHandler.Json(new { id = release.Id, sets = new[] { new { setId, setRevision = 1, quantity = 1 } }, nests = new[] { new { nestId = Guid.NewGuid(), kind = "created", revisionAfter = 1 } }, })); using var store = Store(handler); await Assert.ThrowsAsync(() => store.PostReleaseAsync(release)); } }