using EntKube.Clusters.Domain; using EntKube.Clusters.Features.AdoptCluster; using EntKube.Clusters.Features.AdoptCluster.Components.Ingress; using FluentAssertions; namespace EntKube.Clusters.Tests.Features; /// /// Tests for IngressCheck.DetectProvider — the static method that determines /// which ingress provider is installed on a cluster by examining its component /// list. This drives the auto-detection behavior so users never have to /// manually select "istio" or "traefik" when configuring ingress. /// public class IngressCheckTests { [Fact] public void DetectProvider_IstioInstalled_ReturnsIstio() { // When the cluster has an Istio component marked as Installed, // the detector should pick Istio as the provider. KubernetesCluster cluster = CreateClusterWithComponent("istio", ComponentStatus.Installed); string? provider = IngressCheck.DetectProvider(cluster); provider.Should().Be("istio"); } [Fact] public void DetectProvider_TraefikInstalled_ReturnsTraefik() { // When the cluster has a Traefik component marked as Installed, // the detector should pick Traefik as the provider. KubernetesCluster cluster = CreateClusterWithComponent("traefik", ComponentStatus.Installed); string? provider = IngressCheck.DetectProvider(cluster); provider.Should().Be("traefik"); } [Fact] public void DetectProvider_IstioDegraded_StillReturnsIstio() { // Even if Istio is degraded (partially working), we should still // detect it as the provider — the gateway infra can still be deployed. KubernetesCluster cluster = CreateClusterWithComponent("istio", ComponentStatus.Degraded); string? provider = IngressCheck.DetectProvider(cluster); provider.Should().Be("istio"); } [Fact] public void DetectProvider_NeitherInstalled_ReturnsNull() { // When no ingress controller is installed, the detector returns null // so the installer can report "install Istio or Traefik first." KubernetesCluster cluster = CreateClusterWithComponent("kyverno", ComponentStatus.Installed); string? provider = IngressCheck.DetectProvider(cluster); provider.Should().BeNull(); } [Fact] public void DetectProvider_BothInstalled_PrefersIstio() { // If both Istio and Traefik are installed (unusual but possible), // Istio takes priority because it requires dedicated gateway infrastructure. KubernetesCluster cluster = CreateClusterWithComponents( ("istio", ComponentStatus.Installed), ("traefik", ComponentStatus.Installed)); string? provider = IngressCheck.DetectProvider(cluster); provider.Should().Be("istio"); } // ─── Gateway resolution from ingress component ─────────────────────── [Fact] public void IngressComponent_WithIstioGateways_ExposesGatewayInfo() { // When the ingress component is installed with Istio and has discovered // internal and external gateways, the component's configuration should // contain the gateway details that services can use to auto-resolve. KubernetesCluster cluster = CreateClusterWithIngressConfig( provider: "istio", hasInternalGateway: true, hasExternalGateway: true); ClusterComponent? ingress = cluster.Components.FirstOrDefault( c => c.ComponentName == "ingress"); ingress.Should().NotBeNull(); ingress!.Configuration["provider"].Should().Be("istio"); ingress.Configuration["hasInternalGateway"].Should().Be("True"); ingress.Configuration["hasExternalGateway"].Should().Be("True"); } [Fact] public void IngressComponent_WithTraefik_NoGatewayRefs() { // Traefik manages its own ingress — no Gateway API gateway refs needed. // The component config should show traefik as provider. KubernetesCluster cluster = CreateClusterWithIngressConfig( provider: "traefik", hasInternalGateway: false, hasExternalGateway: false); ClusterComponent? ingress = cluster.Components.FirstOrDefault( c => c.ComponentName == "ingress"); ingress.Should().NotBeNull(); ingress!.Configuration["provider"].Should().Be("traefik"); ingress.Configuration.ContainsKey("hasInternalGateway").Should().BeFalse(); } // ─── Helpers ───────────────────────────────────────────────────────── private static KubernetesCluster CreateClusterWithComponent(string componentName, ComponentStatus status) { return CreateClusterWithComponents((componentName, status)); } private static KubernetesCluster CreateClusterWithComponents(params (string Name, ComponentStatus Status)[] componentDefs) { KubernetesCluster cluster = KubernetesCluster.Register( "test-cluster", "https://k8s.example.com", "fake-kubeconfig", Guid.NewGuid(), "test-context", Guid.NewGuid()); List results = componentDefs .Select(c => new ComponentCheckResult( c.Name, c.Status, Details: new List(), MissingItems: new List())) .ToList(); cluster.UpdateComponents(results); return cluster; } /// /// Creates a cluster with an ingress component that has discovered /// configuration values — provider, gateway presence flags. This mimics /// what the real IngressCheck discovers during an adoption scan. /// private static KubernetesCluster CreateClusterWithIngressConfig( string provider, bool hasInternalGateway, bool hasExternalGateway) { KubernetesCluster cluster = KubernetesCluster.Register( "test-cluster", "https://k8s.example.com", "fake-kubeconfig", Guid.NewGuid(), "test-context", Guid.NewGuid()); Dictionary configValues = new() { ["provider"] = provider }; if (hasInternalGateway) { configValues["hasInternalGateway"] = "True"; } if (hasExternalGateway) { configValues["hasExternalGateway"] = "True"; } List results = new() { new ComponentCheckResult( "ingress", ComponentStatus.Installed, Details: new List(), MissingItems: new List(), Configuration: new DiscoveredConfiguration( Version: null, Namespace: "internal-ingress", HelmReleaseName: null, Values: configValues)) }; cluster.UpdateComponents(results); return cluster; } }