From 6065f0c91ec5adeaf3f36ea4a13ffb849cb4996b Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 28 Aug 2026 15:35:43 +0000 Subject: [PATCH] feat(api): DI-register 5 nodes + NATS provider; enable pending integration tests --- src/VolcanicCore.Api/Program.cs | 5 +++++ .../ServiceCollectionExtensions.cs | 17 +++++++++++++++++ .../ConnectionsEndpointsTests.cs | 18 ++++++++++++++++++ .../DiscoveryEndpointsTests.cs | 12 ++++++++---- .../ExecutionsEndpointsTests.cs | 2 +- tests/VolcanicCore.Tests/TriggerHostTests.cs | 2 +- 6 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 src/VolcanicCore.Nodes/ServiceCollectionExtensions.cs diff --git a/src/VolcanicCore.Api/Program.cs b/src/VolcanicCore.Api/Program.cs index d6283da..ce5c3c8 100644 --- a/src/VolcanicCore.Api/Program.cs +++ b/src/VolcanicCore.Api/Program.cs @@ -7,8 +7,10 @@ using VolcanicCore.Api.Registries; using VolcanicCore.Core; using VolcanicCore.Persistence; using VolcanicCore.Persistence.Encryption; +using VolcanicCore.Nodes; using VolcanicCore.Persistence.Migrations; using VolcanicCore.Persistence.Repositories; +using VolcanicCore.Providers; var builder = WebApplication.CreateBuilder(args); @@ -120,6 +122,9 @@ builder.Services.AddSingleton(sp => builder.Services.AddSingleton(); builder.Services.AddSingleton(); +builder.Services.AddVolcanicProviders(); +builder.Services.AddVolcanicNodes(); + builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(sp => sp.GetRequiredService()); diff --git a/src/VolcanicCore.Nodes/ServiceCollectionExtensions.cs b/src/VolcanicCore.Nodes/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..d3a3bed --- /dev/null +++ b/src/VolcanicCore.Nodes/ServiceCollectionExtensions.cs @@ -0,0 +1,17 @@ +using Microsoft.Extensions.DependencyInjection; +using VolcanicCore.Core; + +namespace VolcanicCore.Nodes; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddVolcanicNodes(this IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + return services; + } +} diff --git a/tests/VolcanicCore.Tests/ConnectionsEndpointsTests.cs b/tests/VolcanicCore.Tests/ConnectionsEndpointsTests.cs index 183931b..3f6b082 100644 --- a/tests/VolcanicCore.Tests/ConnectionsEndpointsTests.cs +++ b/tests/VolcanicCore.Tests/ConnectionsEndpointsTests.cs @@ -72,5 +72,23 @@ public class ConnectionsEndpointsTests : IClassFixture Assert.Equal(HttpStatusCode.Conflict, second.StatusCode); } + [Fact] + public async Task Nats_connection_response_never_returns_pass_field() + { + var c = await LoggedIn(); + var create = await c.PostAsJsonAsync("/api/connections", new + { + providerId = "nats", + name = "nats-secret-test", + config = new { url = "nats://x", user = "u", pass = "shhh" } + }); + Assert.Equal(HttpStatusCode.Created, create.StatusCode); + var created = await create.Content.ReadFromJsonAsync(); + var id = created.GetProperty("id").GetString()!; + + var get = await c.GetFromJsonAsync($"/api/connections/{id}"); + Assert.DoesNotContain(get.GetProperty("config").EnumerateObject(), p => p.Name == "pass"); + } + private sealed record ConnectionDto(string Id, string ProviderId, string Name, JsonElement Config); } diff --git a/tests/VolcanicCore.Tests/DiscoveryEndpointsTests.cs b/tests/VolcanicCore.Tests/DiscoveryEndpointsTests.cs index be57507..d619872 100644 --- a/tests/VolcanicCore.Tests/DiscoveryEndpointsTests.cs +++ b/tests/VolcanicCore.Tests/DiscoveryEndpointsTests.cs @@ -24,21 +24,25 @@ public class DiscoveryEndpointsTests : IClassFixture } [Fact] - public async Task Node_types_returns_registered_types_empty_in_plan_1() + public async Task Node_types_returns_five_registered_types() { var c = await LoggedIn(); var res = await c.GetFromJsonAsync>("/api/node-types"); Assert.NotNull(res); - Assert.Empty(res!); // Plan 2 adds the 5 nodes. + var ids = res!.Select(n => n.Id).ToHashSet(); + Assert.Subset(new HashSet + { + "nats.hook", "nats.publish", "http.webhook", "http.response", "python.transform", + }, ids); } [Fact] - public async Task Connection_providers_returns_registered_providers_empty_in_plan_1() + public async Task Connection_providers_returns_nats() { var c = await LoggedIn(); var res = await c.GetFromJsonAsync>("/api/connection-providers"); Assert.NotNull(res); - Assert.Empty(res!); + Assert.Contains(res!, p => p.Id == "nats"); } private sealed record NodeTypeDto(string Id, string DisplayName, string Category, diff --git a/tests/VolcanicCore.Tests/ExecutionsEndpointsTests.cs b/tests/VolcanicCore.Tests/ExecutionsEndpointsTests.cs index 1d0f4c4..309d00a 100644 --- a/tests/VolcanicCore.Tests/ExecutionsEndpointsTests.cs +++ b/tests/VolcanicCore.Tests/ExecutionsEndpointsTests.cs @@ -16,7 +16,7 @@ public class ExecutionsEndpointsTests : IClassFixture return c; } - [Fact(Skip = "Enabled after Tasks 22-23 land WebhookNode and WebResponseNode, and Task 24 DI-registers them")] + [Fact] public async Task Manual_run_of_workflow_with_single_webhook_trigger_produces_completed_execution() { var c = await LoggedIn(); diff --git a/tests/VolcanicCore.Tests/TriggerHostTests.cs b/tests/VolcanicCore.Tests/TriggerHostTests.cs index b3ce60b..a2ae127 100644 --- a/tests/VolcanicCore.Tests/TriggerHostTests.cs +++ b/tests/VolcanicCore.Tests/TriggerHostTests.cs @@ -18,7 +18,7 @@ public class TriggerHostTests : IClassFixture return c; } - [Fact(Skip = "Enabled after Task 24 DI-registers WebhookNode")] + [Fact] public async Task Activating_a_workflow_registers_its_webhook_and_deactivating_unregisters_it() { var c = await LoggedIn();