using System.Net; using System.Net.Http.Json; namespace HSchool.AppHost.Tests; [Collection(AppHostCollection.Name)] public class NoticeImageApiTests(AppHostFixture fixture) { private static readonly DateTime Start = new(2012, 4, 3, 6, 0, 0, DateTimeKind.Utc); [Fact] public async Task OwnerGenerate_MatchesCardOutcome_GuestIs403() { using var owner = await SchoolApiTests.CreateIsolatedClientAsync(fixture.App, "NoticeImageOwner"); await SchoolApiTests.WipeAllSavesAsync(owner); var school = await SchoolApiTests.CreateAsync(owner, "Кнопка хозяина", Start); var personId = await FirstPersonIdAsync(owner, school.Id); var posted = await PostNoticeAsync(owner, school.Id, "GenerationFailed", personId, "full"); using var card = await owner.PostAsync( $"/api/schools/{school.Id}/people/{Uri.EscapeDataString(personId)}/portrait?kind=full", content: null, TestContext.Current.CancellationToken); using var fromNotice = await owner.PostAsync( $"/api/schools/{school.Id}/notices/{posted.Id}/generate", content: null, TestContext.Current.CancellationToken); Assert.Equal(card.StatusCode, fromNotice.StatusCode); Assert.Equal(await SchoolApiTests.ProblemCodeAsync(card), await SchoolApiTests.ProblemCodeAsync(fromNotice)); var paused = (await SchoolApiTests.GetSchoolsAsync(owner)).Schools.Single(item => item.Id == school.Id); Assert.False(paused.Running); using var guest = await SchoolApiTests.CreateIsolatedClientAsync(fixture.App, "NoticeImageGuest"); using var forbidden = await guest.PostAsync( $"/api/schools/{school.Id}/notices/{posted.Id}/generate", content: null, TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.Forbidden, forbidden.StatusCode); Assert.Equal("not-owner", await SchoolApiTests.ProblemCodeAsync(forbidden)); var stillPaused = (await SchoolApiTests.GetSchoolsAsync(owner)).Schools.Single(item => item.Id == school.Id); Assert.False(stillPaused.Running); } [Fact] public async Task GenerateWithoutPerson_DoesNotCallSwarm() { using var client = fixture.App.CreateHttpClient("server"); await SchoolApiTests.ResetAsync(client); var school = await SchoolApiTests.CreateAsync(client, "Без человека", Start); var posted = await PostNoticeAsync(client, school.Id, "GenerationFailed"); using var response = await client.PostAsync( $"/api/schools/{school.Id}/notices/{posted.Id}/generate", content: null, TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); var code = await SchoolApiTests.ProblemCodeAsync(response); Assert.Equal("notice-cannot-generate", code); Assert.NotEqual("swarmui-not-configured", code); } [Fact] public async Task NoticePersonPrompt_ContainsThePersonNotAnEmptyCorridor() { using var client = fixture.App.CreateHttpClient("server"); await SchoolApiTests.ResetAsync(client); var school = await SchoolApiTests.CreateAsync(client, "Сцена с человеком", Start); var personId = await FirstPersonIdAsync(client, school.Id); await PostNoticeAsync(client, school.Id, "GenerationFailed", personId, "full"); using var response = await client.GetAsync( $"/api/schools/{school.Id}/people/{Uri.EscapeDataString(personId)}/portrait/prompt?kind=full", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var payload = await response.Content.ReadFromJsonAsync(TestContext.Current.CancellationToken); Assert.NotNull(payload); Assert.Contains("years old", payload!.Positive, StringComparison.OrdinalIgnoreCase); Assert.Contains("wearing", payload.Positive, StringComparison.OrdinalIgnoreCase); Assert.DoesNotMatch(@"\bage \d+", payload.Positive); Assert.DoesNotContain("empty corridor", payload.Positive, StringComparison.OrdinalIgnoreCase); Assert.False(string.IsNullOrWhiteSpace(payload.Negative)); } private static async Task FirstPersonIdAsync(HttpClient client, int schoolId) { var page = await client.GetFromJsonAsync( $"/api/schools/{schoolId}/people?pageSize=1", TestContext.Current.CancellationToken); Assert.NotNull(page); Assert.NotEmpty(page!.People); return page.People[0].Id; } private static async Task PostNoticeAsync( HttpClient client, int schoolId, string defName, string? person = null, string? kind = null) { using var response = await client.PostAsJsonAsync( $"/api/dev/schools/{schoolId}/notices", new { defName, person, kind }, TestContext.Current.CancellationToken); response.EnsureSuccessStatusCode(); var body = await response.Content.ReadFromJsonAsync(TestContext.Current.CancellationToken); Assert.NotNull(body); return body; } private sealed record PeopleListResponse(int Total, IReadOnlyList People); private sealed record PersonListItem(string Id); private sealed record DevNoticeResponse(uint Id, string DefName, bool Pause); private sealed record PortraitPromptPayload(string Kind, string Positive, string Negative); }