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:
@@ -527,6 +527,25 @@ public class SchoolApiTests(AppHostFixture fixture)
|
||||
_ = await LoginAndGetCookieAsync(client, userName);
|
||||
}
|
||||
|
||||
internal static async Task<HttpClient> CreateIsolatedClientAsync(HttpClient template, string userName)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(template.BaseAddress);
|
||||
|
||||
var login = new HttpClient { BaseAddress = template.BaseAddress };
|
||||
try
|
||||
{
|
||||
var cookie = await LoginAndGetCookieAsync(login, userName);
|
||||
var handler = new HttpClientHandler { UseCookies = false };
|
||||
var client = new HttpClient(handler) { BaseAddress = template.BaseAddress };
|
||||
client.DefaultRequestHeaders.Add("Cookie", cookie);
|
||||
return client;
|
||||
}
|
||||
finally
|
||||
{
|
||||
login.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
internal static async Task<HttpClient> CreateIsolatedClientAsync(DistributedApplication app, string userName)
|
||||
{
|
||||
var login = app.CreateHttpClient("server");
|
||||
@@ -542,6 +561,29 @@ public class SchoolApiTests(AppHostFixture fixture)
|
||||
return client;
|
||||
}
|
||||
|
||||
internal static async Task<string> WebSocketCookieAsync(HttpClient client, string userName = TestUserName)
|
||||
{
|
||||
if (client.DefaultRequestHeaders.TryGetValues("Cookie", out var values))
|
||||
{
|
||||
var cookie = values.First();
|
||||
if (!string.IsNullOrWhiteSpace(cookie))
|
||||
{
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
|
||||
ArgumentNullException.ThrowIfNull(client.BaseAddress);
|
||||
var login = new HttpClient { BaseAddress = client.BaseAddress };
|
||||
try
|
||||
{
|
||||
return await LoginAndGetCookieAsync(login, userName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
login.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
internal static async Task<string> LoginAndGetCookieAsync(HttpClient client, string userName = TestUserName)
|
||||
{
|
||||
using var first = await client.PostAsJsonAsync(
|
||||
@@ -599,12 +641,12 @@ public class SchoolApiTests(AppHostFixture fixture)
|
||||
{
|
||||
await LoginAsync(client);
|
||||
|
||||
for (var pass = 0; pass < 4; pass++)
|
||||
for (var pass = 0; pass < 8; pass++)
|
||||
{
|
||||
var state = await GetSchoolsAsync(client);
|
||||
if (state.Schools.Count == 0 && state.Others.Count == 0)
|
||||
{
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var school in state.Schools)
|
||||
@@ -615,29 +657,37 @@ public class SchoolApiTests(AppHostFixture fixture)
|
||||
|
||||
foreach (var other in state.Others)
|
||||
{
|
||||
using var response = await client.DeleteAsync($"/api/schools/{other.Id}", TestContext.Current.CancellationToken);
|
||||
if (response.StatusCode == HttpStatusCode.Forbidden)
|
||||
HttpClient? ownedClient = null;
|
||||
var deleter = client;
|
||||
if (!string.IsNullOrWhiteSpace(other.Owner))
|
||||
{
|
||||
continue;
|
||||
ownedClient = await CreateIsolatedClientAsync(client, other.Owner);
|
||||
deleter = ownedClient;
|
||||
}
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
try
|
||||
{
|
||||
using var response = await deleter.DeleteAsync($"/api/schools/{other.Id}", TestContext.Current.CancellationToken);
|
||||
if (response.StatusCode == HttpStatusCode.Forbidden)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ownedClient?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var directory = await SavesDirectoryAsync(client);
|
||||
foreach (var path in Directory.EnumerateFiles(directory))
|
||||
var left = await GetSchoolsAsync(client);
|
||||
if (left.Schools.Count > 0 || left.Others.Count > 0)
|
||||
{
|
||||
File.Delete(path);
|
||||
throw new InvalidOperationException(
|
||||
$"Could not wipe saves: {left.Schools.Count} own and {left.Others.Count} other schools remain.");
|
||||
}
|
||||
|
||||
foreach (var path in Directory.EnumerateDirectories(directory))
|
||||
{
|
||||
Directory.Delete(path, recursive: true);
|
||||
}
|
||||
|
||||
using var reload = await client.PostAsync("/api/dev/reload-schools", content: null, TestContext.Current.CancellationToken);
|
||||
reload.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
internal static async Task<SchoolsResponse> GetSchoolsAsync(HttpClient client)
|
||||
|
||||
Reference in New Issue
Block a user