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

@@ -2,10 +2,12 @@ using System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using ItWorx.KnowledgeHub.Application.Infrastructure;
using ItWorx.KnowledgeHub.Contracts.Admin;
using ItWorx.KnowledgeHub.Contracts.Automation;
using ItWorx.KnowledgeHub.Contracts.Infrastructure;
using ItWorx.KnowledgeHub.Domain.Automation;
using ItWorx.KnowledgeHub.Domain.Sources;
using ItWorx.KnowledgeHub.Infrastructure.Persistence;
using ItWorx.KnowledgeHub.IntegrationTests.Infrastructure;
using Microsoft.EntityFrameworkCore;
@@ -16,6 +18,76 @@ namespace ItWorx.KnowledgeHub.IntegrationTests.InfrastructureKnowledge;
[Collection(PostgresTestGroup.Name)]
public sealed class InfrastructureSynchronizationTests(PostgresContainerFixture postgres) : OwnerSetupTestBase(postgres)
{
[Fact]
public async Task Older_or_future_capture_cannot_replace_current_inventory_or_make_it_fresh()
{
using var client = await AuthenticatedClientAsync();
var currentCapture = DateTimeOffset.UtcNow.AddHours(-48);
using var current = await SetupHelper.PostWithCsrfAsync(client,
"/api/v1/infrastructure/inventory/snapshots",
Snapshot("monotonic-current", true, "running") with { CapturedAt = currentCapture });
Assert.Equal(HttpStatusCode.OK, current.StatusCode);
using var sourceResponse = await client.GetAsync("/api/v1/admin/data-sources?limit=100");
using var sources = JsonDocument.Parse(await sourceResponse.Content.ReadAsStringAsync());
var source = sources.RootElement.GetProperty("items").EnumerateArray()
.Single(item => item.GetProperty("sourceKey").GetString() == "inventory:default");
Assert.Equal("Stale", source.GetProperty("state").GetString());
using var older = await SetupHelper.PostWithCsrfAsync(client,
"/api/v1/infrastructure/inventory/snapshots",
Snapshot("monotonic-older", false, "stopped") with { CapturedAt = currentCapture.AddHours(-1) });
Assert.Equal(HttpStatusCode.UnprocessableEntity, older.StatusCode);
using var future = await SetupHelper.PostWithCsrfAsync(client,
"/api/v1/infrastructure/inventory/snapshots",
Snapshot("monotonic-future", false, "stopped") with { CapturedAt = DateTimeOffset.UtcNow.AddHours(1) });
Assert.Equal(HttpStatusCode.UnprocessableEntity, future.StatusCode);
var services = await client.GetFromJsonAsync<InfrastructureServiceListResponse>(
"/api/v1/infrastructure/services?includeHidden=true");
Assert.Equal("running", Assert.Single(services!.Items).RuntimeStatus);
using var replay = await SetupHelper.PostWithCsrfAsync(client,
"/api/v1/infrastructure/inventory/snapshots",
Snapshot("monotonic-current", true, "running") with { CapturedAt = currentCapture });
Assert.Equal(HttpStatusCode.OK, replay.StatusCode);
Assert.True((await replay.Content.ReadFromJsonAsync<InventorySyncResponse>())!.AlreadyImported);
}
[Fact]
public async Task Disabling_inventory_source_prevents_further_ingestion()
{
using var client = await AuthenticatedClientAsync();
using var first = await SetupHelper.PostWithCsrfAsync(client,
"/api/v1/infrastructure/inventory/snapshots", Snapshot("disabled-before", true, "running"));
Assert.Equal(HttpStatusCode.OK, first.StatusCode);
using var response = await client.GetAsync("/api/v1/admin/data-sources?limit=100");
using var document = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
var source = document.RootElement.GetProperty("items").EnumerateArray()
.Single(item => item.GetProperty("sourceKey").GetString() == "inventory:default");
using var scope = Factory.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<KnowledgeHubDbContext>();
var registered = await db.Set<DataSource>().SingleAsync();
Assert.True(registered.Enabled);
using var disabled = await SetupHelper.PutWithCsrfAsync(client,
$"/api/v1/admin/data-sources/{source.GetProperty("id").GetGuid()}",
new { displayName = "Infrastructuurinventaris", enabled = false, expectedIntervalHours = 24 },
source.GetProperty("eTag").GetString());
Assert.Equal(HttpStatusCode.OK, disabled.StatusCode);
using var rejected = await SetupHelper.PostWithCsrfAsync(client,
"/api/v1/infrastructure/inventory/snapshots", Snapshot("disabled-after", false, "stopped"));
Assert.Equal(HttpStatusCode.UnprocessableEntity, rejected.StatusCode);
var services = await client.GetFromJsonAsync<InfrastructureServiceListResponse>(
"/api/v1/infrastructure/services?includeHidden=true");
Assert.Single(services!.Items);
// The transaction boundary must independently reject a disable that won
// after the application-level check, even with an already tracked source.
Assert.True(registered.Enabled); // stale identity-map instance from before disable
var snapshotsBefore = await db.InventorySnapshots.CountAsync();
var repository = scope.ServiceProvider.GetRequiredService<IInfrastructureRepository>();
await Assert.ThrowsAsync<InactiveInventorySourceException>(() => repository.ApplySnapshotAsync(
registered.WorkspaceId, new InventorySnapshotInput("late-import", "late-hash", DateTimeOffset.UtcNow, [], []),
DateTimeOffset.UtcNow, CancellationToken.None));
Assert.Equal(snapshotsBefore, await db.InventorySnapshots.CountAsync());
}
[Fact]
public async Task Inventory_facts_are_typed_and_editorial_knowledge_survives_later_snapshots()
{