using EntKube.Web.Services; using FluentAssertions; namespace EntKube.Web.Tests; /// /// Tests for the YamlFormMerger utility that takes form field values /// (key-value pairs with dot-notation paths) and merges them into a /// YAML string. This is how form-based configuration gets applied on /// top of the raw YAML that users can also edit directly. /// public class YamlFormMergerTests { // ──────── Simple top-level paths ──────── [Fact] public void MergeFormValues_WithSimplePath_SetsValue() { // A form field targeting "rootUser" should set the top-level key. string baseYaml = """ rootUser: admin rootPassword: changeme """; Dictionary formValues = new() { ["rootUser"] = "minio-admin" }; string result = YamlFormMerger.MergeFormValues(baseYaml, formValues); result.Should().Contain("rootUser: minio-admin"); } [Fact] public void MergeFormValues_WithNestedPath_SetsNestedValue() { // A dot-notation path like "grafana.adminPassword" should set the // nested YAML property grafana → adminPassword. string baseYaml = """ grafana: enabled: true adminPassword: admin """; Dictionary formValues = new() { ["grafana.adminPassword"] = "s3cret!" }; string result = YamlFormMerger.MergeFormValues(baseYaml, formValues); result.Should().Contain("adminPassword: s3cret!"); } [Fact] public void MergeFormValues_WithDeeplyNestedPath_SetsValue() { // Paths can be arbitrarily deep, like "prometheus.prometheusSpec.retention". string baseYaml = """ prometheus: prometheusSpec: retention: 15d resources: requests: memory: 512Mi """; Dictionary formValues = new() { ["prometheus.prometheusSpec.retention"] = "30d" }; string result = YamlFormMerger.MergeFormValues(baseYaml, formValues); result.Should().Contain("retention: 30d"); result.Should().NotContain("retention: 15d"); } [Fact] public void MergeFormValues_WithEmptyBaseYaml_CreatesStructure() { // When the base YAML is empty, the merger should create the nested // structure from scratch based on the dot-notation path. string baseYaml = ""; Dictionary formValues = new() { ["service.type"] = "LoadBalancer" }; string result = YamlFormMerger.MergeFormValues(baseYaml, formValues); result.Should().Contain("service:"); result.Should().Contain("type: LoadBalancer"); } [Fact] public void MergeFormValues_WithMultipleValues_SetsAll() { // Multiple form fields should all be applied. string baseYaml = """ rootUser: admin rootPassword: changeme persistence: size: 50Gi """; Dictionary formValues = new() { ["rootUser"] = "operator", ["rootPassword"] = "strong-pass", ["persistence.size"] = "100Gi" }; string result = YamlFormMerger.MergeFormValues(baseYaml, formValues); result.Should().Contain("rootUser: operator"); result.Should().Contain("rootPassword: strong-pass"); result.Should().Contain("size: 100Gi"); } [Fact] public void MergeFormValues_WithNewPath_AddsToExistingStructure() { // If the path doesn't exist in the base YAML but parent nodes do, // the merger should add the missing leaf without destroying siblings. string baseYaml = """ grafana: enabled: true """; Dictionary formValues = new() { ["grafana.adminPassword"] = "secret" }; string result = YamlFormMerger.MergeFormValues(baseYaml, formValues); result.Should().Contain("enabled: true"); result.Should().Contain("adminPassword: secret"); } [Fact] public void MergeFormValues_WithBooleanValue_WritesUnquoted() { // Boolean-like values (true/false) should remain unquoted in YAML. string baseYaml = """ alertmanager: enabled: true """; Dictionary formValues = new() { ["alertmanager.enabled"] = "false" }; string result = YamlFormMerger.MergeFormValues(baseYaml, formValues); result.Should().Contain("enabled: false"); result.Should().NotContain("enabled: 'false'"); result.Should().NotContain("enabled: \"false\""); } [Fact] public void MergeFormValues_WithEmptyFormValues_ReturnsBaseYamlUnchanged() { // If no form values are provided, the YAML comes back untouched. string baseYaml = """ rootUser: admin rootPassword: changeme """; Dictionary formValues = new(); string result = YamlFormMerger.MergeFormValues(baseYaml, formValues); result.Should().Contain("rootUser: admin"); result.Should().Contain("rootPassword: changeme"); } }