Publish curated Knowledge Hub source from 2ed833f290b439a7bc91e5fd19b042c269e3bee9

This commit is contained in:
Public Source Publisher committed 2026-10-03 17:07:21 +00:00
1 parent 10f2edcd29
commit 59f15b2d08
218 files changed
+23995 -1849

No files matched your search

@@ -0,0 +1,147 @@
using System.Net;
using System.Text.Json;
using ItWorx.KnowledgeHub.IntegrationTests.Infrastructure;
namespace ItWorx.KnowledgeHub.IntegrationTests.Platform;
[Collection(PostgresTestGroup.Name)]
public sealed class UserPreferencesApiTests(PostgresContainerFixture postgres) : OwnerSetupTestBase(postgres)
{
private sealed record PreferencesPayload(
string Theme,
string Density,
bool PrimaryNavigationCollapsed,
bool ContextPanelOpen,
string[] NavigationOrder,
string[] DashboardWidgetOrder,
string[] HiddenDashboardWidgets,
string DefaultLandingPage,
string CatalogView,
int ContextPanelWidth,
int NavigationWidth);
private static PreferencesPayload DefaultPreferences(string theme = "system") => new(
theme,
"comfortable",
false,
false,
["/", "/infrastructure", "/infrastructure/services", "/projects", "/runbooks", "/knowledge", "/activity", "/search"],
["attention", "server", "projects", "activity", "runbooks", "favorites", "quick-actions"],
[],
"/",
"list",
304,
224);
private async Task<HttpClient> AuthenticatedClientAsync()
{
var client = Factory.CreateClient();
await SetupHelper.LoginAsync(client, OwnerEmail, OwnerPassword);
return client;
}
[Fact]
public async Task Missing_preferences_return_the_shared_defaults_without_persisting_a_row()
{
using var client = await AuthenticatedClientAsync();
using var first = await client.GetAsync("/api/v1/me/preferences");
using var firstJson = JsonDocument.Parse(await first.Content.ReadAsStringAsync());
using var second = await client.GetAsync("/api/v1/me/preferences");
using var secondJson = JsonDocument.Parse(await second.Content.ReadAsStringAsync());
Assert.Equal(HttpStatusCode.OK, first.StatusCode);
Assert.Equal("\"0\"", first.Headers.ETag?.Tag);
Assert.Equal("0", firstJson.RootElement.GetProperty("eTag").GetString());
Assert.True(firstJson.RootElement.GetProperty("isDefault").GetBoolean());
Assert.Equal(1, firstJson.RootElement.GetProperty("schemaVersion").GetInt32());
Assert.Equal("system", firstJson.RootElement.GetProperty("theme").GetString());
Assert.Equal("comfortable", firstJson.RootElement.GetProperty("density").GetString());
Assert.Equal(304, firstJson.RootElement.GetProperty("contextPanelWidth").GetInt32());
Assert.Equal(224, firstJson.RootElement.GetProperty("navigationWidth").GetInt32());
Assert.Equal("0", secondJson.RootElement.GetProperty("eTag").GetString());
Assert.True(secondJson.RootElement.GetProperty("isDefault").GetBoolean());
}
[Fact]
public async Task Full_replacement_with_the_current_etag_persists_for_the_signed_in_user()
{
using var client = await AuthenticatedClientAsync();
var request = new PreferencesPayload(
"dark", "compact", true, true,
["/projects", "/", "/knowledge"], ["projects", "attention", "server"], ["server"],
"/projects", "grid", 420, 248);
using var updated = await SetupHelper.PutWithCsrfAsync(client, "/api/v1/me/preferences", request, "0");
using var updatedJson = JsonDocument.Parse(await updated.Content.ReadAsStringAsync());
using var fetched = await client.GetAsync("/api/v1/me/preferences");
using var fetchedJson = JsonDocument.Parse(await fetched.Content.ReadAsStringAsync());
Assert.Equal(HttpStatusCode.OK, updated.StatusCode);
Assert.Equal("\"1\"", updated.Headers.ETag?.Tag);
Assert.Equal("1", updatedJson.RootElement.GetProperty("eTag").GetString());
Assert.False(updatedJson.RootElement.GetProperty("isDefault").GetBoolean());
Assert.Equal("dark", fetchedJson.RootElement.GetProperty("theme").GetString());
Assert.Equal("/projects", fetchedJson.RootElement.GetProperty("defaultLandingPage").GetString());
Assert.Equal(420, fetchedJson.RootElement.GetProperty("contextPanelWidth").GetInt32());
Assert.Equal("1", fetchedJson.RootElement.GetProperty("eTag").GetString());
}
[Fact]
public async Task A_missing_if_match_is_rejected_before_updating_preferences()
{
using var client = await AuthenticatedClientAsync();
var request = DefaultPreferences("light");
using var response = await SetupHelper.PutWithCsrfAsync(client, "/api/v1/me/preferences", request);
Assert.Equal((HttpStatusCode)428, response.StatusCode);
}
[Fact]
public async Task A_stale_if_match_is_rejected_without_overwriting_a_newer_preference_version()
{
using var client = await AuthenticatedClientAsync();
var request = DefaultPreferences("dark");
using var first = await SetupHelper.PutWithCsrfAsync(client, "/api/v1/me/preferences", request, "0");
using var stale = await SetupHelper.PutWithCsrfAsync(client, "/api/v1/me/preferences", request with { Theme = "light" }, "0");
using var fetched = await client.GetAsync("/api/v1/me/preferences");
using var fetchedJson = JsonDocument.Parse(await fetched.Content.ReadAsStringAsync());
Assert.Equal(HttpStatusCode.OK, first.StatusCode);
Assert.Equal(HttpStatusCode.PreconditionFailed, stale.StatusCode);
Assert.Equal("dark", fetchedJson.RootElement.GetProperty("theme").GetString());
}
[Fact]
public async Task Preferences_reject_unknown_navigation_and_widget_ids()
{
using var client = await AuthenticatedClientAsync();
var request = DefaultPreferences() with
{
NavigationOrder = ["/admin/users/delete"],
DashboardWidgetOrder = ["unexpected-widget"],
DefaultLandingPage = "/admin/users/delete"
};
using var response = await SetupHelper.PutWithCsrfAsync(client, "/api/v1/me/preferences", request, "0");
Assert.Equal(HttpStatusCode.UnprocessableEntity, response.StatusCode);
}
[Fact]
public async Task Concurrent_first_writes_with_the_default_etag_have_one_winner()
{
using var firstClient = await AuthenticatedClientAsync();
using var secondClient = await AuthenticatedClientAsync();
var firstWrite = SetupHelper.PutWithCsrfAsync(firstClient, "/api/v1/me/preferences", DefaultPreferences("dark"), "0");
var secondWrite = SetupHelper.PutWithCsrfAsync(secondClient, "/api/v1/me/preferences", DefaultPreferences("light"), "0");
using var firstResponse = await firstWrite;
using var secondResponse = await secondWrite;
Assert.Equal(1, new[] { firstResponse.StatusCode, secondResponse.StatusCode }.Count(status => status == HttpStatusCode.OK));
Assert.Equal(1, new[] { firstResponse.StatusCode, secondResponse.StatusCode }.Count(status => status == HttpStatusCode.PreconditionFailed));
}
}