From fafb9aaea11867767555bba1a423e2ae39046771 Mon Sep 17 00:00:00 2001 From: Scott Seaton Date: Tue, 7 Apr 2026 13:38:28 -0400 Subject: [PATCH] Fix WorkloadGroup enum serialization: ResourceKind and QueryConsistency ResourceKind in RateLimitProperties was missing the StringEnumConverter attribute, causing it to serialize as an integer (e.g. 1) instead of the string value (e.g. "TotalCpuSeconds"). Every other enum property in the file already had this converter. Also added StringEnumConverter to the QueryConsistency enum type definition, since it is used inside PolicyValue where a property- level converter cannot be applied. Added 4 serialization tests covering: - ResourceKind TotalCpuSeconds serializes as string - ResourceKind RequestCount serializes as string - All enum properties across the policy serialize as strings - ToCreateScript output contains string enum values Fixes github/data#10509 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Model/WorkloadGroupSerializationTests.cs | 162 ++++++++++++++++++ KustoSchemaTools/Model/WorkloadGroup.cs | 2 + 2 files changed, 164 insertions(+) create mode 100644 KustoSchemaTools.Tests/Model/WorkloadGroupSerializationTests.cs diff --git a/KustoSchemaTools.Tests/Model/WorkloadGroupSerializationTests.cs b/KustoSchemaTools.Tests/Model/WorkloadGroupSerializationTests.cs new file mode 100644 index 0000000..e05e66c --- /dev/null +++ b/KustoSchemaTools.Tests/Model/WorkloadGroupSerializationTests.cs @@ -0,0 +1,162 @@ +using KustoSchemaTools.Model; +using Newtonsoft.Json.Linq; + +namespace KustoSchemaTools.Tests.Serialization +{ + public class WorkloadGroupSerializationTests + { + [Fact] + public void ResourceKind_ShouldSerializeAsString_NotInteger() + { + // Arrange - matches the exact scenario from github/data#10509 + var policy = new WorkloadGroupPolicy + { + RequestRateLimitPolicies = new PolicyList + { + new RequestRateLimitPolicy + { + IsEnabled = true, + Scope = RateLimitScope.Principal, + LimitKind = RateLimitKind.ResourceUtilization, + Properties = new RateLimitProperties + { + ResourceKind = RateLimitResourceKind.TotalCpuSeconds, + MaxUtilization = 36000, + TimeWindow = TimeSpan.FromMinutes(15) + } + } + } + }; + + // Act + var json = policy.ToJson(); + var parsed = JObject.Parse(json); + + // Assert - ResourceKind must be a string, not an integer + var resourceKind = parsed["RequestRateLimitPolicies"]![0]!["Properties"]!["ResourceKind"]!; + Assert.Equal(JTokenType.String, resourceKind.Type); + Assert.Equal("TotalCpuSeconds", resourceKind.Value()); + } + + [Fact] + public void ResourceKind_RequestCount_ShouldSerializeAsString() + { + var policy = new WorkloadGroupPolicy + { + RequestRateLimitPolicies = new PolicyList + { + new RequestRateLimitPolicy + { + IsEnabled = true, + Scope = RateLimitScope.WorkloadGroup, + LimitKind = RateLimitKind.ResourceUtilization, + Properties = new RateLimitProperties + { + ResourceKind = RateLimitResourceKind.RequestCount, + MaxUtilization = 100, + TimeWindow = TimeSpan.FromMinutes(1) + } + } + } + }; + + var json = policy.ToJson(); + var parsed = JObject.Parse(json); + + var resourceKind = parsed["RequestRateLimitPolicies"]![0]!["Properties"]!["ResourceKind"]!; + Assert.Equal(JTokenType.String, resourceKind.Type); + Assert.Equal("RequestCount", resourceKind.Value()); + } + + [Fact] + public void AllEnumProperties_ShouldSerializeAsStrings() + { + // Arrange - a policy with every enum populated + var policy = new WorkloadGroupPolicy + { + RequestRateLimitPolicies = new PolicyList + { + new RequestRateLimitPolicy + { + IsEnabled = true, + Scope = RateLimitScope.Principal, + LimitKind = RateLimitKind.ResourceUtilization, + Properties = new RateLimitProperties + { + ResourceKind = RateLimitResourceKind.TotalCpuSeconds, + MaxUtilization = 36000, + TimeWindow = TimeSpan.FromMinutes(15) + } + } + }, + RequestRateLimitsEnforcementPolicy = new RequestRateLimitsEnforcementPolicy + { + QueriesEnforcementLevel = QueriesEnforcementLevel.QueryHead, + CommandsEnforcementLevel = CommandsEnforcementLevel.Database + }, + QueryConsistencyPolicy = new QueryConsistencyPolicy + { + QueryConsistency = new PolicyValue + { + Value = QueryConsistency.WeakAffinitizedByDatabase, + IsRelaxable = true + } + } + }; + + // Act + var json = policy.ToJson(); + var parsed = JObject.Parse(json); + + // Assert - every enum value is a string + var rateLimitPolicy = parsed["RequestRateLimitPolicies"]![0]!; + Assert.Equal("Principal", rateLimitPolicy["Scope"]!.Value()); + Assert.Equal("ResourceUtilization", rateLimitPolicy["LimitKind"]!.Value()); + Assert.Equal("TotalCpuSeconds", rateLimitPolicy["Properties"]!["ResourceKind"]!.Value()); + + var enforcement = parsed["RequestRateLimitsEnforcementPolicy"]!; + Assert.Equal("QueryHead", enforcement["QueriesEnforcementLevel"]!.Value()); + Assert.Equal("Database", enforcement["CommandsEnforcementLevel"]!.Value()); + + var consistency = parsed["QueryConsistencyPolicy"]!["QueryConsistency"]!; + Assert.Equal("WeakAffinitizedByDatabase", consistency["Value"]!.Value()); + } + + [Fact] + public void ToCreateScript_ShouldContainStringEnumValues() + { + // Arrange - the exact scenario from the issue + var workloadGroup = new WorkloadGroup + { + WorkloadGroupName = "test-group", + WorkloadGroupPolicy = new WorkloadGroupPolicy + { + RequestRateLimitPolicies = new PolicyList + { + new RequestRateLimitPolicy + { + IsEnabled = true, + Scope = RateLimitScope.Principal, + LimitKind = RateLimitKind.ResourceUtilization, + Properties = new RateLimitProperties + { + ResourceKind = RateLimitResourceKind.TotalCpuSeconds, + MaxUtilization = 36000, + TimeWindow = TimeSpan.FromMinutes(15) + } + } + } + } + }; + + // Act + var script = workloadGroup.ToCreateScript(); + + // Assert - the script should contain string value, not integer + Assert.Contains("\"ResourceKind\": \"TotalCpuSeconds\"", script); + Assert.DoesNotContain("\"ResourceKind\": 1", script); + Assert.Contains("\"Scope\": \"Principal\"", script); + Assert.Contains("\"LimitKind\": \"ResourceUtilization\"", script); + } + } +} diff --git a/KustoSchemaTools/Model/WorkloadGroup.cs b/KustoSchemaTools/Model/WorkloadGroup.cs index 46261f4..abcef24 100644 --- a/KustoSchemaTools/Model/WorkloadGroup.cs +++ b/KustoSchemaTools/Model/WorkloadGroup.cs @@ -26,6 +26,7 @@ public enum CommandsEnforcementLevel Database } + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public enum QueryConsistency { Strong, @@ -244,6 +245,7 @@ public class RateLimitProperties : IEquatable public int? MaxConcurrentRequests { get; set; } [JsonProperty("ResourceKind")] + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public RateLimitResourceKind? ResourceKind { get; set; } [JsonProperty("MaxUtilization")]