too much for one commit
This commit is contained in:
348
tests/EntKube.Clusters.Tests/Features/GiteaComponentTests.cs
Normal file
348
tests/EntKube.Clusters.Tests/Features/GiteaComponentTests.cs
Normal file
@@ -0,0 +1,348 @@
|
||||
using EntKube.Clusters.Features.AdoptCluster;
|
||||
using EntKube.Clusters.Features.AdoptCluster.Components.Gitea;
|
||||
using EntKube.Clusters.Infrastructure.Cleura;
|
||||
using FluentAssertions;
|
||||
using k8s.Models;
|
||||
using Moq;
|
||||
|
||||
namespace EntKube.Clusters.Tests.Features;
|
||||
|
||||
public class GiteaComponentTests
|
||||
{
|
||||
[Fact]
|
||||
public void GiteaInstaller_HasCorrectComponentName()
|
||||
{
|
||||
// The installer's ComponentName must match the check's ComponentName
|
||||
// so the coordinator can pair them correctly.
|
||||
|
||||
GiteaInstaller installer = new(
|
||||
new Microsoft.Extensions.Logging.Abstractions.NullLogger<GiteaInstaller>(),
|
||||
new CleuraS3Client(Mock.Of<IHttpClientFactory>()),
|
||||
Mock.Of<IHttpClientFactory>());
|
||||
|
||||
installer.ComponentName.Should().Be("gitea");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaCheck_HasCorrectComponentName()
|
||||
{
|
||||
// The check's ComponentName identifies which component is being evaluated
|
||||
// during cluster adoption scans.
|
||||
|
||||
GiteaCheck check = new(new Microsoft.Extensions.Logging.Abstractions.NullLogger<GiteaCheck>());
|
||||
|
||||
check.ComponentName.Should().Be("gitea");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaCheck_HasDisplayName()
|
||||
{
|
||||
// The display name is shown in the UI so users can identify the component.
|
||||
|
||||
GiteaCheck check = new(new Microsoft.Extensions.Logging.Abstractions.NullLogger<GiteaCheck>());
|
||||
|
||||
check.DisplayName.Should().NotBeNullOrWhiteSpace();
|
||||
check.DisplayName.Should().Contain("Gitea");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_IsRegistered()
|
||||
{
|
||||
// The configuration schema must be registered so the UI can render
|
||||
// typed configuration forms for the Gitea component.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
schema.ComponentName.Should().Be("gitea");
|
||||
schema.Parameters.Should().NotBeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_ContainsReplicasParameter()
|
||||
{
|
||||
// The replicas parameter controls how many Gitea pods are deployed.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
schema.Parameters.Should().Contain(p => p.Key == "replicas");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_ContainsActionsParameter()
|
||||
{
|
||||
// Gitea Actions (CI/CD) is a key feature that can be toggled.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
schema.Parameters.Should().Contain(p => p.Key == "actionsEnabled");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_ContainsStorageParameter()
|
||||
{
|
||||
// Repository persistence size is configurable for capacity planning.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
schema.Parameters.Should().Contain(p => p.Key == "persistenceSize");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_ContainsSshParameter()
|
||||
{
|
||||
// SSH access can be enabled/disabled depending on security requirements.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
schema.Parameters.Should().Contain(p => p.Key == "sshEnabled");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaInstaller_GetSchema_ReturnsGiteaSchema()
|
||||
{
|
||||
// The installer's default GetSchema() implementation should delegate
|
||||
// to ComponentSchemas and return the gitea schema.
|
||||
|
||||
IComponentInstaller installer = new GiteaInstaller(
|
||||
new Microsoft.Extensions.Logging.Abstractions.NullLogger<GiteaInstaller>(),
|
||||
new CleuraS3Client(Mock.Of<IHttpClientFactory>()),
|
||||
Mock.Of<IHttpClientFactory>());
|
||||
|
||||
ConfigurationSchema schema = installer.GetSchema();
|
||||
|
||||
schema.ComponentName.Should().Be("gitea");
|
||||
schema.Parameters.Should().NotBeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildActRunnerStatefulSet_DefaultReplicas_ReturnsValidStatefulSet()
|
||||
{
|
||||
// Arrange & Act
|
||||
V1StatefulSet sts = GiteaInstaller.BuildActRunnerStatefulSet("gitea", 2, "10Gi");
|
||||
|
||||
// Assert
|
||||
sts.Metadata.Name.Should().Be("act-runner");
|
||||
sts.Metadata.NamespaceProperty.Should().Be("gitea");
|
||||
sts.Spec.Replicas.Should().Be(2);
|
||||
sts.Spec.ServiceName.Should().Be("act-runner");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildActRunnerStatefulSet_UsesCorrectImage()
|
||||
{
|
||||
// Arrange & Act
|
||||
V1StatefulSet sts = GiteaInstaller.BuildActRunnerStatefulSet("gitea", 1, "5Gi");
|
||||
|
||||
// Assert
|
||||
V1Container container = sts.Spec.Template.Spec.Containers[0];
|
||||
container.Image.Should().Be("gitea/act_runner:latest-dind-rootless");
|
||||
container.Name.Should().Be("runner");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildActRunnerStatefulSet_SetsEnvironmentVariables()
|
||||
{
|
||||
// Arrange & Act
|
||||
V1StatefulSet sts = GiteaInstaller.BuildActRunnerStatefulSet("gitea", 1, "5Gi");
|
||||
|
||||
// Assert — runner needs DOCKER_HOST and GITEA_INSTANCE_URL at minimum
|
||||
V1Container container = sts.Spec.Template.Spec.Containers[0];
|
||||
container.Env.Should().Contain(e => e.Name == "DOCKER_HOST");
|
||||
container.Env.Should().Contain(e => e.Name == "GITEA_INSTANCE_URL");
|
||||
container.Env.Should().Contain(e => e.Name == "GITEA_RUNNER_REGISTRATION_TOKEN");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildActRunnerStatefulSet_ConfiguresPvcWithRequestedSize()
|
||||
{
|
||||
// Arrange & Act
|
||||
V1StatefulSet sts = GiteaInstaller.BuildActRunnerStatefulSet("gitea", 3, "20Gi");
|
||||
|
||||
// Assert
|
||||
V1PersistentVolumeClaim pvc = sts.Spec.VolumeClaimTemplates[0];
|
||||
pvc.Metadata.Name.Should().Be("runner-data");
|
||||
pvc.Spec.Resources.Requests["storage"].ToString().Should().Be("20Gi");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildActRunnerStatefulSet_WithHarborUrl_SetsRegistryMirrorEnv()
|
||||
{
|
||||
// Arrange & Act — provide a Harbor registry URL for the runners.
|
||||
V1StatefulSet sts = GiteaInstaller.BuildActRunnerStatefulSet("gitea", 1, "5Gi", "harbor.example.com");
|
||||
|
||||
// Assert — the Docker daemon should be configured to mirror through Harbor.
|
||||
V1Container container = sts.Spec.Template.Spec.Containers[0];
|
||||
container.Env.Should().Contain(e =>
|
||||
e.Name == "DOCKERD_ROOTLESS_FLAGS" &&
|
||||
e.Value == "--registry-mirror=https://harbor.example.com");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildActRunnerStatefulSet_WithoutHarborUrl_NoMirrorEnv()
|
||||
{
|
||||
// Arrange & Act — no Harbor URL, runners pull images directly.
|
||||
V1StatefulSet sts = GiteaInstaller.BuildActRunnerStatefulSet("gitea", 1, "5Gi");
|
||||
|
||||
// Assert — no Docker daemon mirror flag should be present.
|
||||
V1Container container = sts.Spec.Template.Spec.Containers[0];
|
||||
container.Env.Should().NotContain(e => e.Name == "DOCKERD_ROOTLESS_FLAGS");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_ContainsCnpgClusterNameParameter()
|
||||
{
|
||||
// Gitea should reference the shared CNPG cluster for its database.
|
||||
// The cnpgClusterName parameter tells the installer which CNPG cluster
|
||||
// to create the gitea database on, instead of requiring manual dbHost.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
schema.Parameters.Should().Contain(p =>
|
||||
p.Key == "cnpgClusterName" && p.Type == ParameterType.PostgresCluster);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_ContainsCnpgNamespaceParameter()
|
||||
{
|
||||
// The namespace where the CNPG cluster lives — needed to resolve
|
||||
// the service endpoint ({clusterName}-rw.{namespace}.svc).
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
schema.Parameters.Should().Contain(p => p.Key == "cnpgNamespace");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_IngressProviderIsSelect()
|
||||
{
|
||||
// Ingress provider should be a dropdown selector, not a free-text
|
||||
// field, so users pick from the supported providers.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
ConfigurationParameter ingressProvider = schema.Parameters.First(p => p.Key == "ingressProvider");
|
||||
|
||||
ingressProvider.Type.Should().Be(ParameterType.Select);
|
||||
ingressProvider.AllowedValues.Should().Contain("traefik");
|
||||
ingressProvider.AllowedValues.Should().Contain("istio");
|
||||
ingressProvider.AllowedValues.Should().Contain("gatewayapi");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_RedisClusterIsRedisClusterType()
|
||||
{
|
||||
// Redis should be a cluster selector dropdown, not a manual host
|
||||
// textbox. The UI populates it from provisioned Redis clusters.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
schema.Parameters.Should().Contain(p =>
|
||||
p.Key == "redisClusterName" && p.Type == ParameterType.RedisCluster);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_DatabaseFieldsDoNotIncludeManualHostUserPassword()
|
||||
{
|
||||
// With the CNPG cluster selector, manual dbHost/dbUser/dbPassword
|
||||
// fields are no longer needed — credentials are auto-generated
|
||||
// and stored in the secrets vault.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
schema.Parameters.Should().NotContain(p => p.Key == "dbHost");
|
||||
schema.Parameters.Should().NotContain(p => p.Key == "dbUser");
|
||||
schema.Parameters.Should().NotContain(p => p.Key == "dbPassword");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_ContainsOidcParameters()
|
||||
{
|
||||
// OIDC integration allows Gitea to authenticate users via an external
|
||||
// identity provider like Keycloak.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
schema.Parameters.Should().Contain(p => p.Key == "oidcEnabled" && p.Type == ParameterType.Boolean);
|
||||
schema.Parameters.Should().Contain(p => p.Key == "oidcDiscoveryUrl");
|
||||
schema.Parameters.Should().Contain(p => p.Key == "oidcClientId");
|
||||
schema.Parameters.Should().Contain(p => p.Key == "oidcClientSecret");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_OidcFieldsDependOnOidcEnabled()
|
||||
{
|
||||
// OIDC-specific fields should only be visible when oidcEnabled is true.
|
||||
// This keeps the UI clean for installations without OIDC.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
ConfigurationParameter discoveryUrl = schema.Parameters.First(p => p.Key == "oidcDiscoveryUrl");
|
||||
|
||||
discoveryUrl.DependsOnKey.Should().Be("oidcEnabled");
|
||||
discoveryUrl.DependsOnValues.Should().Contain("true");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_ObjectStorageCascading()
|
||||
{
|
||||
// Object storage fields should cascade based on the objectStorageType
|
||||
// selection — selecting "bucket" shows the bucket selector, "s3" shows
|
||||
// manual S3 fields, "azure" shows Azure fields, "none" hides everything.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
ConfigurationParameter storageType = schema.Parameters.First(p => p.Key == "objectStorageType");
|
||||
storageType.Type.Should().Be(ParameterType.Select);
|
||||
storageType.AllowedValues.Should().Contain("none");
|
||||
storageType.AllowedValues.Should().Contain("bucket");
|
||||
storageType.AllowedValues.Should().Contain("s3");
|
||||
storageType.AllowedValues.Should().Contain("azure");
|
||||
|
||||
ConfigurationParameter bucket = schema.Parameters.First(p => p.Key == "storageBucketId");
|
||||
bucket.DependsOnKey.Should().Be("objectStorageType");
|
||||
bucket.DependsOnValues.Should().Contain("bucket");
|
||||
|
||||
ConfigurationParameter s3Endpoint = schema.Parameters.First(p => p.Key == "s3Endpoint");
|
||||
s3Endpoint.DependsOnKey.Should().Be("objectStorageType");
|
||||
s3Endpoint.DependsOnValues.Should().Contain("s3");
|
||||
|
||||
ConfigurationParameter azureName = schema.Parameters.First(p => p.Key == "azureAccountName");
|
||||
azureName.DependsOnKey.Should().Be("objectStorageType");
|
||||
azureName.DependsOnValues.Should().Contain("azure");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_ContainsVersionParameter()
|
||||
{
|
||||
// Users should be able to select which version of Gitea to install
|
||||
// or upgrade to.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
schema.Parameters.Should().Contain(p => p.Key == "version");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_ContainsProjectsParameter()
|
||||
{
|
||||
// Projects (kanban boards) should be configurable per installation.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
schema.Parameters.Should().Contain(p =>
|
||||
p.Key == "projectsEnabled" && p.Type == ParameterType.Boolean);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GiteaSchema_SshPortDependsOnSshEnabled()
|
||||
{
|
||||
// SSH port should only be visible when SSH is enabled.
|
||||
|
||||
ConfigurationSchema schema = ComponentSchemas.GetSchema("gitea");
|
||||
|
||||
ConfigurationParameter sshPort = schema.Parameters.First(p => p.Key == "sshPort");
|
||||
|
||||
sshPort.DependsOnKey.Should().Be("sshEnabled");
|
||||
sshPort.DependsOnValues.Should().Contain("true");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user