Initial curated itworx-knowledge-hub source from 3b1751d0d9dee551aa6994eee0093704dc334817
This commit is contained in:
commit
ad8ad252a9
825 files changed
+124216
No files matched your search
@@ -0,0 +1,101 @@
|
||||
using System.Diagnostics;
|
||||
using System.Net.Http.Json;
|
||||
using ItWorx.KnowledgeHub.Contracts.Knowledge;
|
||||
using ItWorx.KnowledgeHub.Domain.Knowledge;
|
||||
using ItWorx.KnowledgeHub.Infrastructure.Persistence;
|
||||
using ItWorx.KnowledgeHub.IntegrationTests.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ItWorx.KnowledgeHub.IntegrationTests.Knowledge;
|
||||
|
||||
/// <summary>A 10,000-node synthetic hierarchy remains navigable without loading the
|
||||
/// entire tree into the browser (docs/27-acceptance-matrix.md, M2-A07): the API must
|
||||
/// serve one bounded page of children quickly, regardless of how many siblings exist
|
||||
/// in total.</summary>
|
||||
[Collection(PostgresTestGroup.Name)]
|
||||
public sealed class PageTreeScaleTests(PostgresContainerFixture postgres) : OwnerSetupTestBase(postgres)
|
||||
{
|
||||
private const int ChildCount = 10_000;
|
||||
|
||||
[Fact]
|
||||
public async Task Fetching_one_page_of_children_under_a_10000_child_node_stays_fast_and_bounded()
|
||||
{
|
||||
using var client = Factory.CreateClient();
|
||||
await SetupHelper.LoginAsync(client, OwnerEmail, OwnerPassword);
|
||||
|
||||
var createResponse = await SetupHelper.PostWithCsrfAsync(
|
||||
client, "/api/v1/pages", new CreatePageRequest(null, "Grote categorie", "WikiPage", "Root", null));
|
||||
var parent = await createResponse.Content.ReadFromJsonAsync<PageDetail>();
|
||||
Assert.NotNull(parent);
|
||||
|
||||
await SeedChildrenDirectlyAsync(parent.Id);
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var firstPage = await client.GetFromJsonAsync<PageChildrenResponse>(
|
||||
$"/api/v1/pages/{parent.Id}/children?limit=50");
|
||||
stopwatch.Stop();
|
||||
|
||||
Assert.NotNull(firstPage);
|
||||
Assert.Equal(50, firstPage.Items.Count);
|
||||
Assert.False(string.IsNullOrEmpty(firstPage.NextCursor));
|
||||
|
||||
// Generous bound for a CI/dev machine: the point is "bounded and fast", not a
|
||||
// precise performance benchmark (that belongs to the M8 release scale suite).
|
||||
Assert.True(
|
||||
stopwatch.Elapsed < TimeSpan.FromSeconds(5),
|
||||
$"Fetching one bounded page of children took {stopwatch.Elapsed}, expected it to stay well under 5s regardless of the {ChildCount} total children.");
|
||||
|
||||
var secondPage = await client.GetFromJsonAsync<PageChildrenResponse>(
|
||||
$"/api/v1/pages/{parent.Id}/children?limit=50&cursor={Uri.EscapeDataString(firstPage.NextCursor!)}");
|
||||
Assert.NotNull(secondPage);
|
||||
Assert.Equal(50, secondPage.Items.Count);
|
||||
Assert.Empty(firstPage.Items.Select(item => item.Id).Intersect(secondPage.Items.Select(item => item.Id)));
|
||||
}
|
||||
|
||||
private async Task SeedChildrenDirectlyAsync(Guid parentId)
|
||||
{
|
||||
// Seeded directly through the DbContext rather than 10,000 HTTP calls — this
|
||||
// test is about proving the *read* path stays bounded at scale, not about
|
||||
// exercising page creation (already covered by PageCrudTests).
|
||||
using var scope = Factory.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<KnowledgeHubDbContext>();
|
||||
|
||||
var parent = await db.Pages.FindAsync(parentId);
|
||||
Assert.NotNull(parent);
|
||||
var workspaceId = parent.WorkspaceId;
|
||||
var actorId = parent.CreatedBy ?? Guid.NewGuid();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
var sortKey = SortKey.First();
|
||||
var batch = new List<Page>(1000);
|
||||
|
||||
for (var i = 0; i < ChildCount; i++)
|
||||
{
|
||||
var page = Page.Create(
|
||||
workspaceId,
|
||||
parentId,
|
||||
sortKey,
|
||||
PageTitle.Create($"Kindpagina {i:D5}"),
|
||||
DocumentType.WikiPage,
|
||||
"Inhoud",
|
||||
actorId,
|
||||
now);
|
||||
batch.Add(page);
|
||||
sortKey = SortKey.Next(sortKey);
|
||||
|
||||
if (batch.Count == 1000)
|
||||
{
|
||||
db.Pages.AddRange(batch);
|
||||
await db.SaveChangesAsync();
|
||||
db.ChangeTracker.Clear();
|
||||
batch.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (batch.Count > 0)
|
||||
{
|
||||
db.Pages.AddRange(batch);
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user