From 4dc28f2bdc2ac697d098d89b5e1d6343b302c0cb Mon Sep 17 00:00:00 2001 From: christopher dykstra Date: Thu, 6 Jan 2022 09:43:47 -0600 Subject: [PATCH] dictionaries and enumerable key-values should generate map[key]value CRD properties --- .../Extensions/EntityToCrdExtensions.cs | 20 ++++++++++++++++++- .../Operator/Entities/CrdGeneration.Test.cs | 12 ++++++----- .../TestEntities/TestSpecEntity.cs | 6 ++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/KubeOps/Operator/Entities/Extensions/EntityToCrdExtensions.cs b/src/KubeOps/Operator/Entities/Extensions/EntityToCrdExtensions.cs index d4da34d5..07d64d96 100644 --- a/src/KubeOps/Operator/Entities/Extensions/EntityToCrdExtensions.cs +++ b/src/KubeOps/Operator/Entities/Extensions/EntityToCrdExtensions.cs @@ -29,6 +29,7 @@ internal static class EntityToCrdExtensions private const string Float = "float"; private const string Double = "double"; private const string DateTime = "date-time"; + private const string Map = "map[{0}]{1}"; private static readonly string[] IgnoredToplevelProperties = { "metadata", "apiversion", "kind" }; @@ -238,9 +239,26 @@ private static V1JSONSchemaProps MapType( additionalColumns, jsonPath); } + else if (!isSimpleType + && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>)) + { + var genericTypes = type.GenericTypeArguments; + var keyType = MapType(genericTypes[0], additionalColumns, jsonPath).Type; + var valueType = MapType(genericTypes[1], additionalColumns, jsonPath).Type; + props.Type = string.Format(Map, keyType, valueType); + } + else if (!isSimpleType + && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>) + && type.GenericTypeArguments.Length == 1 && type.GenericTypeArguments.Single().IsGenericType + && type.GenericTypeArguments.Single().GetGenericTypeDefinition() == typeof(KeyValuePair<,>)) + { + var genericTypes = type.GenericTypeArguments.Single().GenericTypeArguments; + var keyType = MapType(genericTypes[0], additionalColumns, jsonPath).Type; + var valueType = MapType(genericTypes[1], additionalColumns, jsonPath).Type; + props.Type = string.Format(Map, keyType, valueType); + } else if (!isSimpleType && (typeof(IDictionary).IsAssignableFrom(type) || - (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>)) || (type.IsGenericType && type.GetGenericArguments().FirstOrDefault()?.IsGenericType == true && type.GetGenericArguments().FirstOrDefault()?.GetGenericTypeDefinition() == diff --git a/tests/KubeOps.Test/Operator/Entities/CrdGeneration.Test.cs b/tests/KubeOps.Test/Operator/Entities/CrdGeneration.Test.cs index 50a66762..ff106e6c 100644 --- a/tests/KubeOps.Test/Operator/Entities/CrdGeneration.Test.cs +++ b/tests/KubeOps.Test/Operator/Entities/CrdGeneration.Test.cs @@ -57,6 +57,8 @@ public void Should_Not_Add_Status_SubResource_If_Absent() [InlineData("Bool", "boolean", null)] [InlineData("DateTime", "string", "date-time")] [InlineData("Enum", "string", null)] + [InlineData(nameof(TestSpecEntitySpec.GenericDictionary), "map[string]string", null)] + [InlineData(nameof(TestSpecEntitySpec.KeyValueEnumerable), "map[string]string", null)] public void Should_Set_The_Correct_Type_And_Format_For_Types(string fieldName, string typeName, string? format) { var crd = _testSpecEntity.CreateCrd(); @@ -272,21 +274,21 @@ public void Should_Set_Preserve_Unknown_Fields_On_Dictionaries() } [Fact] - public void Should_Set_Preserve_Unknown_Fields_On_Generic_Dictionaries() + public void Should_Not_Set_Preserve_Unknown_Fields_On_Generic_Dictionaries() { var crd = _testSpecEntity.CreateCrd(); - + var specProperties = crd.Spec.Versions.First().Schema.OpenAPIV3Schema.Properties["spec"]; - specProperties.Properties["genericDictionary"].XKubernetesPreserveUnknownFields.Should().BeTrue(); + specProperties.Properties["genericDictionary"].XKubernetesPreserveUnknownFields.Should().BeNull(); } [Fact] - public void Should_Set_Preserve_Unknown_Fields_On_KeyValuePair_Enumerable() + public void Should_Not_Set_Preserve_Unknown_Fields_On_KeyValuePair_Enumerable() { var crd = _testSpecEntity.CreateCrd(); var specProperties = crd.Spec.Versions.First().Schema.OpenAPIV3Schema.Properties["spec"]; - specProperties.Properties["keyValueEnumerable"].XKubernetesPreserveUnknownFields.Should().BeTrue(); + specProperties.Properties["keyValueEnumerable"].XKubernetesPreserveUnknownFields.Should().BeNull(); } [Fact] diff --git a/tests/KubeOps.Test/TestEntities/TestSpecEntity.cs b/tests/KubeOps.Test/TestEntities/TestSpecEntity.cs index e971b500..2541d8c7 100644 --- a/tests/KubeOps.Test/TestEntities/TestSpecEntity.cs +++ b/tests/KubeOps.Test/TestEntities/TestSpecEntity.cs @@ -114,9 +114,15 @@ public class TestSpecEntitySpec public IDictionary Dictionary { get; set; } = new Dictionary(); public IDictionary GenericDictionary { get; set; } = new Dictionary(); + public IDictionary NormalGenericDictionary { get; set; } = new Dictionary(); + public IDictionary? NullableGenericDictionary { get; set; } = new Dictionary(); public IEnumerable> KeyValueEnumerable { get; set; } = new Dictionary(); + public IEnumerable> NormalKeyValueEnumerable { get; set; } = + new Dictionary(); + public IEnumerable>? NullableKeyValueEnumerable { get; set; } = + new Dictionary(); [PreserveUnknownFields] public object PreserveUnknownFields { get; set; } = new object();