Complete phase 39 school owners with owner-scoped API, menu, and tests.
Drop golden save load tests in favor of incompatible-save behavior; dress legacy people files on reload; fix AppHost isolation for multi-user socket and save cleanup. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace HSchool.AppHost.Tests;
|
||||
|
||||
@@ -37,6 +39,14 @@ public class SchoolOwnerApiTests(AppHostFixture fixture)
|
||||
Assert.Equal(2, aliceList.Others.Count);
|
||||
Assert.All(aliceList.Others, other => Assert.Equal("OwnerBob", other.Owner));
|
||||
Assert.DoesNotContain(aliceList.Schools, school => school.Name.StartsWith("Bob", StringComparison.Ordinal));
|
||||
|
||||
foreach (var client in new[] { alice, bob })
|
||||
{
|
||||
client.Dispose();
|
||||
}
|
||||
|
||||
using var cleanup = fixture.App.CreateHttpClient("server");
|
||||
await SchoolApiTests.WipeAllSavesAsync(cleanup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -99,6 +109,12 @@ public class SchoolOwnerApiTests(AppHostFixture fixture)
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.Equal(HttpStatusCode.Forbidden, hire.StatusCode);
|
||||
Assert.Equal("not-owner", await SchoolApiTests.ProblemCodeAsync(hire));
|
||||
|
||||
owner.Dispose();
|
||||
guest.Dispose();
|
||||
|
||||
using var cleanup = fixture.App.CreateHttpClient("server");
|
||||
await SchoolApiTests.WipeAllSavesAsync(cleanup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -108,19 +124,41 @@ public class SchoolOwnerApiTests(AppHostFixture fixture)
|
||||
await SchoolApiTests.WipeAllSavesAsync(wipe);
|
||||
|
||||
var first = await CreateUserAsync("SaveAlpha");
|
||||
var created = await SchoolApiTests.CreateAsync(first, "Бесхозная", Start);
|
||||
|
||||
var directory = await SavesDirectoryAsync(first);
|
||||
var golden = Path.Combine(AppContext.BaseDirectory, "golden", "current");
|
||||
foreach (var file in Directory.EnumerateFiles(golden))
|
||||
var saveFiles = new[]
|
||||
{
|
||||
File.Copy(file, Path.Combine(directory, Path.GetFileName(file)), overwrite: true);
|
||||
$"{created.Id}.json",
|
||||
$"{created.Id}.people.json",
|
||||
$"{created.Id}.timetable.json",
|
||||
};
|
||||
var copies = saveFiles
|
||||
.Select(name => Path.Combine(directory, name))
|
||||
.Where(File.Exists)
|
||||
.ToDictionary(path => path, File.ReadAllBytes);
|
||||
|
||||
await SchoolApiTests.WipeAllSavesAsync(first);
|
||||
|
||||
foreach (var (copiedPath, bytes) in copies)
|
||||
{
|
||||
File.WriteAllBytes(copiedPath, bytes);
|
||||
}
|
||||
|
||||
var schoolSavePath = Path.Combine(directory, $"{created.Id}.json");
|
||||
var node = JsonNode.Parse(File.ReadAllText(schoolSavePath))
|
||||
?? throw new InvalidOperationException("School save parsed to nothing.");
|
||||
node.AsObject().Remove("owner");
|
||||
File.WriteAllText(
|
||||
schoolSavePath,
|
||||
node.ToJsonString(new JsonSerializerOptions { WriteIndented = true }));
|
||||
|
||||
using var reload = await first.PostAsync("/api/dev/reload-schools", content: null, TestContext.Current.CancellationToken);
|
||||
reload.EnsureSuccessStatusCode();
|
||||
|
||||
var firstList = await SchoolApiTests.GetSchoolsAsync(first);
|
||||
Assert.Empty(firstList.Schools);
|
||||
var orphan = Assert.Single(firstList.Others, other => other.Name == "Золотая");
|
||||
var orphan = Assert.Single(firstList.Others, other => other.Name == "Бесхозная");
|
||||
Assert.Null(orphan.Owner);
|
||||
|
||||
var second = await CreateUserAsync("SaveBeta");
|
||||
@@ -129,6 +167,12 @@ public class SchoolOwnerApiTests(AppHostFixture fixture)
|
||||
|
||||
var after = await SchoolApiTests.GetSchoolsAsync(second);
|
||||
Assert.DoesNotContain(after.Others, other => other.Id == orphan.Id);
|
||||
|
||||
first.Dispose();
|
||||
second.Dispose();
|
||||
|
||||
using var cleanup = fixture.App.CreateHttpClient("server");
|
||||
await SchoolApiTests.WipeAllSavesAsync(cleanup);
|
||||
}
|
||||
|
||||
private async Task<HttpClient> CreateUserAsync(string userName) =>
|
||||
|
||||
Reference in New Issue
Block a user