From e5cf3a1def897ed587d35061a1d7c96392995c92 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Wed, 15 Jul 2026 10:26:22 -0600 Subject: [PATCH 1/2] use wasm rulesengine --- .fernignore | 4 + .github/workflows/ci.yml | 8 + .gitignore | 4 + WASM_VERSION | 2 +- scripts/download-wasm.sh | 68 ++ .../RulesEngine/CompanyTests.cs | 154 ----- .../RulesEngine/EnumResilienceTests.cs | 84 +-- .../RulesEngine/JsonDeserializationTests.cs | 7 - .../RulesEngine/MetricsTests.cs | 605 ------------------ .../RulesEngine/RuleCheckTests.cs | 474 -------------- .../WasmFlagCheckParityTests.cs} | 261 +++----- .../RulesEngine/Wasm/WasmRulesEngineTests.cs | 69 ++ .../Cache/ComparableTypeConverter.cs | 40 -- .../Cache/SchematicCacheSerializerDefaults.cs | 3 +- src/SchematicHQ.Client/Datastream/Client.cs | 58 +- .../RulesEngine/CheckFlagResult.cs | 29 + .../CheckFlagWithEntitlementResponse.cs | 127 ++++ src/SchematicHQ.Client/RulesEngine/Consts.cs | 63 -- src/SchematicHQ.Client/RulesEngine/Errors.cs | 8 + .../RulesEngine/FlagCheck.cs | 394 ------------ src/SchematicHQ.Client/RulesEngine/Metrics.cs | 214 ------- .../RulesEngine/RuleCheck.cs | 350 ---------- .../RulesEngine/RulesEngineExtensions.cs | 67 -- .../RulesEngine/Utils/Set.cs | 39 -- .../RulesEngine/Utils/TypeConverter.cs | 213 ------ .../RulesEngine/Wasm/WasmRulesEngine.cs | 376 +++++++++++ .../RulesEngine/Wasm/rulesengine.wasm | Bin 672455 -> 0 bytes .../SchematicHQ.Client.Custom.props | 22 + 28 files changed, 851 insertions(+), 2892 deletions(-) create mode 100755 scripts/download-wasm.sh delete mode 100644 src/SchematicHQ.Client.Test/RulesEngine/CompanyTests.cs delete mode 100644 src/SchematicHQ.Client.Test/RulesEngine/MetricsTests.cs delete mode 100644 src/SchematicHQ.Client.Test/RulesEngine/RuleCheckTests.cs rename src/SchematicHQ.Client.Test/RulesEngine/{FlagCheckTests.cs => Wasm/WasmFlagCheckParityTests.cs} (73%) create mode 100644 src/SchematicHQ.Client.Test/RulesEngine/Wasm/WasmRulesEngineTests.cs delete mode 100644 src/SchematicHQ.Client/Cache/ComparableTypeConverter.cs create mode 100644 src/SchematicHQ.Client/RulesEngine/CheckFlagResult.cs create mode 100644 src/SchematicHQ.Client/RulesEngine/CheckFlagWithEntitlementResponse.cs delete mode 100644 src/SchematicHQ.Client/RulesEngine/Consts.cs create mode 100644 src/SchematicHQ.Client/RulesEngine/Errors.cs delete mode 100644 src/SchematicHQ.Client/RulesEngine/FlagCheck.cs delete mode 100644 src/SchematicHQ.Client/RulesEngine/Metrics.cs delete mode 100644 src/SchematicHQ.Client/RulesEngine/RuleCheck.cs delete mode 100644 src/SchematicHQ.Client/RulesEngine/RulesEngineExtensions.cs delete mode 100644 src/SchematicHQ.Client/RulesEngine/Utils/Set.cs delete mode 100644 src/SchematicHQ.Client/RulesEngine/Utils/TypeConverter.cs create mode 100644 src/SchematicHQ.Client/RulesEngine/Wasm/WasmRulesEngine.cs delete mode 100755 src/SchematicHQ.Client/RulesEngine/Wasm/rulesengine.wasm diff --git a/.fernignore b/.fernignore index d364963f..02123399 100644 --- a/.fernignore +++ b/.fernignore @@ -2,6 +2,10 @@ .claude/ .github/CODEOWNERS .github/workflows/claude-code.yml +.github/workflows/ci.yml +.gitignore +WASM_VERSION +scripts/download-wasm.sh CLAUDE.md LICENSE README.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9eed61c6..1b6320a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,11 @@ concurrency: env: DOTNET_NOLOGO: true + # Authenticates `gh release download` in scripts/download-wasm.sh; the rules engine + # WASM lives in the private SchematicHQ/schematic-api repo, so the default + # GITHUB_TOKEN (scoped to this repo) cannot read it. Requires a GH_TOKEN repo + # secret with read access to schematic-api releases. + GH_TOKEN: ${{ secrets.GH_TOKEN }} jobs: ci: @@ -22,6 +27,9 @@ jobs: with: dotnet-version: 10.x + - name: Download WASM binary + run: ./scripts/download-wasm.sh + - name: Install tools run: dotnet tool restore diff --git a/.gitignore b/.gitignore index 11014f2b..f83e9c99 100644 --- a/.gitignore +++ b/.gitignore @@ -482,3 +482,7 @@ $RECYCLE.BIN/ # Vim temporary swap files *.swp + +# Rules engine WASM binary (downloaded at build time from schematic-api GitHub Releases) +src/SchematicHQ.Client/RulesEngine/Wasm/rulesengine.wasm +src/SchematicHQ.Client/RulesEngine/Wasm/.wasm_version diff --git a/WASM_VERSION b/WASM_VERSION index 1d0ba9ea..8f0916f7 100644 --- a/WASM_VERSION +++ b/WASM_VERSION @@ -1 +1 @@ -0.4.0 +0.5.0 diff --git a/scripts/download-wasm.sh b/scripts/download-wasm.sh new file mode 100755 index 00000000..787cacaf --- /dev/null +++ b/scripts/download-wasm.sh @@ -0,0 +1,68 @@ +#!/bin/bash +set -e + +# Downloads the rules engine WASM binary from the schematic-api GitHub Release. +# Reads the pinned version from WASM_VERSION at the repo root. +# +# The binary is intentionally NOT tracked in git (see .gitignore); it is fetched +# at build time both locally (via the DownloadWasm MSBuild target) and in CI. + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +WASM_DIR="$REPO_ROOT/src/SchematicHQ.Client/RulesEngine/Wasm" +VERSION_FILE="$REPO_ROOT/WASM_VERSION" + +GITHUB_REPO="SchematicHQ/schematic-api" + +if [ ! -f "$VERSION_FILE" ]; then + echo "ERROR: WASM_VERSION file not found at $VERSION_FILE" + exit 1 +fi + +VERSION=$(tr -d '[:space:]' < "$VERSION_FILE") +TAG="rulesengine/v${VERSION}" +ASSET_NAME="rulesengine-wasm-csharp-v${VERSION}.tar.gz" + +# Skip download if binary already exists and version matches +if [ -f "$WASM_DIR/rulesengine.wasm" ] && [ -f "$WASM_DIR/.wasm_version" ]; then + CURRENT=$(tr -d '[:space:]' < "$WASM_DIR/.wasm_version") + if [ "$CURRENT" = "$VERSION" ]; then + echo "WASM binary already at version $VERSION, skipping download." + exit 0 + fi +fi + +echo "Downloading rules engine WASM v${VERSION}..." +mkdir -p "$WASM_DIR" + +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +if ! gh release download "$TAG" \ + -R "$GITHUB_REPO" \ + -p "$ASSET_NAME" \ + -D "$TMPDIR" 2>/dev/null; then + echo "ERROR: Failed to download WASM binary" + echo "Tag: $TAG" + echo "Asset: $ASSET_NAME" + echo "" + echo "If this is a new version, ensure a release exists at:" + echo " https://github.com/${GITHUB_REPO}/releases/tag/${TAG}" + echo "" + echo "Ensure the GitHub CLI is authenticated with access to ${GITHUB_REPO}: gh auth status" + exit 1 +fi + +tar -xzf "$TMPDIR/$ASSET_NAME" -C "$TMPDIR" + +if [ ! -f "$TMPDIR/rulesengine.wasm" ]; then + echo "ERROR: rulesengine.wasm not found in release archive" + ls -la "$TMPDIR" + exit 1 +fi + +cp "$TMPDIR"/rulesengine.wasm "$WASM_DIR/" + +echo "$VERSION" > "$WASM_DIR/.wasm_version" + +echo "Downloaded rules engine WASM v${VERSION} to $WASM_DIR/" diff --git a/src/SchematicHQ.Client.Test/RulesEngine/CompanyTests.cs b/src/SchematicHQ.Client.Test/RulesEngine/CompanyTests.cs deleted file mode 100644 index 6ca02436..00000000 --- a/src/SchematicHQ.Client.Test/RulesEngine/CompanyTests.cs +++ /dev/null @@ -1,154 +0,0 @@ -using SchematicHQ.Client.RulesEngine; -using System.Diagnostics; -using NUnit.Framework; - -namespace SchematicHQ.Client.Test.RulesEngine -{ - [TestFixture] - public class CompanyTests - { - [Test] - public void AddMetric_Adds_New_Metric_When_None_Exists_With_Same_Constraints() - { - // Arrange - var company = TestHelpers.CreateTestCompany(); - int initialCount = company.Metrics.Count(); - - // Act - var metric = TestHelpers.CreateTestMetric(company, "test-event", RulesengineMetricPeriod.AllTime, 5); - company.AddMetric(metric); - - // Assert - Assert.That(company.Metrics.Count(), Is.EqualTo(initialCount + 1)); - Assert.That(company.Metrics, Does.Contain(metric)); - } - - [Test] - public void AddMetric_Replaces_Existing_Metric_With_Same_Constraints() - { - // Arrange - var company = TestHelpers.CreateTestCompany(); - - // Add initial metric - string eventSubtype = "test-event"; - var period = RulesengineMetricPeriod.AllTime; - RulesengineMetricPeriodMonthReset monthReset = RulesengineMetricPeriodMonthReset.FirstOfMonth; - - var initialMetric = TestHelpers.CreateTestMetric(company, eventSubtype, period, 5); - company.AddMetric(initialMetric); - int initialCount = company.Metrics.Count(); - - // Act - Add metric with same constraints but different value - var newMetric = TestHelpers.CreateTestMetric(company, eventSubtype, period, 10); - company.AddMetric(newMetric); - - // Assert - // Verify the length hasn't changed but the new metric replaced the old one - Assert.That(company.Metrics.Count(), Is.EqualTo(initialCount)); - Assert.That(company.Metrics, Does.Contain(newMetric)); - Assert.That(company.Metrics, Does.Not.Contain(initialMetric)); - - // Find the metric and verify it has the new value - var foundMetric = CompanyMetricExtensions.Find(company.Metrics, eventSubtype, period, monthReset); - Assert.That(foundMetric, Is.Not.Null); - Assert.That(foundMetric!.Value, Is.EqualTo(10)); - } - - [Test] - public void AddMetric_Handles_Concurrent_Updates_Safely() - { - // Arrange - var company = TestHelpers.CreateTestCompany(); - - // Set up concurrent tasks to add metrics - const int numTasks = 10; - var tasks = new List(); - - // Act - for (int i = 0; i < numTasks; i++) - { - var index = i; // Capture the current index for the task - tasks.Add(Task.Run(() => - { - // Create a metric with a unique event subtype to avoid collision - string uniqueSubtype = $"test-event-{DateTime.Now.Ticks}-{index}"; - var metric = TestHelpers.CreateTestMetric(company, uniqueSubtype, RulesengineMetricPeriod.AllTime, index); - - // Add the metric - company.AddMetric(metric); - })); - } - - var taskArray = tasks.ToArray(); - Debug.WriteLine($"Starting {taskArray.Length} concurrent tasks to add metrics..."); - - // Wait for all tasks to finish - Task.WaitAll(tasks.ToArray()); - - // Assert - Assert.That(company.Metrics.Count(), Is.GreaterThanOrEqualTo(numTasks)); - } - - [Test] - public void AddMetric_NullCompany_DoesNotThrow() - { - // Arrange - RulesengineCompany? company = null; - var metric = new RulesengineCompanyMetric - { - AccountId = "acct", - EnvironmentId = "env", - CompanyId = "comp", - EventSubtype = "test", - Value = 0, - Period = new RulesengineMetricPeriod("all_time"), - MonthReset = RulesengineMetricPeriodMonthReset.FirstOfMonth, - CreatedAt = DateTime.UtcNow - }; - - // Act & Assert - Assert.DoesNotThrow(() => company?.AddMetric(metric)); - } - - [Test] - public void AddMetric_NullMetric_DoesNotThrow() - { - // Arrange - var company = TestHelpers.CreateTestCompany(); - - // Act & Assert - Assert.DoesNotThrow(() => company.AddMetric(null)); - } - - [Test] - public void AddMetric_CompanyWithNoMetrics_DoesNotThrow() - { - // Arrange - var company = new RulesengineCompany - { - Id = TestHelpers.GenerateTestId("comp"), - AccountId = TestHelpers.GenerateTestId("acct"), - EnvironmentId = TestHelpers.GenerateTestId("env"), - PlanIds = new List { TestHelpers.GenerateTestId("plan"), TestHelpers.GenerateTestId("plan") }, - BillingProductIds = new List { TestHelpers.GenerateTestId("bilp"), TestHelpers.GenerateTestId("bilp") }, - BasePlanId = TestHelpers.GenerateTestId("plan"), - Traits = new List(), - Subscription = new RulesengineSubscription - { - Id = TestHelpers.GenerateTestId("bilsub"), - PeriodStart = DateTime.UtcNow.AddDays(-30), - PeriodEnd = DateTime.UtcNow.AddDays(30) - }, - // Initialize with null metrics list - Metrics = null! - }; - - var metric = TestHelpers.CreateTestMetric(company, "foo", RulesengineMetricPeriod.AllTime, 1); - - // Act & Assert - Assert.DoesNotThrow(() => company.AddMetric(metric)); - Assert.That(company.Metrics, Is.Not.Null); - Assert.That(company.Metrics.Count(), Is.EqualTo(1)); - } - } -} diff --git a/src/SchematicHQ.Client.Test/RulesEngine/EnumResilienceTests.cs b/src/SchematicHQ.Client.Test/RulesEngine/EnumResilienceTests.cs index 8deceb85..c8ee879a 100644 --- a/src/SchematicHQ.Client.Test/RulesEngine/EnumResilienceTests.cs +++ b/src/SchematicHQ.Client.Test/RulesEngine/EnumResilienceTests.cs @@ -19,8 +19,7 @@ public void Setup() { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, Converters = { - new ResilientEnumConverter(), - new ComparableTypeConverter() + new ResilientEnumConverter() } }; } @@ -39,34 +38,6 @@ public void RuleType_UnknownValue_ShouldFallbackToUnknown() }); } - [Test] - public void ComparableType_UnknownValue_ShouldFallbackToDefault() - { - // Arrange - string unknownComparableTypeJson = "\"unknown_comparable_type\""; - - // Act & Assert - Assert.DoesNotThrow(() => - { - var result = JsonSerializer.Deserialize(unknownComparableTypeJson, _options); - Assert.That(result, Is.EqualTo(ComparableType.Unknown)); // First enum value - }); - } - - [Test] - public void ComparableType_EmptyString_ShouldFallbackToDefault() - { - // Arrange - string emptyComparableTypeJson = "\"\""; - - // Act & Assert - Assert.DoesNotThrow(() => - { - var result = JsonSerializer.Deserialize(emptyComparableTypeJson, _options); - Assert.That(result, Is.EqualTo(ComparableType.Unknown)); - }); - } - [Test] public void RuleType_ValidValue_ShouldParseCorrectly() { @@ -80,19 +51,6 @@ public void RuleType_ValidValue_ShouldParseCorrectly() Assert.That(result, Is.EqualTo(RulesengineRuleType.Standard)); } - [Test] - public void ComparableType_ValidValue_ShouldParseCorrectly() - { - // Arrange - string validComparableTypeJson = "\"String\""; - - // Act - var result = JsonSerializer.Deserialize(validComparableTypeJson, _options); - - // Assert - Assert.That(result, Is.EqualTo(ComparableType.String)); - } - [Test] public void RuleType_SnakeCaseValue_ShouldParseCorrectly() { @@ -106,20 +64,6 @@ public void RuleType_SnakeCaseValue_ShouldParseCorrectly() Assert.That(result, Is.EqualTo(RulesengineRuleType.GlobalOverride)); } - [Test] - public void ComparableType_NullValue_ShouldFallbackToDefault() - { - // Arrange - string nullComparableTypeJson = "null"; - - // Act & Assert - Assert.DoesNotThrow(() => - { - var result = JsonSerializer.Deserialize(nullComparableTypeJson, _options); - Assert.That(result, Is.Null); - }); - } - [Test] public void RuleType_InvalidValue_ShouldFallbackToUnknown() { @@ -153,19 +97,6 @@ public void RuleType_EmptyValue_ShouldFallbackToUnknown() }); } - [TestCase("\"invalid_type\"", ComparableType.Unknown)] - [TestCase("\"nonexistent\"", ComparableType.Unknown)] - [TestCase("\"\"", ComparableType.Unknown)] - public void ComparableType_InvalidValues_ShouldFallbackToDefault(string json, ComparableType expected) - { - // Act & Assert - Assert.DoesNotThrow(() => - { - var result = JsonSerializer.Deserialize(json, _options); - Assert.That(result, Is.EqualTo(expected)); - }); - } - [Test] public void RuleType_Serialization_ShouldUseSnakeCase() { @@ -191,18 +122,5 @@ public void RuleType_UnknownSerialization_ShouldSerializeAsEmptyString() // Assert Assert.That(json, Is.EqualTo("\"\"")); } - - [Test] - public void ComparableType_Serialization_ShouldUseSnakeCase() - { - // Arrange - var comparableType = ComparableType.String; - - // Act - var json = JsonSerializer.Serialize(comparableType, _options); - - // Assert - Assert.That(json, Is.EqualTo("\"string\"")); - } } } diff --git a/src/SchematicHQ.Client.Test/RulesEngine/JsonDeserializationTests.cs b/src/SchematicHQ.Client.Test/RulesEngine/JsonDeserializationTests.cs index 4c64612f..d72c8ffd 100644 --- a/src/SchematicHQ.Client.Test/RulesEngine/JsonDeserializationTests.cs +++ b/src/SchematicHQ.Client.Test/RulesEngine/JsonDeserializationTests.cs @@ -21,7 +21,6 @@ public void SetUp() WriteIndented = false, PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, Converters = { - new ComparableTypeConverter(), new ResilientEnumConverter(), new JsonStringEnumConverter(JsonNamingPolicy.SnakeCaseLower, true) } @@ -328,12 +327,6 @@ public void RuleType_WithInvalidValue_ShouldFallbackToUnknown() } // Test helper classes - private class TestComparableTypeObject - { - [JsonPropertyName("comparable_type")] - public ComparableType ComparableType { get; set; } - } - private class TestTraitDefinitionComparableTypeObject { [JsonPropertyName("comparable_type")] diff --git a/src/SchematicHQ.Client.Test/RulesEngine/MetricsTests.cs b/src/SchematicHQ.Client.Test/RulesEngine/MetricsTests.cs deleted file mode 100644 index a293df85..00000000 --- a/src/SchematicHQ.Client.Test/RulesEngine/MetricsTests.cs +++ /dev/null @@ -1,605 +0,0 @@ -using SchematicHQ.Client.RulesEngine; -using NUnit.Framework; - -namespace SchematicHQ.Client.Test.RulesEngine -{ - [TestFixture] - public class MetricsTests - { - [Test] - public void TestGetCurrentMetricPeriodStartForCalendarMetricPeriod() - { - // Test for CurrentDay - { - var result = Metrics.GetCurrentMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod.CurrentDay); - Assert.That(result, Is.Not.Null); - - var expected = DateTime.UtcNow.Date; - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(expected.Day)); - Assert.That(result?.Hour, Is.EqualTo(0)); - Assert.That(result?.Minute, Is.EqualTo(0)); - Assert.That(result?.Second, Is.EqualTo(0)); - } - - // Test for CurrentWeek - { - var result = Metrics.GetCurrentMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod.CurrentWeek); - Assert.That(result, Is.Not.Null); - - var now = DateTime.UtcNow; - int daysSinceMonday = ((int)now.DayOfWeek - (int)DayOfWeek.Monday + 7) % 7; - var expected = now.Date.AddDays(-daysSinceMonday); - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(expected.Day)); - Assert.That(result?.Hour, Is.EqualTo(0)); - Assert.That(result?.Minute, Is.EqualTo(0)); - Assert.That(result?.Second, Is.EqualTo(0)); - Assert.That(result?.DayOfWeek, Is.EqualTo(DayOfWeek.Monday)); - } - - // Test for CurrentMonth - { - var result = Metrics.GetCurrentMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod.CurrentMonth); - Assert.That(result, Is.Not.Null); - - var now = DateTime.UtcNow; - var expected = new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Utc); - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(expected.Day)); - Assert.That(result?.Hour, Is.EqualTo(0)); - Assert.That(result?.Minute, Is.EqualTo(0)); - Assert.That(result?.Second, Is.EqualTo(0)); - Assert.That(result?.Day, Is.EqualTo(1)); - } - - // Test for AllTime - { - var result = Metrics.GetCurrentMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod.AllTime); - Assert.That(result, Is.Null); - } - } - - [Test] - public void TestGetCurrentMetricPeriodStartForCompanyBillingSubscription() - { - // Test for null company - { - var result = Metrics.GetCurrentMetricPeriodStartForCompanyBillingSubscription(null); - Assert.That(result, Is.Not.Null); - - var now = DateTime.UtcNow; - var expected = new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Utc); - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(1)); - } - - // Test for company with null subscription - { - var company = TestHelpers.CreateTestCompany(); - company.Subscription = null; - var result = Metrics.GetCurrentMetricPeriodStartForCompanyBillingSubscription(company); - Assert.That(result, Is.Not.Null); - - var now = DateTime.UtcNow; - var expected = new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Utc); - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(1)); - } - - // Test for subscription period start in future - { - var company = TestHelpers.CreateTestCompany(); - company.Subscription = new RulesengineSubscription - { - Id = "test-subscription", - PeriodStart = DateTime.UtcNow.AddDays(7), - PeriodEnd = DateTime.UtcNow.AddDays(37) - }; - - var result = Metrics.GetCurrentMetricPeriodStartForCompanyBillingSubscription(company); - Assert.That(result, Is.Not.Null); - - var now = DateTime.UtcNow; - var expected = new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Utc); - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(1)); - } - - // Test for current month reset date not passed yet - { - var now = DateTime.UtcNow; - var company = TestHelpers.CreateTestCompany(); - - // Set subscription to start on a day later in the month than today - int futureDay = 15; - if (now.Day >= 15) // Avoid month boundary issues - { - futureDay = 5; - } - - company.Subscription = new RulesengineSubscription - { - Id = "test-subscription", - PeriodStart = new DateTime( - now.Year - 1, - now.Month, - futureDay, - 12, 0, 0, - DateTimeKind.Utc), - PeriodEnd = now.AddMonths(6) - }; - - var result = Metrics.GetCurrentMetricPeriodStartForCompanyBillingSubscription(company); - Assert.That(result, Is.Not.Null); - - // In this case, the result should be last month's reset date - DateTime expected; - if (now.Day < 15) - { - expected = new DateTime( - now.Year, - now.Month, - futureDay, - 12, 0, 0, - DateTimeKind.Utc); - } - else - { - expected = new DateTime( - now.Year, - now.Month + 1, - futureDay, - 12, 0, 0, - DateTimeKind.Utc); - if (now.Month == 12) - { - expected = new DateTime( - now.Year + 1, - 1, // January - futureDay, - 12, 0, 0, - DateTimeKind.Utc); - } - } - - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(expected.Day)); - Assert.That(result?.Hour, Is.EqualTo(expected.Hour)); - } - - // Test for current month reset date has passed - { - var now = DateTime.UtcNow; - var company = TestHelpers.CreateTestCompany(); - - // Set subscription to start on a day earlier in the month than today - int pastDay = now.Day - 5; - if (pastDay < 1) - { - pastDay = 1; - } - - company.Subscription = new RulesengineSubscription - { - Id = "test-subscription", - PeriodStart = new DateTime( - now.Year - 1, - now.Month, - pastDay, - 12, 0, 0, - DateTimeKind.Utc), - PeriodEnd = now.AddMonths(6) - }; - - var result = Metrics.GetCurrentMetricPeriodStartForCompanyBillingSubscription(company); - Assert.That(result, Is.Not.Null); - - // In this case, the result should be this month's reset date - var expected = new DateTime( - now.Year, - now.Month+1, - pastDay, - 12, 0, 0, - DateTimeKind.Utc); - - if (now.Month == 12) // December - { - expected = new DateTime( - now.Year + 1, - 1, // January - pastDay, - 12, 0, 0, - DateTimeKind.Utc); - } - - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(expected.Day)); - Assert.That(result?.Hour, Is.EqualTo(expected.Hour)); - } - - // Test for reset date before subscription period start - { - var now = DateTime.UtcNow; - var company = TestHelpers.CreateTestCompany(); - - var periodStart = now.AddMonths(-6); - // Set a recent subscription start date (10 days ago) - company.Subscription = new RulesengineSubscription - { - Id = "test-subscription", - PeriodStart = periodStart, - PeriodEnd = now.AddDays(10) - }; - - var result = Metrics.GetCurrentMetricPeriodStartForCompanyBillingSubscription(company); - Assert.That(result, Is.Not.Null); - - // The result should be the period start date - Assert.That(result?.Year, Is.EqualTo(company.Subscription.PeriodEnd.Year)); - Assert.That(result?.Month, Is.EqualTo(company.Subscription.PeriodEnd.Month)); - Assert.That(result?.Day, Is.EqualTo(company.Subscription.PeriodEnd.Day)); - Assert.That(result?.Hour, Is.EqualTo(company.Subscription.PeriodEnd.Hour)); - } - } - - [Test] - public void TestGetNextMetricPeriodStartForCalendarMetricPeriod() - { - // Test for CurrentDay - { - var result = Metrics.GetNextMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod.CurrentDay); - Assert.That(result, Is.Not.Null); - - var expected = DateTime.UtcNow.Date.AddDays(1); - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(expected.Day)); - Assert.That(result?.Hour, Is.EqualTo(0)); - Assert.That(result?.Minute, Is.EqualTo(0)); - Assert.That(result?.Second, Is.EqualTo(0)); - } - - // Test for CurrentWeek - { - var result = Metrics.GetNextMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod.CurrentWeek); - Assert.That(result, Is.Not.Null); - - var now = DateTime.UtcNow; - int daysUntilMonday = ((int)DayOfWeek.Monday - (int)now.DayOfWeek + 7) % 7; - if (daysUntilMonday == 0) - daysUntilMonday = 7; // If today is Monday, get next Monday - var expected = now.Date.AddDays(daysUntilMonday); - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(expected.Day)); - Assert.That(result?.Hour, Is.EqualTo(0)); - Assert.That(result?.Minute, Is.EqualTo(0)); - Assert.That(result?.Second, Is.EqualTo(0)); - Assert.That(result?.DayOfWeek, Is.EqualTo(DayOfWeek.Monday)); - } - - // Test for CurrentMonth - { - var result = Metrics.GetNextMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod.CurrentMonth); - Assert.That(result, Is.Not.Null); - - var now = DateTime.UtcNow; - var firstDayOfCurrentMonth = new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Utc); - var expected = firstDayOfCurrentMonth.AddMonths(1); - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(expected.Day)); - Assert.That(result?.Hour, Is.EqualTo(0)); - Assert.That(result?.Minute, Is.EqualTo(0)); - Assert.That(result?.Second, Is.EqualTo(0)); - Assert.That(result?.Day, Is.EqualTo(1)); - } - - // Test for AllTime - { - var result = Metrics.GetNextMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod.AllTime); - Assert.That(result, Is.Null); - } - } - - [Test] - public void TestGetNextMetricPeriodStartForCompanyBillingSubscription() - { - // Test for null company - { - var result = Metrics.GetNextMetricPeriodStartForCompanyBillingSubscription(null); - Assert.That(result, Is.Not.Null); - - var now = DateTime.UtcNow; - var firstDayOfCurrentMonth = new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Utc); - var expected = firstDayOfCurrentMonth.AddMonths(1); - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(1)); - } - - // Test for company with null subscription - { - var company = TestHelpers.CreateTestCompany(); - company.Subscription = null; - var result = Metrics.GetNextMetricPeriodStartForCompanyBillingSubscription(company); - Assert.That(result, Is.Not.Null); - - var now = DateTime.UtcNow; - var firstDayOfCurrentMonth = new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Utc); - var expected = firstDayOfCurrentMonth.AddMonths(1); - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(1)); - } - - // Test for subscription period start in future - { - var company = TestHelpers.CreateTestCompany(); - var now = DateTime.UtcNow; - - // Set subscription to start 7 days from now - company.Subscription = new RulesengineSubscription - { - Id = "test-subscription", - PeriodStart = now.AddDays(7), - PeriodEnd = now.AddDays(37) - }; - - var result = Metrics.GetNextMetricPeriodStartForCompanyBillingSubscription(company); - Assert.That(result, Is.Not.Null); - - // If period start is sooner than next month, period start should be used - var firstDayOfCurrentMonth = new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Utc); - var startOfNextMonth = firstDayOfCurrentMonth.AddMonths(1); - - if (company.Subscription.PeriodStart > startOfNextMonth) - { - // Period start is after next month, so next month should be used - Assert.That(result, Is.EqualTo(startOfNextMonth)); - } - else - { - // Period start is before next month, so period start should be used - Assert.That(result, Is.EqualTo(company.Subscription.PeriodStart)); - } - } - - // Test for next reset date after subscription end - { - var company = TestHelpers.CreateTestCompany(); - var now = DateTime.UtcNow; - - // Set subscription to have started some time ago - company.Subscription = new RulesengineSubscription - { - Id = "test-subscription", - PeriodStart = now.AddMonths(-6), - PeriodEnd = now.AddDays(10) // But set it to end soon (before the next monthly reset) - }; - - var result = Metrics.GetNextMetricPeriodStartForCompanyBillingSubscription(company); - Assert.That(result, Is.Not.Null); - - // The result should be the period end date - Assert.That(result, Is.EqualTo(company.Subscription.PeriodEnd)); - } - - // Test for current month reset date has passed - { - var now = DateTime.UtcNow; - var company = TestHelpers.CreateTestCompany(); - - // Set subscription to start on a day earlier in the month than today - int pastDay = now.Day - 5; - if (pastDay < 1) - { - pastDay = 1; - } - - company.Subscription = new RulesengineSubscription - { - Id = "test-subscription", - PeriodStart = new DateTime( - now.Year - 1, - now.Month, - pastDay, - 12, 0, 0, - DateTimeKind.Utc), - PeriodEnd = now.AddYears(1) // Set end date far in the future - }; - - var result = Metrics.GetNextMetricPeriodStartForCompanyBillingSubscription(company); - Assert.That(result, Is.Not.Null); - - // In this case, the result should be next month's reset date - DateTime expected; - if (now.Month == 12) // December - { - expected = new DateTime( - now.Year + 1, - 1, // January - pastDay, - 12, 0, 0, - DateTimeKind.Utc); - } - else - { - expected = new DateTime( - now.Year, - now.Month + 1, - Math.Min(pastDay, DateTime.DaysInMonth(now.Year, now.Month + 1)), - 12, 0, 0, - DateTimeKind.Utc); - } - - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(expected.Day)); - Assert.That(result?.Hour, Is.EqualTo(expected.Hour)); - } - - // Test for current month reset date has not passed yet - { - var now = DateTime.UtcNow; - var company = TestHelpers.CreateTestCompany(); - - // Set subscription to start on a day later in the month than today - // Ensure we have a truly future day by adding a safety margin - int futureDay = now.Day + 2; - if (futureDay > 28) // Avoid month boundary issues - { - // If we can't get a future day this month, use a day earlier this month - // and expect next month's reset date instead - futureDay = Math.Max(1, now.Day - 2); - - company.Subscription = new RulesengineSubscription - { - Id = "test-subscription", - PeriodStart = new DateTime( - now.Year - 1, - now.Month, - futureDay, - 12, 0, 0, - DateTimeKind.Utc), - PeriodEnd = now.AddYears(1) // Set end date far in the future - }; - - var result = Metrics.GetNextMetricPeriodStartForCompanyBillingSubscription(company); - Assert.That(result, Is.Not.Null); - - // Since the reset day is in the past this month, the next reset should be next month's reset date - DateTime expected; - if (now.Month == 12) // December - { - expected = new DateTime( - now.Year + 1, - 1, // January - futureDay, - 12, 0, 0, - DateTimeKind.Utc); - } - else - { - expected = new DateTime( - now.Year, - now.Month + 1, - Math.Min(futureDay, DateTime.DaysInMonth(now.Year, now.Month + 1)), - 12, 0, 0, - DateTimeKind.Utc); - } - - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(expected.Day)); - Assert.That(result?.Hour, Is.EqualTo(expected.Hour)); - } - else - { - company.Subscription = new RulesengineSubscription - { - Id = "test-subscription", - PeriodStart = new DateTime( - now.Year - 1, - now.Month, - futureDay, - 12, 0, 0, - DateTimeKind.Utc), - PeriodEnd = now.AddYears(1) // Set end date far in the future - }; - - var result = Metrics.GetNextMetricPeriodStartForCompanyBillingSubscription(company); - Assert.That(result, Is.Not.Null); - - // Since the reset day is in the future this month, the next reset should be this month's reset date - DateTime expected = new DateTime( - now.Year, - now.Month, - futureDay, - 12, 0, 0, - DateTimeKind.Utc); - - Assert.That(result?.Year, Is.EqualTo(expected.Year)); - Assert.That(result?.Month, Is.EqualTo(expected.Month)); - Assert.That(result?.Day, Is.EqualTo(expected.Day)); - Assert.That(result?.Hour, Is.EqualTo(expected.Hour)); - } - } - } - - [Test] - public void TestGetNextMetricPeriodStartFromCondition() - { - // Test for null condition - { - var result = Metrics.GetNextMetricPeriodStartFromCondition(null, null); - Assert.That(result, Is.Null); - } - - // Test for condition that is not metric type - { - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Trait); - var result = Metrics.GetNextMetricPeriodStartFromCondition(condition, null); - Assert.That(result, Is.Null); - } - - // Test for metric period is null - { - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Metric); - condition.MetricPeriod = null; - var result = Metrics.GetNextMetricPeriodStartFromCondition(condition, null); - Assert.That(result, Is.Null); - } - - // Test for metric period is all time - { - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Metric); - condition.MetricPeriod = RulesengineMetricPeriod.AllTime; - var result = Metrics.GetNextMetricPeriodStartFromCondition(condition, null); - Assert.That(result, Is.Null); - } - - // Test for metric period is current month with billing cycle reset - { - var company = TestHelpers.CreateTestCompany(); - company.Subscription = new RulesengineSubscription - { - Id = "test-subscription", - PeriodStart = DateTime.UtcNow.AddMonths(-1), - PeriodEnd = DateTime.UtcNow.AddMonths(1) - }; - - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Metric); - condition.MetricPeriod = RulesengineMetricPeriod.CurrentMonth; - condition.MetricPeriodMonthReset = RulesengineMetricPeriodMonthReset.BillingCycle; - - var result = Metrics.GetNextMetricPeriodStartFromCondition(condition, company); - var expected = Metrics.GetNextMetricPeriodStartForCompanyBillingSubscription(company); - - Assert.That(result, Is.Not.Null); - Assert.That(result, Is.EqualTo(expected)); - } - - // Test for metric period is calendar-based - { - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Metric); - condition.MetricPeriod = RulesengineMetricPeriod.CurrentDay; - - var result = Metrics.GetNextMetricPeriodStartFromCondition(condition, null); - var expected = Metrics.GetNextMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod.CurrentDay); - - Assert.That(result, Is.Not.Null); - Assert.That(result, Is.EqualTo(expected)); - } - } - } -} diff --git a/src/SchematicHQ.Client.Test/RulesEngine/RuleCheckTests.cs b/src/SchematicHQ.Client.Test/RulesEngine/RuleCheckTests.cs deleted file mode 100644 index 190d4bac..00000000 --- a/src/SchematicHQ.Client.Test/RulesEngine/RuleCheckTests.cs +++ /dev/null @@ -1,474 +0,0 @@ -using NUnit.Framework; -using SchematicHQ.Client.RulesEngine; -using SchematicHQ.Client.RulesEngine.Utils; - -namespace SchematicHQ.Client.Test.RulesEngine -{ - [TestFixture] - public class RuleCheckServiceTests - { - [Test] - public async Task Check_ReturnsTrue_ForGlobalOverrideRules() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - var company = TestHelpers.CreateTestCompany(); - var rule = TestHelpers.CreateTestRule(); - rule.RuleType = RulesengineRuleType.GlobalOverride; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.True); - } - - [Test] - public async Task Check_ReturnsFalse_ForNilRule() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - var company = TestHelpers.CreateTestCompany(); - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = null - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.False); - } - - [Test] - public async Task Check_ReturnsTrue_ForDefaultRules() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - var company = TestHelpers.CreateTestCompany(); - var rule = TestHelpers.CreateTestRule(); - rule.RuleType = RulesengineRuleType.Default; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.True); - } - - [Test] - public async Task Rule_Matches_SpecificCompany() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - var company = TestHelpers.CreateTestCompany(); - var rule = TestHelpers.CreateTestRule(); - - // Create condition targeting the company - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Company); - condition.ResourceIds = new List { company.Id }; - rule.Conditions = new List { condition }; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.True); - } - - [Test] - public async Task Rule_Matches_When_Metric_Within_Limit() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - var company = TestHelpers.CreateTestCompany(); - - string eventSubtype = "test-event"; - var rule = TestHelpers.CreateTestRule(); - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Metric); - condition.EventSubtype = eventSubtype; - condition.MetricValue = 10; - condition.Operator = ComparableOperator.Lte; - rule.Conditions = new List { condition }; - - var metric = TestHelpers.CreateTestMetric(company, eventSubtype, condition.MetricPeriod!.Value, 5); - company.Metrics = new List { metric }; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.True); - } - - [Test] - public async Task Rule_DoesNotMatch_When_Metric_Exceeds_Limit() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - var company = TestHelpers.CreateTestCompany(); - - string eventSubtype = "test-event"; - var rule = TestHelpers.CreateTestRule(); - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Metric); - condition.EventSubtype = eventSubtype; - condition.MetricValue = 5; - condition.Operator = ComparableOperator.Lte; - rule.Conditions = new List { condition }; - - var metric = TestHelpers.CreateTestMetric(company, eventSubtype, condition.MetricPeriod!.Value, 6); // Value exceeds limit - company.Metrics = new List { metric }; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.False); - } - - [Test] - public async Task Trait_Evaluation_MatchesWhenValueMatches() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - var company = TestHelpers.CreateTestCompany(); - var trait = TestHelpers.CreateTestTrait("test-value", null); - company.Traits = new List { trait }; - - var rule = TestHelpers.CreateTestRule(); - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Trait); - condition.TraitDefinition = trait.TraitDefinition; - condition.TraitValue = "test-value"; - condition.Operator = ComparableOperator.Eq; - rule.Conditions = new List { condition }; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.True); - } - - [Test] - public async Task ConditionGroup_Matches_When_Any_Condition_Matches() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - var company = TestHelpers.CreateTestCompany(); - - var rule = TestHelpers.CreateTestRule(); - var condition1 = TestHelpers.CreateTestCondition(RulesengineConditionType.Company); - var condition2 = TestHelpers.CreateTestCondition(RulesengineConditionType.Company); - condition2.ResourceIds = new List { company.Id }; - - var group = new RulesengineConditionGroup - { - Conditions = new List { condition1, condition2 } - }; - rule.ConditionGroups = new List { group }; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.True); - } - - [Test] - public async Task ConditionGroup_DoesNotMatch_When_No_Conditions_Match() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - var company = TestHelpers.CreateTestCompany(); - - var rule = TestHelpers.CreateTestRule(); - var condition1 = TestHelpers.CreateTestCondition(RulesengineConditionType.Company); - var condition2 = TestHelpers.CreateTestCondition(RulesengineConditionType.Company); - // No matching condition added to the group - - var group = new RulesengineConditionGroup - { - Conditions = new List { condition1, condition2 } - }; - rule.ConditionGroups = new List { group }; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.False); - } - - [Test] - public async Task User_Trait_Evaluation() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - var user = TestHelpers.CreateTestUser(); - var traitDef = TestHelpers.CreateTestTraitDefinition(RulesengineTraitDefinitionComparableType.String, RulesengineEntityType.User); - var trait = TestHelpers.CreateTestTrait("user-trait-value", traitDef); - user.Traits = new List { trait }; - - var rule = TestHelpers.CreateTestRule(); - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Trait); - condition.TraitDefinition = traitDef; - condition.TraitValue = "user-trait-value"; - condition.Operator = ComparableOperator.Eq; - rule.Conditions = new List { condition }; - - // Act - var result = await svc.Check(new CheckScope - { - User = user, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.True); - } - - [Test] - public async Task Multiple_Conditions_All_Must_Match() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - var company = TestHelpers.CreateTestCompany(); - var trait = TestHelpers.CreateTestTrait("test-value", null); - company.Traits = new List { trait }; - - var rule = TestHelpers.CreateTestRule(); - - // Company condition - var condition1 = TestHelpers.CreateTestCondition(RulesengineConditionType.Company); - condition1.ResourceIds = new List { company.Id }; - - // Trait condition - var condition2 = TestHelpers.CreateTestCondition(RulesengineConditionType.Trait); - condition2.TraitDefinition = trait.TraitDefinition; - condition2.TraitValue = "test-value"; - condition2.Operator = ComparableOperator.Eq; - - rule.Conditions = new List { condition1, condition2 }; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.True); - } - - [Test] - public async Task Multiple_Conditions_Fail_If_Any_Does_Not_Match() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - var company = TestHelpers.CreateTestCompany(); - var trait = TestHelpers.CreateTestTrait("test-value", null); - company.Traits = new List { trait }; - - var rule = TestHelpers.CreateTestRule(); - - // Company condition - var condition1 = TestHelpers.CreateTestCondition(RulesengineConditionType.Company); - condition1.ResourceIds = new List { company.Id }; - - // Trait condition that doesn't match - var condition2 = TestHelpers.CreateTestCondition(RulesengineConditionType.Trait); - condition2.TraitDefinition = trait.TraitDefinition; - condition2.TraitValue = "different-value"; - condition2.Operator = ComparableOperator.Eq; - - rule.Conditions = new List { condition1, condition2 }; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.False); - } - - [Test] - public async Task Rule_Matches_WithSufficientCreditBalance() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - - // Create a company with a credit balance - var company = TestHelpers.CreateTestCompany(); - var creditId = "test-credit-id"; - company.CreditBalances = new Dictionary - { - { creditId, 100.0 } // Set a credit balance of 100.0 - }; - - // Create a rule with a credit condition - var rule = TestHelpers.CreateTestRule(); - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Credit); - condition.CreditId = creditId; - condition.ConsumptionRate = 50.0; // Consumption rate less than the balance - rule.Conditions = new List { condition }; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.True); - } - - [Test] - public async Task Rule_DoesNotMatch_WithInsufficientCreditBalance() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - - // Create a company with a credit balance - var company = TestHelpers.CreateTestCompany(); - var creditId = "test-credit-id"; - company.CreditBalances = new Dictionary - { - { creditId, 20.0 } // Set a credit balance of 20.0 - }; - - // Create a rule with a credit condition - var rule = TestHelpers.CreateTestRule(); - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Credit); - condition.CreditId = creditId; - condition.ConsumptionRate = 50.0; // Consumption rate more than the balance - rule.Conditions = new List { condition }; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.False); - } - - [Test] - public async Task Rule_Matches_WithDefaultConsumptionRate() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - - // Create a company with a credit balance - var company = TestHelpers.CreateTestCompany(); - var creditId = "test-credit-id"; - company.CreditBalances = new Dictionary - { - { creditId, 2.0 } // Set a credit balance of 2.0 - }; - - // Create a rule with a credit condition - var rule = TestHelpers.CreateTestRule(); - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Credit); - condition.CreditId = creditId; - condition.ConsumptionRate = null; // Default consumption rate is 1.0 - rule.Conditions = new List { condition }; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.True); - } - - [Test] - public async Task Rule_DoesNotMatch_WithNonExistentCreditId() - { - // Arrange - var svc = RuleCheckService.NewRuleCheckService(); - - // Create a company with a credit balance - var company = TestHelpers.CreateTestCompany(); - company.CreditBalances = new Dictionary - { - { "existing-credit-id", 100.0 } - }; - - // Create a rule with a credit condition for a different credit ID - var rule = TestHelpers.CreateTestRule(); - var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Credit); - condition.CreditId = "non-existent-credit-id"; // Different from the one in company - condition.ConsumptionRate = 1.0; - rule.Conditions = new List { condition }; - - // Act - var result = await svc.Check(new CheckScope - { - Company = company, - Rule = rule - }); - - // Assert - Assert.That(result, Is.Not.Null); - Assert.That(result.Match, Is.False); - } - } -} diff --git a/src/SchematicHQ.Client.Test/RulesEngine/FlagCheckTests.cs b/src/SchematicHQ.Client.Test/RulesEngine/Wasm/WasmFlagCheckParityTests.cs similarity index 73% rename from src/SchematicHQ.Client.Test/RulesEngine/FlagCheckTests.cs rename to src/SchematicHQ.Client.Test/RulesEngine/Wasm/WasmFlagCheckParityTests.cs index 36574a9c..e7cc6f0a 100644 --- a/src/SchematicHQ.Client.Test/RulesEngine/FlagCheckTests.cs +++ b/src/SchematicHQ.Client.Test/RulesEngine/Wasm/WasmFlagCheckParityTests.cs @@ -1,80 +1,79 @@ -using SchematicHQ.Client.RulesEngine.Utils; -using SchematicHQ.Client.RulesEngine; +using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; +using SchematicHQ.Client; +using SchematicHQ.Client.RulesEngine; -namespace SchematicHQ.Client.Test.RulesEngine +namespace SchematicHQ.Client.Test.RulesEngine.Wasm { + /// + /// Behavioral parity coverage for the WASM rules engine, ported from the former native + /// FlagCheckService unit tests. Each case drives + /// and asserts the same evaluation outcomes (value, matched rule, entitlement usage / + /// allocation) the native C# port produced — the regression guard the migration needs. + /// + /// Native-only reason strings (e.g. "No rules matched") are not asserted here; the + /// WASM engine emits its own reasons, so these tests assert on Value/RuleId + /// (a null RuleId means no rule matched → flag default). + /// [TestFixture] - public class FlagCheckServiceTests + public class WasmFlagCheckParityTests { - [Test] - public async Task Returns_ErrorResult_WhenFlagIsNil() - { - // Arrange - var company = TestHelpers.CreateTestCompany(); + private WasmRulesEngine _engine = null!; - // Act - var result = await FlagCheckService.CheckFlag(company, null, null); - - // Assert - Assert.That(result.Reason, Is.EqualTo(FlagCheckService.ReasonFlagNotFound)); - Assert.That(result.Error, Is.EqualTo(Errors.ErrorFlagNotFound)); + [OneTimeSetUp] + public void SetUp() + { + _engine = new WasmRulesEngine(NullLogger.Instance); + _engine.Initialize(); } + [OneTimeTearDown] + public void TearDown() => _engine.Dispose(); + [Test] - public async Task Returns_DefaultValue_WhenNoRulesMatch() + public void Returns_DefaultValue_WhenNoRulesMatch() { - // Arrange var company = TestHelpers.CreateTestCompany(); var flag = TestHelpers.CreateTestFlag(); flag.DefaultValue = true; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert - Assert.That(result.Reason, Is.EqualTo(FlagCheckService.ReasonNoRulesMatched)); Assert.That(result.Value, Is.True); Assert.That(result.CompanyId, Is.EqualTo(company.Id)); + Assert.That(result.RuleId, Is.Null); } [Test] - public async Task GlobalOverride_TakesPrecedence() + public void GlobalOverride_TakesPrecedence() { - // Arrange var company = TestHelpers.CreateTestCompany(); var flag = TestHelpers.CreateTestFlag(); - // Create a standard rule that matches var standardRule = TestHelpers.CreateTestRule(); standardRule.Value = false; var standardCondition = TestHelpers.CreateTestCondition(RulesengineConditionType.Company); standardCondition.ResourceIds = new List { company.Id }; standardRule.Conditions = new List { standardCondition }; - // Create a global override rule var overrideRule = TestHelpers.CreateTestRule(); overrideRule.RuleType = RulesengineRuleType.GlobalOverride; overrideRule.Value = true; flag.Rules = new List { standardRule, overrideRule }; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(overrideRule.Id)); } [Test] - public async Task Rules_Evaluated_In_Priority_Order() + public void Rules_Evaluated_In_Priority_Order() { - // Arrange var company = TestHelpers.CreateTestCompany(); var flag = TestHelpers.CreateTestFlag(); - // Create two matching rules with different priorities var rule1 = TestHelpers.CreateTestRule(); rule1.Priority = 2; rule1.Value = false; @@ -91,25 +90,21 @@ public async Task Rules_Evaluated_In_Priority_Order() flag.Rules = new List { rule1, rule2 }; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(rule2.Id)); } [Test] - public async Task Condition_Group_Matches_When_Any_Condition_Matches() + public void Condition_Group_Matches_When_Any_Condition_Matches() { - // Arrange var company = TestHelpers.CreateTestCompany(); var flag = TestHelpers.CreateTestFlag(); var rule = TestHelpers.CreateTestRule(); rule.Value = true; - // Create condition group with two conditions var condition1 = TestHelpers.CreateTestCondition(RulesengineConditionType.Company); condition1.ResourceIds = new List { "non-matching-id" }; @@ -124,23 +119,19 @@ public async Task Condition_Group_Matches_When_Any_Condition_Matches() rule.ConditionGroups = new List { group }; flag.Rules = new List { rule }; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(rule.Id)); } [Test] - public async Task Sets_Usage_And_Allocation_For_Metric_Condition() + public void Sets_Usage_And_Allocation_For_Metric_Condition() { - // Arrange var company = TestHelpers.CreateTestCompany(); var flag = TestHelpers.CreateTestFlag(); - // Create entitlement rule with metric condition - string eventSubtype = "test-event"; + const string eventSubtype = "test-event"; var rule = TestHelpers.CreateTestRule(); rule.RuleType = RulesengineRuleType.PlanEntitlement; rule.Value = true; @@ -153,35 +144,27 @@ public async Task Sets_Usage_And_Allocation_For_Metric_Condition() rule.Conditions = new List { condition }; flag.Rules = new List { rule }; - // Create company metric var metric = TestHelpers.CreateTestMetric(company, eventSubtype, condition.MetricPeriod!.Value, 5); company.Metrics = new List { metric }; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(rule.Id)); - Assert.That(result.FeatureUsage, Is.Not.Null); Assert.That(result.FeatureUsage, Is.EqualTo(5)); - Assert.That(result.FeatureAllocation, Is.Not.Null); Assert.That(result.FeatureAllocation, Is.EqualTo(10)); } [Test] - public async Task Sets_Usage_And_Allocation_For_Trait_Condition() + public void Sets_Usage_And_Allocation_For_Trait_Condition() { - // Arrange var company = TestHelpers.CreateTestCompany(); var flag = TestHelpers.CreateTestFlag(); - // Create trait var traitDef = TestHelpers.CreateTestTraitDefinition(RulesengineTraitDefinitionComparableType.Int, RulesengineEntityType.Company); var trait = TestHelpers.CreateTestTrait("5", traitDef); company.Traits = new List { trait }; - // Create entitlement rule with trait condition var rule = TestHelpers.CreateTestRule(); rule.RuleType = RulesengineRuleType.PlanEntitlement; rule.Value = true; @@ -194,23 +177,17 @@ public async Task Sets_Usage_And_Allocation_For_Trait_Condition() rule.Conditions = new List { condition }; flag.Rules = new List { rule }; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(rule.Id)); - Assert.That(result.FeatureUsage, Is.Not.Null); Assert.That(result.FeatureUsage, Is.EqualTo(5)); - Assert.That(result.FeatureAllocation, Is.Not.Null); Assert.That(result.FeatureAllocation, Is.EqualTo(10)); } - [Test] - public async Task Matches_User_Specific_Conditions() + public void Matches_User_Specific_Conditions() { - // Arrange var user = TestHelpers.CreateTestUser(); var flag = TestHelpers.CreateTestFlag(); @@ -222,19 +199,16 @@ public async Task Matches_User_Specific_Conditions() flag.Rules = new List { rule }; - // Act - var result = await FlagCheckService.CheckFlag(null, user, flag); + var result = _engine.CheckFlag(null, user, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.UserId, Is.EqualTo(user.Id)); Assert.That(result.RuleId, Is.EqualTo(rule.Id)); } [Test] - public async Task Checks_User_Traits() + public void Checks_User_Traits() { - // Arrange var user = TestHelpers.CreateTestUser(); var traitDef = TestHelpers.CreateTestTraitDefinition(RulesengineTraitDefinitionComparableType.String, RulesengineEntityType.User); var trait = TestHelpers.CreateTestTrait("test-value", traitDef); @@ -252,18 +226,15 @@ public async Task Checks_User_Traits() rule.Conditions = new List { condition }; flag.Rules = new List { rule }; - // Act - var result = await FlagCheckService.CheckFlag(null, user, flag); + var result = _engine.CheckFlag(null, user, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(rule.Id)); } [Test] - public async Task Handles_Multiple_Condition_Types_And_Groups() + public void Handles_Multiple_Condition_Types_And_Groups() { - // Arrange var company = TestHelpers.CreateTestCompany(); var trait = TestHelpers.CreateTestTrait("test-value", null); company.Traits = new List { trait }; @@ -272,7 +243,6 @@ public async Task Handles_Multiple_Condition_Types_And_Groups() var rule = TestHelpers.CreateTestRule(); rule.Value = true; - // Add direct conditions var condition1 = TestHelpers.CreateTestCondition(RulesengineConditionType.Company); condition1.ResourceIds = new List { company.Id }; @@ -283,7 +253,6 @@ public async Task Handles_Multiple_Condition_Types_And_Groups() rule.Conditions = new List { condition1, condition2 }; - // Add condition group var groupCondition1 = TestHelpers.CreateTestCondition(RulesengineConditionType.Plan); groupCondition1.ResourceIds = new List { company.PlanIds.First() }; @@ -301,23 +270,19 @@ public async Task Handles_Multiple_Condition_Types_And_Groups() rule.ConditionGroups = new List { group }; flag.Rules = new List { rule }; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(rule.Id)); } [Test] - public async Task Handles_Missing_Or_Invalid_Data_Gracefully() + public void Handles_Missing_Or_Invalid_Data_Gracefully() { - // Arrange var company = TestHelpers.CreateTestCompany(); var flag = TestHelpers.CreateTestFlag(); var rule = TestHelpers.CreateTestRule(); - // Add condition with null fields var condition = new RulesengineCondition { Id = "", @@ -329,29 +294,24 @@ public async Task Handles_Missing_Or_Invalid_Data_Gracefully() }; rule.Conditions = new List { condition }; - // Add empty condition group var group = new RulesengineConditionGroup(); rule.ConditionGroups = new List { group }; flag.Rules = new List { rule }; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert Assert.That(result.Value, Is.EqualTo(flag.DefaultValue)); - Assert.That(result.Reason, Is.EqualTo(FlagCheckService.ReasonNoRulesMatched)); + Assert.That(result.RuleId, Is.Null); } [Test] - public async Task CompanyProvidedRule_IsEvaluatedAlongWithFlagRules() + public void CompanyProvidedRule_IsEvaluatedAlongWithFlagRules() { - // Arrange var company = TestHelpers.CreateTestCompany(); var flag = TestHelpers.CreateTestFlag(); flag.DefaultValue = false; - // Create a company-provided rule that matches var companyRule = TestHelpers.CreateTestRule(); companyRule.FlagId = flag.Id; companyRule.Value = true; @@ -361,22 +321,18 @@ public async Task CompanyProvidedRule_IsEvaluatedAlongWithFlagRules() company.Rules = new List { companyRule }; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(companyRule.Id)); } [Test] - public async Task CompanyProvidedRule_RespectsPriorityOrdering() + public void CompanyProvidedRule_RespectsPriorityOrdering() { - // Arrange var company = TestHelpers.CreateTestCompany(); var flag = TestHelpers.CreateTestFlag(); - // Create flag rule with lower priority var flagRule = TestHelpers.CreateTestRule(); flagRule.Priority = 2; flagRule.Value = false; @@ -384,7 +340,6 @@ public async Task CompanyProvidedRule_RespectsPriorityOrdering() condition1.ResourceIds = new List { company.Id }; flagRule.Conditions = new List { condition1 }; - // Create company rule with higher priority var companyRule = TestHelpers.CreateTestRule(); companyRule.FlagId = flag.Id; companyRule.Priority = 1; @@ -396,29 +351,24 @@ public async Task CompanyProvidedRule_RespectsPriorityOrdering() flag.Rules = new List { flagRule }; company.Rules = new List { companyRule }; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(companyRule.Id)); } [Test] - public async Task CompanyProvidedRule_WithGlobalOverrideTakesPrecedence() + public void CompanyProvidedRule_WithGlobalOverrideTakesPrecedence() { - // Arrange var company = TestHelpers.CreateTestCompany(); var flag = TestHelpers.CreateTestFlag(); - // Create standard flag rule var flagRule = TestHelpers.CreateTestRule(); flagRule.Value = false; var condition1 = TestHelpers.CreateTestCondition(RulesengineConditionType.Company); condition1.ResourceIds = new List { company.Id }; flagRule.Conditions = new List { condition1 }; - // Create company rule with global override var companyRule = TestHelpers.CreateTestRule(); companyRule.FlagId = flag.Id; companyRule.RuleType = RulesengineRuleType.GlobalOverride; @@ -427,23 +377,19 @@ public async Task CompanyProvidedRule_WithGlobalOverrideTakesPrecedence() flag.Rules = new List { flagRule }; company.Rules = new List { companyRule }; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(companyRule.Id)); } [Test] - public async Task MultipleCompanyProvidedRules_AreAllEvaluated() + public void MultipleCompanyProvidedRules_AreAllEvaluated() { - // Arrange var company = TestHelpers.CreateTestCompany(); var flag = TestHelpers.CreateTestFlag(); flag.DefaultValue = false; - // Create two company rules, only one matches var companyRule1 = TestHelpers.CreateTestRule(); companyRule1.FlagId = flag.Id; companyRule1.Priority = 1; @@ -462,23 +408,19 @@ public async Task MultipleCompanyProvidedRules_AreAllEvaluated() company.Rules = new List { companyRule1, companyRule2 }; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(companyRule2.Id)); } [Test] - public async Task UserProvidedRule_IsEvaluatedAlongWithFlagRules() + public void UserProvidedRule_IsEvaluatedAlongWithFlagRules() { - // Arrange var user = TestHelpers.CreateTestUser(); var flag = TestHelpers.CreateTestFlag(); flag.DefaultValue = false; - // Create a user-provided rule that matches var userRule = TestHelpers.CreateTestRule(); userRule.FlagId = flag.Id; userRule.Value = true; @@ -488,22 +430,18 @@ public async Task UserProvidedRule_IsEvaluatedAlongWithFlagRules() user.Rules = new List { userRule }; - // Act - var result = await FlagCheckService.CheckFlag(null, user, flag); + var result = _engine.CheckFlag(null, user, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(userRule.Id)); } [Test] - public async Task UserProvidedRule_RespectsPriorityOrdering() + public void UserProvidedRule_RespectsPriorityOrdering() { - // Arrange var user = TestHelpers.CreateTestUser(); var flag = TestHelpers.CreateTestFlag(); - // Create flag rule with lower priority var flagRule = TestHelpers.CreateTestRule(); flagRule.Priority = 2; flagRule.Value = false; @@ -511,7 +449,6 @@ public async Task UserProvidedRule_RespectsPriorityOrdering() condition1.ResourceIds = new List { user.Id }; flagRule.Conditions = new List { condition1 }; - // Create user rule with higher priority var userRule = TestHelpers.CreateTestRule(); userRule.FlagId = flag.Id; userRule.Priority = 1; @@ -523,29 +460,24 @@ public async Task UserProvidedRule_RespectsPriorityOrdering() flag.Rules = new List { flagRule }; user.Rules = new List { userRule }; - // Act - var result = await FlagCheckService.CheckFlag(null, user, flag); + var result = _engine.CheckFlag(null, user, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(userRule.Id)); } [Test] - public async Task UserProvidedRule_WithGlobalOverrideTakesPrecedence() + public void UserProvidedRule_WithGlobalOverrideTakesPrecedence() { - // Arrange var user = TestHelpers.CreateTestUser(); var flag = TestHelpers.CreateTestFlag(); - // Create standard flag rule var flagRule = TestHelpers.CreateTestRule(); flagRule.Value = false; var condition1 = TestHelpers.CreateTestCondition(RulesengineConditionType.User); condition1.ResourceIds = new List { user.Id }; flagRule.Conditions = new List { condition1 }; - // Create user rule with global override var userRule = TestHelpers.CreateTestRule(); userRule.FlagId = flag.Id; userRule.RuleType = RulesengineRuleType.GlobalOverride; @@ -554,24 +486,20 @@ public async Task UserProvidedRule_WithGlobalOverrideTakesPrecedence() flag.Rules = new List { flagRule }; user.Rules = new List { userRule }; - // Act - var result = await FlagCheckService.CheckFlag(null, user, flag); + var result = _engine.CheckFlag(null, user, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(userRule.Id)); } [Test] - public async Task BothCompanyAndUserRules_AreEvaluated() + public void BothCompanyAndUserRules_AreEvaluated() { - // Arrange var company = TestHelpers.CreateTestCompany(); var user = TestHelpers.CreateTestUser(); var flag = TestHelpers.CreateTestFlag(); flag.DefaultValue = false; - // Create company rule that doesn't match var companyRule = TestHelpers.CreateTestRule(); companyRule.FlagId = flag.Id; companyRule.Priority = 1; @@ -580,7 +508,6 @@ public async Task BothCompanyAndUserRules_AreEvaluated() condition1.ResourceIds = new List { "non-matching-id" }; companyRule.Conditions = new List { condition1 }; - // Create user rule that matches var userRule = TestHelpers.CreateTestRule(); userRule.FlagId = flag.Id; userRule.Priority = 2; @@ -592,24 +519,20 @@ public async Task BothCompanyAndUserRules_AreEvaluated() company.Rules = new List { companyRule }; user.Rules = new List { userRule }; - // Act - var result = await FlagCheckService.CheckFlag(company, user, flag); + var result = _engine.CheckFlag(company, user, flag); - // Assert Assert.That(result.Value, Is.True); Assert.That(result.RuleId, Is.EqualTo(userRule.Id)); } [Test] - public async Task AllThreeRuleSources_EvaluatedWithCorrectPriority() + public void AllThreeRuleSources_EvaluatedWithCorrectPriority() { - // Arrange var company = TestHelpers.CreateTestCompany(); var user = TestHelpers.CreateTestUser(); var flag = TestHelpers.CreateTestFlag(); flag.DefaultValue = false; - // Create rules from all three sources - all matching their respective conditions var flagRule = TestHelpers.CreateTestRule(); flagRule.Priority = 2; flagRule.Value = true; @@ -637,25 +560,19 @@ public async Task AllThreeRuleSources_EvaluatedWithCorrectPriority() company.Rules = new List { companyRule }; user.Rules = new List { userRule }; - // Act - var result = await FlagCheckService.CheckFlag(company, user, flag); + var result = _engine.CheckFlag(company, user, flag); - // Assert Assert.That(result.Value, Is.True); - Assert.That(result.RuleId, Is.Not.Null); - // Should match the user rule since it has highest priority (lowest number) - Assert.That(result.RuleId, Is.EqualTo(userRule.Id)); + Assert.That(result.RuleId, Is.EqualTo(userRule.Id)); // user rule has highest priority } [Test] - public async Task CompanyProvidedRule_WithWrongFlagId_IsNotEvaluated() + public void CompanyProvidedRule_WithWrongFlagId_IsNotEvaluated() { - // Arrange var company = TestHelpers.CreateTestCompany(); var flag = TestHelpers.CreateTestFlag(); flag.DefaultValue = false; - // Create a company-provided rule for a different flag var companyRule = TestHelpers.CreateTestRule(); companyRule.FlagId = TestHelpers.GenerateTestId("flag"); // Different flag ID companyRule.Value = true; @@ -665,23 +582,19 @@ public async Task CompanyProvidedRule_WithWrongFlagId_IsNotEvaluated() company.Rules = new List { companyRule }; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert - Assert.That(result.Value, Is.False); // Should use flag's default value - Assert.That(result.Reason, Is.EqualTo(FlagCheckService.ReasonNoRulesMatched)); + Assert.That(result.Value, Is.False); // flag default + Assert.That(result.RuleId, Is.Null); } [Test] - public async Task UserProvidedRule_WithWrongFlagId_IsNotEvaluated() + public void UserProvidedRule_WithWrongFlagId_IsNotEvaluated() { - // Arrange var user = TestHelpers.CreateTestUser(); var flag = TestHelpers.CreateTestFlag(); flag.DefaultValue = false; - // Create a user-provided rule for a different flag var userRule = TestHelpers.CreateTestRule(); userRule.FlagId = TestHelpers.GenerateTestId("flag"); // Different flag ID userRule.Value = true; @@ -691,23 +604,19 @@ public async Task UserProvidedRule_WithWrongFlagId_IsNotEvaluated() user.Rules = new List { userRule }; - // Act - var result = await FlagCheckService.CheckFlag(null, user, flag); + var result = _engine.CheckFlag(null, user, flag); - // Assert - Assert.That(result.Value, Is.False); // Should use flag's default value - Assert.That(result.Reason, Is.EqualTo(FlagCheckService.ReasonNoRulesMatched)); + Assert.That(result.Value, Is.False); // flag default + Assert.That(result.RuleId, Is.Null); } [Test] - public async Task CompanyProvidedRule_WithNullFlagId_IsNotEvaluated() + public void CompanyProvidedRule_WithNullFlagId_IsNotEvaluated() { - // Arrange var company = TestHelpers.CreateTestCompany(); var flag = TestHelpers.CreateTestFlag(); flag.DefaultValue = false; - // Create a company-provided rule with null FlagId var companyRule = TestHelpers.CreateTestRule(); companyRule.FlagId = null; companyRule.Value = true; @@ -717,23 +626,19 @@ public async Task CompanyProvidedRule_WithNullFlagId_IsNotEvaluated() company.Rules = new List { companyRule }; - // Act - var result = await FlagCheckService.CheckFlag(company, null, flag); + var result = _engine.CheckFlag(company, null, flag); - // Assert - Assert.That(result.Value, Is.False); // Should use flag's default value - Assert.That(result.Reason, Is.EqualTo(FlagCheckService.ReasonNoRulesMatched)); + Assert.That(result.Value, Is.False); // flag default + Assert.That(result.RuleId, Is.Null); } [Test] - public async Task UserProvidedRule_WithNullFlagId_IsNotEvaluated() + public void UserProvidedRule_WithNullFlagId_IsNotEvaluated() { - // Arrange var user = TestHelpers.CreateTestUser(); var flag = TestHelpers.CreateTestFlag(); flag.DefaultValue = false; - // Create a user-provided rule with null FlagId var userRule = TestHelpers.CreateTestRule(); userRule.FlagId = null; userRule.Value = true; @@ -743,12 +648,10 @@ public async Task UserProvidedRule_WithNullFlagId_IsNotEvaluated() user.Rules = new List { userRule }; - // Act - var result = await FlagCheckService.CheckFlag(null, user, flag); + var result = _engine.CheckFlag(null, user, flag); - // Assert - Assert.That(result.Value, Is.False); // Should use flag's default value - Assert.That(result.Reason, Is.EqualTo(FlagCheckService.ReasonNoRulesMatched)); + Assert.That(result.Value, Is.False); // flag default + Assert.That(result.RuleId, Is.Null); } } } diff --git a/src/SchematicHQ.Client.Test/RulesEngine/Wasm/WasmRulesEngineTests.cs b/src/SchematicHQ.Client.Test/RulesEngine/Wasm/WasmRulesEngineTests.cs new file mode 100644 index 00000000..ce7d7a87 --- /dev/null +++ b/src/SchematicHQ.Client.Test/RulesEngine/Wasm/WasmRulesEngineTests.cs @@ -0,0 +1,69 @@ +using Microsoft.Extensions.Logging.Abstractions; +using NUnit.Framework; +using SchematicHQ.Client; +using SchematicHQ.Client.RulesEngine; + +namespace SchematicHQ.Client.Test.RulesEngine.Wasm +{ + /// + /// Regression coverage for the WASM rules engine that replaced the native C# port. + /// Asserts parity with the previous native results (value + entitlement fields) and + /// that feature_usage_reset_at is populated on the clockless wasmtime host (SCHY-471). + /// + [TestFixture] + public class WasmRulesEngineTests + { + private WasmRulesEngine _engine = null!; + + [OneTimeSetUp] + public void SetUp() + { + _engine = new WasmRulesEngine(NullLogger.Instance); + _engine.Initialize(); + } + + [OneTimeTearDown] + public void TearDown() => _engine.Dispose(); + + [Test] + public void Initializes_And_Exposes_Version_Key() + { + Assert.That(_engine.IsInitialized, Is.True); + Assert.That(_engine.GetVersionKey(), Is.Not.Empty); + } + + [Test] + public void Bounded_Metric_Period_Populates_Reset_At() + { + // SCHY-471: with setCurrentTimeMillis wired, a calendar metric period must + // populate feature_usage_reset_at (rather than trapping / omitting it). + var company = TestHelpers.CreateTestCompany(); + var flag = TestHelpers.CreateTestFlag(); + flag.DefaultValue = false; + + const string eventSubtype = "monthly-event"; + var rule = TestHelpers.CreateTestRule(); + rule.RuleType = RulesengineRuleType.PlanEntitlement; + rule.Value = true; + + var condition = TestHelpers.CreateTestCondition(RulesengineConditionType.Metric); + condition.EventSubtype = eventSubtype; + condition.MetricValue = 10; + condition.Operator = ComparableOperator.Lte; + condition.MetricPeriod = RulesengineMetricPeriod.CurrentMonth; + rule.Conditions = new List { condition }; + flag.Rules = new List { rule }; + + company.Metrics = new List + { + TestHelpers.CreateTestMetric(company, eventSubtype, RulesengineMetricPeriod.CurrentMonth, 5), + }; + + var result = _engine.CheckFlag(company, null, flag); + + Assert.That(result.Value, Is.True); + Assert.That(result.FeatureUsageResetAt, Is.Not.Null); + Assert.That(result.FeatureUsageResetAt, Is.GreaterThan(DateTime.UtcNow)); + } + } +} diff --git a/src/SchematicHQ.Client/Cache/ComparableTypeConverter.cs b/src/SchematicHQ.Client/Cache/ComparableTypeConverter.cs deleted file mode 100644 index fc977843..00000000 --- a/src/SchematicHQ.Client/Cache/ComparableTypeConverter.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Text.Json; -using System.Text.Json.Serialization; -using SchematicHQ.Client.RulesEngine.Utils; - -namespace SchematicHQ.Client.Cache -{ - public class ComparableTypeConverter : JsonConverter - { - public override ComparableType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var value = reader.GetString(); - - return value switch - { - "" or null => ComparableType.Unknown, - "string" => ComparableType.String, - "int" => ComparableType.Int, - "bool" => ComparableType.Bool, - "date" => ComparableType.Date, - _ => ComparableType.Unknown - }; - } - - public override void Write(Utf8JsonWriter writer, ComparableType value, JsonSerializerOptions options) - { - var stringValue = value switch - { - ComparableType.Unknown => "", - ComparableType.String => "string", - ComparableType.Int => "int", - ComparableType.Bool => "bool", - ComparableType.Date => "date", - _ => "" - }; - - writer.WriteStringValue(stringValue); - } - } -} \ No newline at end of file diff --git a/src/SchematicHQ.Client/Cache/SchematicCacheSerializerDefaults.cs b/src/SchematicHQ.Client/Cache/SchematicCacheSerializerDefaults.cs index 9ed526e0..3996fb92 100644 --- a/src/SchematicHQ.Client/Cache/SchematicCacheSerializerDefaults.cs +++ b/src/SchematicHQ.Client/Cache/SchematicCacheSerializerDefaults.cs @@ -10,8 +10,7 @@ public static class SchematicCacheSerializerDefaults PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, Converters = { - new ComparableTypeConverter(), // Specific handler for ComparableType empty strings - new ResilientEnumConverter() // Fallback for all other enums + new ResilientEnumConverter() // Fallback for all enums } }; } \ No newline at end of file diff --git a/src/SchematicHQ.Client/Datastream/Client.cs b/src/SchematicHQ.Client/Datastream/Client.cs index c0c8af2b..c4dde7d5 100644 --- a/src/SchematicHQ.Client/Datastream/Client.cs +++ b/src/SchematicHQ.Client/Datastream/Client.cs @@ -22,6 +22,11 @@ public class DatastreamClient : IDisposable private readonly TimeSpan _cacheTtl; private readonly Action _connectionStateCallback; private IWebSocketClient _webSocket; + + // Local flag evaluator (shared Rust rules engine, hosted via WASM). Null when + // initialization failed, in which case flag checks fall back to the flag default. + private readonly WasmRulesEngine? _rulesEngine; + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private readonly SemaphoreSlim _reconnectSemaphore = new SemaphoreSlim(1, 1); private CancellationTokenSource _readCancellationSource = new CancellationTokenSource(); @@ -64,6 +69,11 @@ public class DatastreamClient : IDisposable // Authentication error close code private const int AuthErrorCloseCode = 4001; + // Reasons returned when the WASM rules engine cannot evaluate a flag; the flag's + // default value is returned in both cases (matching schematic-java's semantics). + private const string ReasonRulesEngineUnavailable = "RULES_ENGINE_UNAVAILABLE"; + private const string ReasonRulesEngineError = "RULES_ENGINE_ERROR"; + // Handshake headers attached to the WebSocket connection so the backend can // distinguish direct-SDK connections from the schematic-datastream-replicator // and correlate either to a specific release. Mode is always "direct" here — @@ -115,6 +125,20 @@ public DatastreamClient( _flagsCache = new DatastreamCacheDecorator(cacheProvider, flagTTL); _webSocket = webSocket ?? new StandardWebSocketClient(); + + // Initialize the WASM rules engine. On failure, degrade gracefully: flag + // checks return the flag's default value rather than throwing. + try + { + var rulesEngine = new WasmRulesEngine(_logger); + rulesEngine.Initialize(); + _rulesEngine = rulesEngine; + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to initialize WASM rules engine; flag checks will return default values"); + _rulesEngine = null; + } } public void Start() @@ -840,23 +864,40 @@ private void HandleErrorMessage(DataStreamResponse response) } } - internal async Task CheckFlag(RulesengineCompany? company, RulesengineUser? user, RulesengineFlag flag, CancellationToken cancellationToken = default) + internal Task CheckFlag(RulesengineCompany? company, RulesengineUser? user, RulesengineFlag flag, CancellationToken cancellationToken = default) { + if (_rulesEngine == null || !_rulesEngine.IsInitialized) + { + _logger.LogWarning("WASM rules engine unavailable; returning default value for flag {FlagKey}", flag.Key); + return Task.FromResult(new CheckFlagResult + { + Reason = ReasonRulesEngineUnavailable, + FlagKey = flag.Key, + FlagId = flag.Id, + Value = flag.DefaultValue, + CompanyId = company?.Id, + UserId = user?.Id, + }); + } + try { - var result = await FlagCheckService.CheckFlag(company, user, flag); - return result; + var result = _rulesEngine.CheckFlag(company, user, flag); + return Task.FromResult(result); } catch (Exception ex) { _logger.LogError(ex, "Error checking flag {FlagKey}", flag.Key); - return new CheckFlagResult + return Task.FromResult(new CheckFlagResult { - Reason = "Error", + Reason = ReasonRulesEngineError, FlagKey = flag.Key, + FlagId = flag.Id, Error = ex, - Value = false, - }; + Value = flag.DefaultValue, + CompanyId = company?.Id, + UserId = user?.Id, + }); } } @@ -1516,6 +1557,9 @@ public void Dispose() lockEntry.Value.Dispose(); } _companyUpdateLocks.Clear(); + + // Release the WASM rules engine's native Wasmtime resources. + _rulesEngine?.Dispose(); } } } diff --git a/src/SchematicHQ.Client/RulesEngine/CheckFlagResult.cs b/src/SchematicHQ.Client/RulesEngine/CheckFlagResult.cs new file mode 100644 index 00000000..76baea83 --- /dev/null +++ b/src/SchematicHQ.Client/RulesEngine/CheckFlagResult.cs @@ -0,0 +1,29 @@ +namespace SchematicHQ.Client.RulesEngine +{ + /// + /// Result of a local flag evaluation, returned by the datastream client. + /// + /// Retained for backward compatibility. Internally the WASM rules engine produces the + /// generated , which is mapped onto this type at the + /// engine boundary. (The former native-only SetRuleFields helper was removed with the + /// native port; the WASM engine populates the entitlement fields directly.) + /// + public class CheckFlagResult + { + public string? CompanyId { get; set; } + public RulesengineFeatureEntitlement? Entitlement { get; set; } + public Exception? Error { get; set; } + public long? FeatureAllocation { get; set; } + public long? FeatureUsage { get; set; } + public string? FeatureUsageEvent { get; set; } + public RulesengineMetricPeriod? FeatureUsagePeriod { get; set; } + public DateTime? FeatureUsageResetAt { get; set; } + public string? FlagId { get; set; } + public required string FlagKey { get; set; } + public required string Reason { get; set; } + public string? RuleId { get; set; } + public RulesengineRuleType? RuleType { get; set; } + public string? UserId { get; set; } + public bool Value { get; set; } + } +} diff --git a/src/SchematicHQ.Client/RulesEngine/CheckFlagWithEntitlementResponse.cs b/src/SchematicHQ.Client/RulesEngine/CheckFlagWithEntitlementResponse.cs new file mode 100644 index 00000000..237c42d6 --- /dev/null +++ b/src/SchematicHQ.Client/RulesEngine/CheckFlagWithEntitlementResponse.cs @@ -0,0 +1,127 @@ +namespace SchematicHQ.Client.RulesEngine +{ + /// + /// Response from CheckFlagWithEntitlement containing flag check result with entitlement information. + /// This is a subset of CheckFlagResponseData with deprecated fields removed. + /// + /// This is the public return type of and is + /// intentionally kept distinct from the generated (used + /// internally on the datastream/WASM path) so that its shape stays stable for existing consumers. + /// + public class CheckFlagWithEntitlementResponse + { + /// + /// If company keys were provided and matched a company, its ID + /// + public string? CompanyId { get; set; } + + /// + /// Entitlement information for the feature, if applicable + /// + public RulesengineFeatureEntitlement? Entitlement { get; set; } + + /// + /// If a flag was found, its ID + /// + public string? FlagId { get; set; } + + /// + /// The key used to check the flag + /// + public required string FlagKey { get; set; } + + /// + /// A human-readable explanation of the result + /// + public required string Reason { get; set; } + + /// + /// If a rule was found, its ID + /// + public string? RuleId { get; set; } + + /// + /// If a rule was found, its type + /// + public string? RuleType { get; set; } + + /// + /// If user keys were provided and matched a user, its ID + /// + public string? UserId { get; set; } + + /// + /// A boolean flag check result; for feature entitlements, this represents whether further consumption is permitted + /// + public bool Value { get; set; } + + /// + /// Create a CheckFlagWithEntitlementResponse from a rules engine result + /// + public static CheckFlagWithEntitlementResponse FromCheckFlagResult(CheckFlagResult result) + { + return new CheckFlagWithEntitlementResponse + { + CompanyId = result.CompanyId, + Entitlement = result.Entitlement, + FlagId = result.FlagId, + FlagKey = result.FlagKey, + Reason = result.Reason, + RuleId = result.RuleId, + RuleType = result.RuleType?.Value, + UserId = result.UserId, + Value = result.Value + }; + } + + /// + /// Create a CheckFlagWithEntitlementResponse from an API CheckFlagResponseData + /// + public static CheckFlagWithEntitlementResponse FromApiResponse(CheckFlagResponseData data, string flagKey) + { + return new CheckFlagWithEntitlementResponse + { + CompanyId = data.CompanyId, + Entitlement = ToRulesEngineEntitlement(data.Entitlement), + FlagId = data.FlagId, + FlagKey = flagKey, + Reason = data.Reason, + RuleId = data.RuleId, + RuleType = data.RuleType?.Value, + UserId = data.UserId, + Value = data.Value + }; + } + + /// + /// Convert API FeatureEntitlement to RulesengineFeatureEntitlement + /// + private static RulesengineFeatureEntitlement? ToRulesEngineEntitlement(FeatureEntitlement? entitlement) + { + if (entitlement == null) + return null; + + return new RulesengineFeatureEntitlement + { + Allocation = entitlement.Allocation, + CreditId = entitlement.CreditId, + CreditRemaining = entitlement.CreditRemaining, + CreditTotal = entitlement.CreditTotal, + CreditUsed = entitlement.CreditUsed, + EventName = entitlement.EventName, + FeatureId = entitlement.FeatureId, + FeatureKey = entitlement.FeatureKey, + MetricPeriod = entitlement.MetricPeriod.HasValue + ? new RulesengineMetricPeriod(entitlement.MetricPeriod.Value.Value) + : null, + MetricResetAt = entitlement.MetricResetAt, + MonthReset = entitlement.MonthReset.HasValue + ? new RulesengineMetricPeriodMonthReset(entitlement.MonthReset.Value.Value) + : null, + SoftLimit = entitlement.SoftLimit, + Usage = entitlement.Usage, + ValueType = new RulesengineEntitlementValueType(entitlement.ValueType.Value) + }; + } + } +} diff --git a/src/SchematicHQ.Client/RulesEngine/Consts.cs b/src/SchematicHQ.Client/RulesEngine/Consts.cs deleted file mode 100644 index 6bc04ae6..00000000 --- a/src/SchematicHQ.Client/RulesEngine/Consts.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Text.Json.Serialization; -using System.Collections.Generic; - -namespace SchematicHQ.Client.RulesEngine -{ - public static class RulesengineRuleTypeExtensions - { - public static string DisplayName(this RulesengineRuleType ruleType) - { - return ruleType.Value.Replace("_", " "); - } - - public static bool IsEntitlement(this RulesengineRuleType ruleType) - { - return ruleType == RulesengineRuleType.PlanEntitlement.Value || - ruleType == RulesengineRuleType.PlanEntitlementUsageExceeded.Value || - ruleType == RulesengineRuleType.CompanyOverride.Value || - ruleType == RulesengineRuleType.CompanyOverrideUsageExceeded.Value; - } - - public static RulePrioritizationMethod PrioritizationMethod(this RulesengineRuleType ruleType) - { - if (ruleType == RulesengineRuleType.Standard.Value) - { - return RulePrioritizationMethod.Priority; - } - - if (ruleType == RulesengineRuleType.CompanyOverride.Value || - ruleType == RulesengineRuleType.PlanEntitlement.Value || - ruleType == RulesengineRuleType.CompanyOverrideUsageExceeded.Value || - ruleType == RulesengineRuleType.PlanEntitlementUsageExceeded.Value) - { - return RulePrioritizationMethod.Optimistic; - } - - return RulePrioritizationMethod.None; - } - - public static List RuleTypePriority = new List - { - RulesengineRuleType.GlobalOverride, - RulesengineRuleType.CompanyOverride, - RulesengineRuleType.PlanEntitlement, - RulesengineRuleType.CompanyOverrideUsageExceeded, - RulesengineRuleType.PlanEntitlementUsageExceeded, - RulesengineRuleType.Standard, - RulesengineRuleType.Default - }; - } - - [JsonConverter(typeof(JsonStringEnumConverter))] - public enum RulePrioritizationMethod - { - [JsonPropertyName("none")] - None, - - [JsonPropertyName("priority")] - Priority, - - [JsonPropertyName("optimistic")] - Optimistic - } -} diff --git a/src/SchematicHQ.Client/RulesEngine/Errors.cs b/src/SchematicHQ.Client/RulesEngine/Errors.cs new file mode 100644 index 00000000..30da1725 --- /dev/null +++ b/src/SchematicHQ.Client/RulesEngine/Errors.cs @@ -0,0 +1,8 @@ +namespace SchematicHQ.Client.RulesEngine +{ + public static class Errors + { + public static readonly Exception ErrorUnexpected = new Exception("Unexpected error"); + public static readonly Exception ErrorFlagNotFound = new Exception("Flag not found"); + } +} diff --git a/src/SchematicHQ.Client/RulesEngine/FlagCheck.cs b/src/SchematicHQ.Client/RulesEngine/FlagCheck.cs deleted file mode 100644 index 2a204c27..00000000 --- a/src/SchematicHQ.Client/RulesEngine/FlagCheck.cs +++ /dev/null @@ -1,394 +0,0 @@ -using SchematicHQ.Client.RulesEngine.Utils; - -namespace SchematicHQ.Client.RulesEngine -{ - public class CheckFlagResult - { - public string? CompanyId { get; set; } - public RulesengineFeatureEntitlement? Entitlement { get; set; } - public Exception? Error { get; set; } - public long? FeatureAllocation { get; set; } - public long? FeatureUsage { get; set; } - public string? FeatureUsageEvent { get; set; } - public RulesengineMetricPeriod? FeatureUsagePeriod { get; set; } - public DateTime? FeatureUsageResetAt { get; set; } - public string? FlagId { get; set; } - public required string FlagKey { get; set; } - public required string Reason { get; set; } - public string? RuleId { get; set; } - public RulesengineRuleType? RuleType { get; set; } - public string? UserId { get; set; } - public bool Value { get; set; } - - public void SetRuleFields(RulesengineCompany? company, RulesengineRule? rule) - { - if (rule == null) - { - return; - } - - RuleId = rule.Id; - RuleType = rule.RuleType; - - - if (company == null) - { - return; - } - - // Only set entitlement fields if the matched rule is an entitlement rule - if (!rule.RuleType.IsEntitlement()) - { - return; - } - - // For a numeric entitlement rule, there will be a metric or trait condition; - // for a boolean or unlimited entitlement rule, we don't need to set these fields - var usageCondition = rule.Conditions.FirstOrDefault(c => - c != null && (c.ConditionType == RulesengineConditionType.Metric || c.ConditionType == RulesengineConditionType.Trait)); - - if (usageCondition == null) - { - return; - } - - // Set usage, allocation, and other usage-related fields - long usage = 0; - long allocation = 0; - - if (usageCondition.ConditionType == RulesengineConditionType.Metric) - { - FeatureUsageEvent = usageCondition.EventSubtype; - - if (!string.IsNullOrEmpty(usageCondition.EventSubtype)) - { - var usageMetric = CompanyMetricExtensions.Find( - company.Metrics, - usageCondition.EventSubtype, - usageCondition.MetricPeriod, - usageCondition.MetricPeriodMonthReset - ); - - if (usageMetric != null) - { - usage = usageMetric.Value; - } - } - - if (usageCondition.MetricValue.HasValue) - { - allocation = usageCondition.MetricValue.Value; - } - - var metricPeriod = usageCondition.MetricPeriod; - - FeatureUsagePeriod = metricPeriod; - FeatureUsageResetAt = Metrics.GetNextMetricPeriodStartFromCondition(usageCondition, company); - } - else if (usageCondition.ConditionType == RulesengineConditionType.Trait) - { - if (usageCondition.TraitDefinition != null) - { - var companyUsageTrait = company.GetTraitByDefinitionId(usageCondition.TraitDefinition.Id); - if (companyUsageTrait != null) - { - usage = TypeConverter.StringToInt64(companyUsageTrait.Value); - } - } - - allocation = TypeConverter.StringToInt64(usageCondition.TraitValue); - } - - // If there is a comparison trait, this takes precedence for allocation over the numeric value - if (usageCondition.ComparisonTraitDefinition != null) - { - var companyAllocationTrait = company.GetTraitByDefinitionId(usageCondition.ComparisonTraitDefinition.Id); - if (companyAllocationTrait != null) - { - allocation = TypeConverter.StringToInt64(companyAllocationTrait.Value); - } - } - - FeatureUsage = usage; - FeatureAllocation = allocation; - } - } - - public static class Errors - { - public static readonly Exception ErrorUnexpected = new Exception("Unexpected error"); - public static readonly Exception ErrorFlagNotFound = new Exception("Flag not found"); - } - - public static class FlagCheckService - { - public const string ReasonNoCompanyOrUser = "No company or user context; default value for flag"; - public const string ReasonCompanyNotFound = "Company not found"; - public const string ReasonCompanyNotSpecified = "Must specify a company"; - public const string ReasonFlagNotFound = "Flag not found"; - public const string ReasonNoRulesMatched = "No rules matched; default value for flag"; - public const string ReasonServerError = "Server error; Schematic has been notified"; - public const string ReasonUserNotFound = "User not found"; - - public static async Task CheckFlag( - RulesengineCompany? company, - RulesengineUser? user, - RulesengineFlag? flag, - CancellationToken cancellationToken = default) - { - var resp = new CheckFlagResult - { - Reason = ReasonNoRulesMatched, - FlagKey = "", - }; - - if (flag == null) - { - resp.Reason = ReasonFlagNotFound; - resp.Error = Errors.ErrorFlagNotFound; - return resp; - } - - resp.FlagId = flag.Id; - resp.FlagKey = flag.Key; - resp.Value = flag.DefaultValue; - - if (company != null) - { - resp.CompanyId = company.Id; - var entitlement = company.Entitlements?.FirstOrDefault(e => e != null && e.FeatureKey == flag.Key); - if (entitlement != null) - { - resp.Entitlement = entitlement; - } - } - - if (user != null) - { - resp.UserId = user.Id; - } - - // Filter company and user rules to only include those for this flag - var companyRules = company?.Rules? - .Where(r => r?.FlagId != null && r.FlagId == flag.Id) - .ToList(); - var userRules = user?.Rules? - .Where(r => r?.FlagId != null && r.FlagId == flag.Id) - .ToList(); - - var ruleChecker = RuleCheckService.NewRuleCheckService(); - // The wire format may send `"rules": null` for flags with no rules; treat that as empty. - var flagRules = flag.Rules?.ToList() ?? new List(); - foreach (var group in GroupRulesByPriority(flagRules, companyRules, userRules)) - { - foreach (var rule in group) - { - if (rule == null) - { - continue; - } - - try - { - var checkRuleResp = await ruleChecker.Check(new CheckScope - { - Company = company, - Rule = rule, - User = user - }, cancellationToken); - - if (checkRuleResp == null) - { - resp.Error = Errors.ErrorUnexpected; - return resp; - } - - if (checkRuleResp.Match) - { - resp.Value = rule.Value; - resp.Reason = $"Matched {rule.RuleType.DisplayName()} rule \"{rule.Name}\" ({rule.Id})"; - resp.SetRuleFields(company, rule); - return resp; - } - } - catch (Exception ex) - { - resp.Error = ex; - return resp; - } - } - } - - return resp; - } - - public static List> GroupRulesByPriority(params List?[] ruleSlices) - { - var allRules = new List(); - foreach (var rules in ruleSlices) - { - if (rules != null && rules.Count > 0) - { - allRules.AddRange(rules); - } - } - - if (allRules.Count == 0) - { - return new List>(); - } - - // Group rules by their type (convert to internal enum for grouping) - var grouped = allRules.GroupBy(rule => rule.RuleType) - .ToDictionary(g => g.Key, g => g.ToList()); - - // Prioritize rules within each type group - foreach (var ruleType in grouped.Keys.ToList()) - { - var rulesForType = grouped[ruleType]; - switch (ruleType.PrioritizationMethod()) - { - case RulePrioritizationMethod.Priority: - grouped[ruleType] = rulesForType.OrderBy(r => r.Priority).ToList(); - break; - case RulePrioritizationMethod.Optimistic: - grouped[ruleType] = rulesForType.OrderByDescending(r => r.Value).ToList(); - break; - } - } - - // Prioritize type groups relative to one another - var prioritizedGroups = new List>(); - foreach (var ruleType in RulesengineRuleTypeExtensions.RuleTypePriority) - { - if (grouped.TryGetValue(ruleType, out var rules2)) - { - prioritizedGroups.Add(rules2); - } - } - - return prioritizedGroups; - } - } - - /// - /// Response from CheckFlagWithEntitlement containing flag check result with entitlement information. - /// This is a subset of CheckFlagResponseData with deprecated fields removed. - /// - public class CheckFlagWithEntitlementResponse - { - /// - /// If company keys were provided and matched a company, its ID - /// - public string? CompanyId { get; set; } - - /// - /// Entitlement information for the feature, if applicable - /// - public RulesengineFeatureEntitlement? Entitlement { get; set; } - - /// - /// If a flag was found, its ID - /// - public string? FlagId { get; set; } - - /// - /// The key used to check the flag - /// - public required string FlagKey { get; set; } - - /// - /// A human-readable explanation of the result - /// - public required string Reason { get; set; } - - /// - /// If a rule was found, its ID - /// - public string? RuleId { get; set; } - - /// - /// If a rule was found, its type - /// - public string? RuleType { get; set; } - - /// - /// If user keys were provided and matched a user, its ID - /// - public string? UserId { get; set; } - - /// - /// A boolean flag check result; for feature entitlements, this represents whether further consumption is permitted - /// - public bool Value { get; set; } - - /// - /// Create a CheckFlagWithEntitlementResponse from a rules engine CheckFlagResult - /// - public static CheckFlagWithEntitlementResponse FromCheckFlagResult(CheckFlagResult result) - { - return new CheckFlagWithEntitlementResponse - { - CompanyId = result.CompanyId, - Entitlement = result.Entitlement, - FlagId = result.FlagId, - FlagKey = result.FlagKey, - Reason = result.Reason, - RuleId = result.RuleId, - RuleType = result.RuleType?.Value, - UserId = result.UserId, - Value = result.Value - }; - } - - /// - /// Create a CheckFlagWithEntitlementResponse from an API CheckFlagResponseData - /// - public static CheckFlagWithEntitlementResponse FromApiResponse(CheckFlagResponseData data, string flagKey) - { - return new CheckFlagWithEntitlementResponse - { - CompanyId = data.CompanyId, - Entitlement = ToRulesEngineEntitlement(data.Entitlement), - FlagId = data.FlagId, - FlagKey = flagKey, - Reason = data.Reason, - RuleId = data.RuleId, - RuleType = data.RuleType?.Value, - UserId = data.UserId, - Value = data.Value - }; - } - - /// - /// Convert API FeatureEntitlement to RulesengineFeatureEntitlement - /// - private static RulesengineFeatureEntitlement? ToRulesEngineEntitlement(FeatureEntitlement? entitlement) - { - if (entitlement == null) - return null; - - return new RulesengineFeatureEntitlement - { - Allocation = entitlement.Allocation, - CreditId = entitlement.CreditId, - CreditRemaining = entitlement.CreditRemaining, - CreditTotal = entitlement.CreditTotal, - CreditUsed = entitlement.CreditUsed, - EventName = entitlement.EventName, - FeatureId = entitlement.FeatureId, - FeatureKey = entitlement.FeatureKey, - MetricPeriod = entitlement.MetricPeriod.HasValue - ? new RulesengineMetricPeriod(entitlement.MetricPeriod.Value.Value) - : null, - MetricResetAt = entitlement.MetricResetAt, - MonthReset = entitlement.MonthReset.HasValue - ? new RulesengineMetricPeriodMonthReset(entitlement.MonthReset.Value.Value) - : null, - SoftLimit = entitlement.SoftLimit, - Usage = entitlement.Usage, - ValueType = new RulesengineEntitlementValueType(entitlement.ValueType.Value) - }; - } - } -} diff --git a/src/SchematicHQ.Client/RulesEngine/Metrics.cs b/src/SchematicHQ.Client/RulesEngine/Metrics.cs deleted file mode 100644 index 49c42b7d..00000000 --- a/src/SchematicHQ.Client/RulesEngine/Metrics.cs +++ /dev/null @@ -1,214 +0,0 @@ -namespace SchematicHQ.Client.RulesEngine -{ - public static class Metrics - { - - public static DateTime? GetCurrentMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod? metricPeriod) - { - if (metricPeriod == null) return null; - - var now = DateTime.UtcNow; - - if (metricPeriod == RulesengineMetricPeriod.CurrentDay) - // UTC midnight for the current day - return now.Date; - - if (metricPeriod == RulesengineMetricPeriod.CurrentWeek) - { - // UTC midnight for the current week's Monday - int daysSinceMonday = ((int)now.DayOfWeek - (int)DayOfWeek.Monday + 7) % 7; - return now.Date.AddDays(-daysSinceMonday); - } - - if (metricPeriod == RulesengineMetricPeriod.CurrentMonth) - // UTC midnight for the first day of current month - return new DateTime(now.Year, now.Month, 1, 0, 0, 0, DateTimeKind.Utc); - - return null; - } - - /// - /// Given a company, determine the current metric period start based on the company's billing subscription. - /// - public static DateTime? GetCurrentMetricPeriodStartForCompanyBillingSubscription(RulesengineCompany? company) - { - // If no subscription exists, we use calendar month reset - if (company == null || company.Subscription == null) - { - return GetCurrentMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod.CurrentMonth); - } - - var now = DateTime.UtcNow; - var periodStart = company.Subscription.PeriodStart; - var periodEnd = company.Subscription.PeriodEnd; - - // If the start period is in the future, the metric period is from the start of the current calendar month until either - // the end of the current calendar month or the start of the billing period, whichever comes first - if (periodStart > now) - { - DateTime? startOfNextMonth = GetCurrentMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod.CurrentMonth); - if (periodStart > startOfNextMonth) - { - return startOfNextMonth; - } - return periodStart; - } - - // Month metric period will reset on the same day/hour/minute/second as the subscription started every month; get that timestamp for the current month - var currentPeriodStart = new DateTime( - now.Year, - now.Month, - Math.Min(periodStart.Day, DateTime.DaysInMonth(now.Year, now.Month)), - periodStart.Hour, - periodStart.Minute, - periodStart.Second, - periodStart.Millisecond, - DateTimeKind.Utc); - - // If we've already passed this month's reset date, move to next month - if (currentPeriodStart < now) - { - currentPeriodStart = currentPeriodStart.AddMonths(1); - - // Handle day adjustment when going back from 30/31 to a month with fewer days - var daysInMonth = DateTime.DaysInMonth(currentPeriodStart.Year, currentPeriodStart.Month); - if (periodStart.Day > daysInMonth) - { - currentPeriodStart = new DateTime( - currentPeriodStart.Year, - currentPeriodStart.Month, - daysInMonth, - periodStart.Hour, - periodStart.Minute, - periodStart.Second, - periodStart.Millisecond, - DateTimeKind.Utc); - } - } - - // If the next reset is after the end of the billing period, use the end of the billing period instead - if (currentPeriodStart > periodEnd) - { - return periodEnd; - } - - return currentPeriodStart; - } - - public static DateTime? GetNextMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod? metricPeriod) - { - if (metricPeriod == null) return null; - - if (metricPeriod == RulesengineMetricPeriod.CurrentDay) - // UTC midnight for upcoming day - return DateTime.UtcNow.Date.AddDays(1); - - if (metricPeriod == RulesengineMetricPeriod.CurrentWeek) - { - // UTC midnight for upcoming Monday (C# uses Monday as first day, Go example used Sunday) - var now = DateTime.UtcNow; - int daysUntilMonday = ((int)DayOfWeek.Monday - (int)now.DayOfWeek + 7) % 7; - if (daysUntilMonday == 0) - daysUntilMonday = 7; // If today is Monday, get next Monday - return now.Date.AddDays(daysUntilMonday); - } - - if (metricPeriod == RulesengineMetricPeriod.CurrentMonth) - { - // UTC midnight for the first day of next month - var currentDate = DateTime.UtcNow; - return new DateTime(currentDate.Year, currentDate.Month, 1, 0, 0, 0, DateTimeKind.Utc).AddMonths(1); - } - - return null; - } - - - /// - /// Given a company, determine the next metric period start based on the company's billing subscription. - /// - public static DateTime? GetNextMetricPeriodStartForCompanyBillingSubscription(RulesengineCompany? company) - { - // If no subscription exists, we use calendar month reset - if (company == null || company.Subscription == null) - { - return GetNextMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod.CurrentMonth); - } - - var now = DateTime.UtcNow; - var periodEnd = company.Subscription.PeriodEnd; - var periodStart = company.Subscription.PeriodStart; - - // If the start period is in the future, the metric period is from the start of the current calendar month until either - // the end of the current calendar month or the start of the billing period, whichever comes first - if (periodStart > now) - { - var startOfNextMonth = GetNextMetricPeriodStartForCalendarMetricPeriod(RulesengineMetricPeriod.CurrentMonth); - if (periodStart > startOfNextMonth) - { - return startOfNextMonth; - } - - return periodStart; - } - - // Month metric period will reset on the same day/hour/minute/second as the subscription started every month; - // Get that timestamp for the current month - var nextReset = new DateTime( - now.Year, - now.Month, - periodStart.Day, - periodStart.Hour, - periodStart.Minute, - periodStart.Second, - periodStart.Millisecond, - DateTimeKind.Utc); - - // If we've already passed this month's reset date, move to next month - if (nextReset <= now) - { - nextReset = nextReset.AddMonths(1); - } - - // If the next reset is after the end of the billing period, use the end of the billing period instead - if (nextReset > periodEnd) - { - return periodEnd; - } - - return nextReset; - } - - /// - /// Given a rule condition and a company, determine the next metric period start. - /// Will return null if the condition is not a metric condition. - /// - public static DateTime? GetNextMetricPeriodStartFromCondition(RulesengineCondition? condition, RulesengineCompany? company) - { - // Only metric conditions have a metric period that can reset - if (condition == null || condition.ConditionType != RulesengineConditionType.Metric || condition.MetricPeriod == null) - { - return null; - } - - var metricPeriod = condition.MetricPeriod; - - // If the metric period is all-time, no reset - if (metricPeriod == RulesengineMetricPeriod.AllTime) - { - return null; - } - - // Metric period current month with billing cycle reset - if (metricPeriod == RulesengineMetricPeriod.CurrentMonth && - condition.MetricPeriodMonthReset.HasValue && - condition.MetricPeriodMonthReset == RulesengineMetricPeriodMonthReset.BillingCycle) - { - return GetNextMetricPeriodStartForCompanyBillingSubscription(company); - } - - // Calendar-based metric periods - return GetNextMetricPeriodStartForCalendarMetricPeriod(metricPeriod); - } - } -} diff --git a/src/SchematicHQ.Client/RulesEngine/RuleCheck.cs b/src/SchematicHQ.Client/RulesEngine/RuleCheck.cs deleted file mode 100644 index 43856ff6..00000000 --- a/src/SchematicHQ.Client/RulesEngine/RuleCheck.cs +++ /dev/null @@ -1,350 +0,0 @@ -using SchematicHQ.Client.RulesEngine.Utils; - -namespace SchematicHQ.Client.RulesEngine -{ - public class CheckScope - { - public RulesengineCompany? Company { get; set; } - public RulesengineRule? Rule { get; set; } - public RulesengineUser? User { get; set; } - } - - public class CheckResult - { - public CheckScope? CheckScope { get; set; } - public bool Match { get; set; } - } - - public class RuleCheckService - { - public static RuleCheckService NewRuleCheckService() - { - return new RuleCheckService(); - } - - public async Task Check(CheckScope scope, CancellationToken cancellationToken = default) - { - var res = new CheckResult - { - CheckScope = scope - }; - - if (scope.Rule == null) - { - return res; - } - - if (scope.Rule.RuleType == RulesengineRuleType.Default.Value || scope.Rule.RuleType == RulesengineRuleType.GlobalOverride.Value) - { - res.Match = true; - return res; - } - - bool match; - foreach (var condition in scope.Rule.Conditions ?? Enumerable.Empty()) - { - match = await CheckCondition(scope.Company, scope.User, condition, cancellationToken); - if (!match) - { - return res; - } - } - - foreach (var group in scope.Rule.ConditionGroups ?? Enumerable.Empty()) - { - match = await CheckConditionGroup(scope.Company, scope.User, group, cancellationToken); - if (!match) - { - return res; - } - } - - res.Match = true; - return res; - } - - private async Task CheckCondition(RulesengineCompany? company, RulesengineUser? user, RulesengineCondition condition, CancellationToken cancellationToken) - { - if (condition == null) - { - return false; - } - - if (condition.ConditionType == RulesengineConditionType.Company) - return await CheckCompanyCondition(company, condition, cancellationToken); - if (condition.ConditionType == RulesengineConditionType.Metric.Value) - return await CheckMetricCondition(company, condition, cancellationToken); - if (condition.ConditionType == RulesengineConditionType.BasePlan.Value) - return await CheckBasePlanCondition(company, condition, cancellationToken); - if (condition.ConditionType == RulesengineConditionType.Plan.Value) - return await CheckPlanCondition(company, condition, cancellationToken); - if (condition.ConditionType == RulesengineConditionType.Trait.Value) - return await CheckTraitCondition(company, user, condition, cancellationToken); - if (condition.ConditionType == RulesengineConditionType.User.Value) - return await CheckUserCondition(user, condition, cancellationToken); - if (condition.ConditionType == RulesengineConditionType.BillingProduct.Value) - return await CheckBillingProductCondition(company, condition, cancellationToken); - if (condition.ConditionType == RulesengineConditionType.Credit.Value) - return await CheckCreditBalanceCondition(company, condition, cancellationToken); - if (condition.ConditionType == RulesengineConditionType.PlanVersion.Value) - return await CheckPlanVersionCondition(company, condition, cancellationToken); - - return false; - } - - private async Task CheckConditionGroup(RulesengineCompany? company, RulesengineUser? user, RulesengineConditionGroup group, CancellationToken cancellationToken) - { - if (group == null || !group.Conditions.Any()) - { - return false; - } - - foreach (var condition in group.Conditions) - { - if (await CheckCondition(company, user, condition, cancellationToken)) - { - return true; - } - } - - return false; - } - - private Task CheckCompanyCondition(RulesengineCompany? company, RulesengineCondition condition, CancellationToken cancellationToken) - { - if (condition.ConditionType != RulesengineConditionType.Company || company == null) - { - return Task.FromResult(false); - } - - var resourceMatch = Set.NewSet(condition.ResourceIds.ToArray()).Contains(company.Id); - if (condition.Operator == ComparableOperator.Ne) - { - return Task.FromResult(!resourceMatch); - } - - return Task.FromResult(resourceMatch); - } - - private Task CheckBillingProductCondition(RulesengineCompany? company, RulesengineCondition condition, CancellationToken cancellationToken) - { - if (condition.ConditionType != RulesengineConditionType.BillingProduct || company == null) - { - return Task.FromResult(false); - } - - var companyBillingProductIds = Set.NewSet(company.BillingProductIds.ToArray()); - var resourceMatch = Set.NewSet(condition.ResourceIds.ToArray()).Intersection(companyBillingProductIds).Len > 0; - if (condition.Operator == ComparableOperator.Ne) - { - return Task.FromResult(!resourceMatch); - } - - return Task.FromResult(resourceMatch); - } - - private Task CheckCreditBalanceCondition(RulesengineCompany? company, RulesengineCondition condition, CancellationToken cancellationToken) - { - if (condition.ConditionType != RulesengineConditionType.Credit || company == null || string.IsNullOrEmpty(condition.CreditId)) - { - return Task.FromResult(false); - } - - double consumptionCost = 1.0; - if (condition.ConsumptionRate.HasValue) - { - consumptionCost = condition.ConsumptionRate.Value; - } - - double creditBalance = 0.0; - if (company.CreditBalances != null && company.CreditBalances.TryGetValue(condition.CreditId, out double balance)) - { - creditBalance = balance; - } - - return Task.FromResult(creditBalance >= consumptionCost); - } - - private Task CheckPlanCondition(RulesengineCompany? company, RulesengineCondition condition, CancellationToken cancellationToken) - { - if (condition.ConditionType != RulesengineConditionType.Plan || company == null) - { - return Task.FromResult(false); - } - - var companyPlanIds = Set.NewSet(company.PlanIds.ToArray()); - var resourceMatch = Set.NewSet(condition.ResourceIds.ToArray()).Intersection(companyPlanIds).Len > 0; - if (condition.Operator == ComparableOperator.Ne) - { - return Task.FromResult(!resourceMatch); - } - - return Task.FromResult(resourceMatch); - } - - private Task CheckBasePlanCondition(RulesengineCompany? company, RulesengineCondition condition, CancellationToken cancellationToken) - { - if (condition.ConditionType != RulesengineConditionType.BasePlan || company == null) - { - return Task.FromResult(false); - } - - var op = condition.Operator; - - if (op == ComparableOperator.IsEmpty) - { - return Task.FromResult(company.BasePlanId == null); - } - - if (op == ComparableOperator.NotEmpty) - { - return Task.FromResult(company.BasePlanId != null); - } - - var resourceIds = Set.NewSet(condition.ResourceIds.ToArray()); - var resourceMatch = company.BasePlanId != null && resourceIds.Contains(company.BasePlanId); - if (op == ComparableOperator.Ne) - { - return Task.FromResult(company.BasePlanId == null || !resourceIds.Contains(company.BasePlanId)); - } - - return Task.FromResult(resourceMatch); - } - - private Task CheckMetricCondition(RulesengineCompany? company, RulesengineCondition condition, CancellationToken cancellationToken) - { - if (condition == null || condition.ConditionType != RulesengineConditionType.Metric || company == null || string.IsNullOrEmpty(condition.EventSubtype)) - { - return Task.FromResult(false); - } - - long leftVal = 0; - var metric = CompanyMetricExtensions.Find(company.Metrics, condition.EventSubtype, condition.MetricPeriod, condition.MetricPeriodMonthReset); - if (metric != null) - { - leftVal = metric.Value; - } - - if (!condition.MetricValue.HasValue) - { - throw new InvalidOperationException($"Expected metric value for condition: {condition.Id}, but received null"); - } - - long rightVal = condition.MetricValue.Value; - if (condition.ComparisonTraitDefinition != null) - { - var comparisonTrait = FindTrait(condition.ComparisonTraitDefinition, company.Traits); - if (comparisonTrait == null) - { - rightVal = 0; - } - else - { - rightVal = TypeConverter.StringToInt64(comparisonTrait.Value); - } - } - - bool resourceMatch = TypeConverter.CompareInt64(leftVal, rightVal, condition.Operator); - - return Task.FromResult(resourceMatch); - } - - private Task CheckTraitCondition(RulesengineCompany? company, RulesengineUser? user, RulesengineCondition condition, CancellationToken cancellationToken) - { - if (condition == null || condition.ConditionType != RulesengineConditionType.Trait || condition.TraitDefinition == null) - { - return Task.FromResult(false); - } - - var traitDef = condition.TraitDefinition; - RulesengineTrait? trait; - RulesengineTrait? comparisonTrait; - - if (traitDef.EntityType == RulesengineEntityType.Company && company != null) - { - trait = FindTrait(traitDef, company.Traits); - comparisonTrait = FindTrait(condition.ComparisonTraitDefinition, company.Traits); - } - else if (traitDef.EntityType == RulesengineEntityType.User && user != null) - { - trait = FindTrait(traitDef, user.Traits); - comparisonTrait = FindTrait(condition.ComparisonTraitDefinition, user.Traits); - } - else - { - return Task.FromResult(false); - } - - bool resourceMatch = CompareTraits(condition, trait, comparisonTrait); - - return Task.FromResult(resourceMatch); - } - - private Task CheckUserCondition(RulesengineUser? user, RulesengineCondition condition, CancellationToken cancellationToken) - { - if (condition.ConditionType != RulesengineConditionType.User || user == null) - { - return Task.FromResult(false); - } - - var resourceMatch = Set.NewSet(condition.ResourceIds.ToArray()).Contains(user.Id); - if (condition.Operator == ComparableOperator.Ne) - { - return Task.FromResult(!resourceMatch); - } - - return Task.FromResult(resourceMatch); - } - - private Task CheckPlanVersionCondition(RulesengineCompany? company, RulesengineCondition condition, CancellationToken cancellationToken) - { - if (condition.ConditionType != RulesengineConditionType.PlanVersion || company == null) - { - return Task.FromResult(false); - } - - var companyPlanVersionIds = Set.NewSet(company.PlanVersionIds.ToArray()); - var resourceMatch = Set.NewSet(condition.ResourceIds.ToArray()).Intersection(companyPlanVersionIds).Len > 0; - if (condition.Operator == ComparableOperator.Ne) - { - return Task.FromResult(!resourceMatch); - } - - return Task.FromResult(resourceMatch); - } - - static private bool CompareTraits(RulesengineCondition condition, RulesengineTrait? trait, RulesengineTrait? comparisonTrait) - { - string leftVal = ""; - string rightVal = condition.TraitValue ?? ""; - - if (trait != null) - { - leftVal = trait.Value; - } - - if (comparisonTrait != null) - { - rightVal = comparisonTrait.Value; - } - - var comparableType = ComparableType.String; - if (trait != null && trait.TraitDefinition != null) - { - comparableType = trait.TraitDefinition.ComparableType.ToComparableType(); - } - - return TypeConverter.Compare(leftVal, rightVal, comparableType, condition.Operator); - } - - static private RulesengineTrait? FindTrait(RulesengineTraitDefinition? traitDef, IEnumerable? traits) - { - if (traitDef == null || traits == null) - { - return null; - } - - return traits.FirstOrDefault(t => t.TraitDefinition?.Id == traitDef.Id); - } - } -} diff --git a/src/SchematicHQ.Client/RulesEngine/RulesEngineExtensions.cs b/src/SchematicHQ.Client/RulesEngine/RulesEngineExtensions.cs deleted file mode 100644 index 3a619f6e..00000000 --- a/src/SchematicHQ.Client/RulesEngine/RulesEngineExtensions.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace SchematicHQ.Client.RulesEngine -{ - public static class RulesengineCompanyExtensions - { - private static readonly ConditionalWeakTable MetricsLocks = new ConditionalWeakTable(); - - public static RulesengineTrait? GetTraitByDefinitionId(this RulesengineCompany company, string definitionId) - { - return company.Traits?.FirstOrDefault(t => t.TraitDefinition?.Id == definitionId); - } - - public static void AddMetric(this RulesengineCompany company, RulesengineCompanyMetric? metric) - { - if (metric == null) - { - return; - } - - var metricsList = company.Metrics as List; - if (metricsList == null) - { - metricsList = company.Metrics != null - ? new List(company.Metrics) - : new List(); - company.Metrics = metricsList; - } - - var metricsLock = MetricsLocks.GetOrCreateValue(company); - lock (metricsLock) - { - var existingMetricIndex = metricsList.FindIndex(m => - m.EventSubtype == metric.EventSubtype && - m.Period == metric.Period && - m.MonthReset == metric.MonthReset); - - if (existingMetricIndex != -1) - { - metricsList[existingMetricIndex] = metric; - } - else - { - metricsList.Add(metric); - } - } - } - } - - public static class CompanyMetricExtensions - { - public static RulesengineCompanyMetric? Find( - IEnumerable? metrics, - string eventSubtype, - RulesengineMetricPeriod? period, - RulesengineMetricPeriodMonthReset? monthReset) - { - if (metrics == null || string.IsNullOrEmpty(eventSubtype) || period == null) - return null; - - return metrics.FirstOrDefault(m => - m.EventSubtype == eventSubtype && - m.Period.Value == period.Value.Value && - (monthReset == null || m.MonthReset.Value == monthReset.Value.Value)); - } - } -} diff --git a/src/SchematicHQ.Client/RulesEngine/Utils/Set.cs b/src/SchematicHQ.Client/RulesEngine/Utils/Set.cs deleted file mode 100644 index 4ebf9549..00000000 --- a/src/SchematicHQ.Client/RulesEngine/Utils/Set.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace SchematicHQ.Client.RulesEngine.Utils -{ - public class Set - { - private HashSet _items = new HashSet(); - - public Set(params T[] items) - { - if (items != null) - { - foreach (var item in items) - { - _items.Add(item); - } - } - } - - public static Set NewSet(params T[] items) - { - return new Set(items); - } - - public bool Contains(T item) - { - return _items.Contains(item); - } - - public int Count => _items.Count; - - public Set Intersection(Set other) - { - var result = new Set(); - result._items = new HashSet(_items.Intersect(other._items)); - return result; - } - - public int Len => Count; - } -} \ No newline at end of file diff --git a/src/SchematicHQ.Client/RulesEngine/Utils/TypeConverter.cs b/src/SchematicHQ.Client/RulesEngine/Utils/TypeConverter.cs deleted file mode 100644 index ecac3bb1..00000000 --- a/src/SchematicHQ.Client/RulesEngine/Utils/TypeConverter.cs +++ /dev/null @@ -1,213 +0,0 @@ -using System.Globalization; -using System.Text.Json.Serialization; - -namespace SchematicHQ.Client.RulesEngine.Utils -{ - - [JsonConverter(typeof(SchematicHQ.Client.Cache.ComparableTypeConverter))] - public enum ComparableType - { - Unknown, - String, - Int, - Bool, - Date - } - - // Extension methods to convert from generated types to utility types - public static class ComparableTypeExtensions - { - public static ComparableType ToComparableType(this RulesengineTraitDefinitionComparableType comparableType) - { - return comparableType.Value switch - { - "bool" => ComparableType.Bool, - "date" => ComparableType.Date, - "int" => ComparableType.Int, - "string" => ComparableType.String, - _ => ComparableType.String - }; - } - } - - public static class TypeConverter - { - public static bool Compare(string a, string b, ComparableType comparableType, ComparableOperator op) - { - switch (comparableType) - { - case ComparableType.String: - return CompareString(a, b, op); - case ComparableType.Int: - return CompareInt64(StringToInt64(a), StringToInt64(b), op); - case ComparableType.Bool: - return CompareBool(StringToBool(a), StringToBool(b), op); - case ComparableType.Date: - var dateA = StringToDate(a); - var dateB = StringToDate(b); - if (dateA == null || dateB == null) - return false; - return CompareDate(dateA.Value, dateB.Value, op); - default: - return false; - } - } - - public static bool CompareString(string a, string b, ComparableOperator op) - { - switch (op.Value) - { - case ComparableOperator.Values.Eq: - return string.Equals(a, b, StringComparison.OrdinalIgnoreCase); - case ComparableOperator.Values.Ne: - return !string.Equals(a, b, StringComparison.OrdinalIgnoreCase); - case ComparableOperator.Values.Lt: - return string.Compare(a, b, StringComparison.OrdinalIgnoreCase) < 0; - case ComparableOperator.Values.Lte: - return string.Compare(a, b, StringComparison.OrdinalIgnoreCase) <= 0; - case ComparableOperator.Values.Gt: - return string.Compare(a, b, StringComparison.OrdinalIgnoreCase) > 0; - case ComparableOperator.Values.Gte: - return string.Compare(a, b, StringComparison.OrdinalIgnoreCase) >= 0; - case ComparableOperator.Values.IsEmpty: - return string.IsNullOrEmpty(a); - case ComparableOperator.Values.NotEmpty: - return !string.IsNullOrEmpty(a); - default: - return false; - } - } - - public static bool CompareInt64(long a, long b, ComparableOperator op) - { - switch (op.Value) - { - case ComparableOperator.Values.Eq: - return a == b; - case ComparableOperator.Values.Ne: - return a != b; - case ComparableOperator.Values.Lt: - return a < b; - case ComparableOperator.Values.Lte: - return a <= b; - case ComparableOperator.Values.Gt: - return a > b; - case ComparableOperator.Values.Gte: - return a >= b; - default: - return false; - } - } - - public static bool CompareFloat(double a, double b, ComparableOperator op) - { - switch (op.Value) - { - case ComparableOperator.Values.Eq: - return Math.Abs(a - b) < double.Epsilon; - case ComparableOperator.Values.Ne: - return Math.Abs(a - b) >= double.Epsilon; - case ComparableOperator.Values.Lt: - return a < b; - case ComparableOperator.Values.Lte: - return a <= b; - case ComparableOperator.Values.Gt: - return a > b; - case ComparableOperator.Values.Gte: - return a >= b; - default: - return false; - } - } - - public static bool CompareBool(bool a, bool b, ComparableOperator op) - { - switch (op.Value) - { - case ComparableOperator.Values.Eq: - return a == b; - case ComparableOperator.Values.Ne: - return a != b; - default: - return false; - } - } - - public static bool CompareDate(DateTime a, DateTime b, ComparableOperator op) - { - switch (op.Value) - { - case ComparableOperator.Values.Eq: - return a.Date == b.Date; - case ComparableOperator.Values.Ne: - return a.Date != b.Date; - case ComparableOperator.Values.Lt: - return a < b; - case ComparableOperator.Values.Lte: - return a <= b; - case ComparableOperator.Values.Gt: - return a > b; - case ComparableOperator.Values.Gte: - return a >= b; - default: - return false; - } - } - - public static string BoolToString(bool v) - { - return v ? "true" : "false"; - } - - public static bool Int64ToBool(long v) - { - return v != 0; - } - - public static string Int64ToString(long v) - { - return v.ToString(); - } - - public static bool StringToBool(string? v) - { - if (string.IsNullOrEmpty(v)) - return false; - - return v.ToLower() == "true" || v == "1"; - } - - public static long StringToInt64(string? v) - { - if (string.IsNullOrEmpty(v)) - return 0; - - if (long.TryParse(v, out long result)) - return result; - - return 0; - } - - public static double StringToFloat(string? v) - { - if (string.IsNullOrEmpty(v)) - return 0; - - if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out double result)) - return result; - - return 0; - } - - public static DateTime? StringToDate(string? v) - { - if (string.IsNullOrEmpty(v)) - return null; - - if (DateTime.TryParse(v, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime result)) - return result; - - return null; - } - } -} diff --git a/src/SchematicHQ.Client/RulesEngine/Wasm/WasmRulesEngine.cs b/src/SchematicHQ.Client/RulesEngine/Wasm/WasmRulesEngine.cs new file mode 100644 index 00000000..87ef8b35 --- /dev/null +++ b/src/SchematicHQ.Client/RulesEngine/Wasm/WasmRulesEngine.cs @@ -0,0 +1,376 @@ +using System; +using System.IO; +using System.Text; +using System.Text.Json.Nodes; +using Microsoft.Extensions.Logging; +using SchematicHQ.Client.Core; +using Wasmtime; + +#nullable enable + +namespace SchematicHQ.Client.RulesEngine +{ + /// + /// WASM-based rules engine for local flag evaluation. + /// + /// Loads the shared Schematic rules engine WASM binary (compiled from Rust) + /// and evaluates flags locally using cached flag definitions, company data, and + /// user data. Hosts the module with the Wasmtime .NET runtime — mirroring the + /// Python and Ruby SDKs (and the pure-Java Chicory host in schematic-java). + /// + /// Data flow: typed models are serialized to snake_case JSON (via each type's + /// JsonPropertyName attributes) into an envelope {flag, company, user}; + /// the WASM module returns camelCase JSON which is converted to snake_case and + /// deserialized into . + /// + internal sealed class WasmRulesEngine : IDisposable + { + private const string WasmResourceName = "rulesengine.wasm"; + + private readonly ILogger _logger; + private readonly object _lock = new(); + + private volatile bool _initialized; + private string? _versionKey; + + // Wasmtime objects — kept alive for the lifetime of the engine. + private Engine? _engine; + private Module? _module; + private Linker? _linker; + private Store? _store; + private Instance _instance; + private Memory? _memory; + + // Exported functions (see the Rust rules engine C-ABI). + private Func? _alloc; // alloc(len) -> ptr + private Action? _dealloc; // dealloc(ptr, len) + private Func? _checkFlag; // checkFlagCombined(ptr, len) -> resultLen + private Action? _setTime; // setCurrentTimeMillis(nowMillis) — optional + private Func? _getResultJson; // getResultJson() -> ptr + private Func? _getResultJsonLength; // getResultJsonLength() -> len + private Func? _getVersionKey; // get_version_key_wasm() -> ptr (C string) + + public WasmRulesEngine(ILogger logger) + { + _logger = logger; + } + + public bool IsInitialized => _initialized; + + /// + /// Loads and instantiates the WASM module. Idempotent and thread-safe. + /// On failure the engine stays uninitialized so callers can degrade gracefully. + /// + public void Initialize() + { + if (_initialized) + { + return; + } + + lock (_lock) + { + if (_initialized) + { + return; + } + + using var wasmStream = + typeof(WasmRulesEngine).Assembly.GetManifestResourceStream(WasmResourceName) + ?? throw new InvalidOperationException( + $"Embedded WASM resource '{WasmResourceName}' not found. " + + "Ensure scripts/download-wasm.sh ran before the build."); + + _engine = new Engine(); + _module = Module.FromStream(_engine, WasmResourceName, wasmStream); + + _linker = new Linker(_engine); + _linker.DefineWasi(); + + _store = new Store(_engine); + // Inherit stdout/stderr so Rust panics / eprintln! surface for debugging. + _store.SetWasiConfiguration( + new WasiConfiguration() + .WithInheritedStandardOutput() + .WithInheritedStandardError() + ); + + _instance = _linker.Instantiate(_store, _module); + + _memory = + _instance.GetMemory("memory") + ?? throw new InvalidOperationException("WASM module does not export 'memory'"); + + _alloc = + _instance.GetFunction("alloc") + ?? throw new InvalidOperationException("WASM module does not export 'alloc'"); + _dealloc = + _instance.GetAction("dealloc") + ?? throw new InvalidOperationException("WASM module does not export 'dealloc'"); + _checkFlag = + _instance.GetFunction("checkFlagCombined") + ?? throw new InvalidOperationException( + "WASM module does not export 'checkFlagCombined'" + ); + _getResultJson = + _instance.GetFunction("getResultJson") + ?? throw new InvalidOperationException( + "WASM module does not export 'getResultJson'" + ); + _getResultJsonLength = + _instance.GetFunction("getResultJsonLength") + ?? throw new InvalidOperationException( + "WASM module does not export 'getResultJsonLength'" + ); + + // Optional exports — resolved defensively so older wasm builds still load. + // Without setCurrentTimeMillis the clockless wasmtime host cannot compute + // metric-period reset timestamps (SCHY-471); with it, feature_usage_reset_at + // is populated. + _setTime = _instance.GetAction("setCurrentTimeMillis"); + _getVersionKey = _instance.GetFunction("get_version_key_wasm"); + + _initialized = true; + + // Cache the version key immediately — the pointer is only stable before + // any other WASM call mutates linear memory. + _versionKey = ReadVersionKeyFromWasm(); + _logger.LogDebug("WASM rules engine initialized (version: {Version})", _versionKey); + } + } + + /// + /// Evaluates a flag using the WASM rules engine. + /// + public CheckFlagResult CheckFlag( + RulesengineCompany? company, + RulesengineUser? user, + RulesengineFlag flag + ) + { + if (!_initialized) + { + throw new InvalidOperationException("WASM rules engine not initialized"); + } + + var envelope = new JsonObject + { + ["flag"] = Sanitize(JsonUtils.SerializeToNode(flag), null), + }; + if (company != null) + { + envelope["company"] = Sanitize(JsonUtils.SerializeToNode(company), "company"); + } + if (user != null) + { + envelope["user"] = Sanitize(JsonUtils.SerializeToNode(user), "user"); + } + + var resultJson = CallWasm(envelope.ToJsonString()); + + // WASM returns camelCase JSON; the generated type expects snake_case. + var camelNode = + JsonNode.Parse(resultJson) + ?? throw new InvalidOperationException("WASM returned empty result JSON"); + var snakeJson = CamelToSnakeKeys(camelNode).ToJsonString(); + var result = JsonUtils.Deserialize(snakeJson); + + return ToCheckFlagResult(result); + } + + private static CheckFlagResult ToCheckFlagResult(RulesengineCheckFlagResult r) => + new() + { + CompanyId = r.CompanyId, + Entitlement = r.Entitlement, + Error = string.IsNullOrEmpty(r.Err) ? null : new Exception(r.Err), + FeatureAllocation = r.FeatureAllocation, + FeatureUsage = r.FeatureUsage, + FeatureUsageEvent = r.FeatureUsageEvent, + FeatureUsagePeriod = r.FeatureUsagePeriod, + FeatureUsageResetAt = r.FeatureUsageResetAt, + FlagId = r.FlagId, + FlagKey = r.FlagKey, + Reason = r.Reason, + RuleId = r.RuleId, + RuleType = r.RuleType, + UserId = r.UserId, + Value = r.Value, + }; + + /// + /// Version key from the WASM engine, used for cache-key generation so caches + /// invalidate when the engine changes. Computed once during initialization. + /// + public string GetVersionKey() => _versionKey ?? "1"; + + public void Dispose() + { + _store?.Dispose(); + _linker?.Dispose(); + _module?.Dispose(); + _engine?.Dispose(); + } + + /// + /// Writes into WASM memory, invokes the engine, + /// and returns the result JSON. Serialized under a lock because the WASM + /// instance shares a single linear memory across calls. + /// + private string CallWasm(string inputJson) + { + var data = Encoding.UTF8.GetBytes(inputJson); + var length = data.Length; + + lock (_lock) + { + var ptr = _alloc!(length); + try + { + data.CopyTo(_memory!.GetSpan(ptr, length)); + + // Supply the host's current time so the engine can compute + // metric-period reset timestamps (SCHY-471). No-op on older wasm. + _setTime?.Invoke(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()); + + var resultLen = _checkFlag!(ptr, length); + if (resultLen < 0) + { + throw new InvalidOperationException( + $"WASM checkFlagCombined returned error code: {resultLen}" + ); + } + + var resultPtr = _getResultJson!(); + var actualLen = _getResultJsonLength!(); + + // Result buffer is owned by the WASM module (thread-local); no free needed. + return _memory.ReadString(resultPtr, actualLen, Encoding.UTF8); + } + finally + { + // Frees the input buffer only. + _dealloc!(ptr, length); + } + } + } + + private string ReadVersionKeyFromWasm() + { + if (_getVersionKey == null) + { + return "1"; + } + + try + { + var ptr = _getVersionKey(); + return _memory!.ReadNullTerminatedString(ptr); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to read WASM version key"); + return "1"; + } + } + + /// + /// Recursively converts JSON object keys from camelCase to snake_case. + /// + private static JsonNode? CamelToSnakeKeys(JsonNode? node) + { + switch (node) + { + case JsonObject obj: + var result = new JsonObject(); + foreach (var kvp in obj) + { + result[CamelToSnake(kvp.Key)] = CamelToSnakeKeys(kvp.Value?.DeepClone()); + } + return result; + case JsonArray arr: + var newArr = new JsonArray(); + foreach (var element in arr) + { + newArr.Add(CamelToSnakeKeys(element?.DeepClone())); + } + return newArr; + default: + return node?.DeepClone(); + } + } + + private static string CamelToSnake(string name) + { + var sb = new StringBuilder(name.Length + 4); + for (var i = 0; i < name.Length; i++) + { + var c = name[i]; + if (char.IsUpper(c)) + { + if (i > 0) + { + sb.Append('_'); + } + sb.Append(char.ToLowerInvariant(c)); + } + else + { + sb.Append(c); + } + } + return sb.ToString(); + } + + /// + /// Recursively fixes any trait_definition.entity_type that is missing or + /// empty. The WASM engine's Rust EntityType enum only accepts "user" or + /// "company"; an empty string fails the entire parse with error code -1. + /// + /// When is non-null (company/user + /// subtree) we inject it; when null (flag subtree, where the entity is ambiguous) + /// we drop the optional trait_definition so the rule still evaluates. + /// Workaround for replicator data that writes entity_type: ""; a no-op + /// once the replicator writes correct values. + /// + private static JsonNode? Sanitize(JsonNode? node, string? defaultEntityType) + { + switch (node) + { + case JsonObject obj: + if (obj["trait_definition"] is JsonObject td) + { + var et = td["entity_type"]; + var missing = + et == null + || et.GetValueKind() != System.Text.Json.JsonValueKind.String + || string.IsNullOrEmpty(et.GetValue()); + if (missing) + { + if (defaultEntityType != null) + { + td["entity_type"] = defaultEntityType; + } + else + { + obj.Remove("trait_definition"); + } + } + } + foreach (var kvp in obj) + { + Sanitize(kvp.Value, defaultEntityType); + } + return node; + case JsonArray arr: + foreach (var element in arr) + { + Sanitize(element, defaultEntityType); + } + return node; + default: + return node; + } + } + } +} diff --git a/src/SchematicHQ.Client/RulesEngine/Wasm/rulesengine.wasm b/src/SchematicHQ.Client/RulesEngine/Wasm/rulesengine.wasm deleted file mode 100755 index 29bd0d48263c481ac4a046da36858af81c7dd7f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 672455 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±HIeRp1zwl~a70oJaLn8mYO((dj{ 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ⅅjMUTT{ucgn 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¯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�Tr-Mlj99H_2DTd=@y3cJl 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 diff --git a/src/SchematicHQ.Client/SchematicHQ.Client.Custom.props b/src/SchematicHQ.Client/SchematicHQ.Client.Custom.props index c8b28412..b2c9fd92 100644 --- a/src/SchematicHQ.Client/SchematicHQ.Client.Custom.props +++ b/src/SchematicHQ.Client/SchematicHQ.Client.Custom.props @@ -12,6 +12,19 @@ Configure additional MSBuild properties for your project in this file: + + + + + + + + rulesengine.wasm + @@ -34,4 +47,13 @@ Configure additional MSBuild properties for your project in this file: + + + + + From ec968c74cde0a5f47ee75d102ef55263d61a7543 Mon Sep 17 00:00:00 2001 From: Christopher Brady Date: Thu, 16 Jul 2026 11:15:21 -0600 Subject: [PATCH 2/2] use fern generated schema hash --- .fernignore | 1 - .../SchemaVersionGeneratorTests.cs | 30 +++++++++ .../RulesEngine/Wasm/WasmRulesEngineTests.cs | 3 +- .../RulesEngine/Utils/GeneratedModelHash.cs | 14 ----- .../RulesEngine/Utils/VersionGenerator.cs | 48 ++++++++++++--- .../RulesEngine/Wasm/WasmRulesEngine.cs | 36 +---------- .../SchematicHQ.Client.Custom.props | 13 ---- .../generate-schema-hash.sh | 61 ------------------- 8 files changed, 72 insertions(+), 134 deletions(-) create mode 100644 src/SchematicHQ.Client.Test/RulesEngine/SchemaVersionGeneratorTests.cs delete mode 100644 src/SchematicHQ.Client/RulesEngine/Utils/GeneratedModelHash.cs delete mode 100755 src/SchematicHQ.Client/generate-schema-hash.sh diff --git a/.fernignore b/.fernignore index 02123399..33401d08 100644 --- a/.fernignore +++ b/.fernignore @@ -35,7 +35,6 @@ src/SchematicHQ.Client/Schematic.cs src/SchematicHQ.Client/SchematicHQ.Client.Custom.props src/SchematicHQ.Client/Webhooks/WebhookUtils/ src/SchematicHQ.Client/OpenFeature/ -src/SchematicHQ.Client/generate-schema-hash.sh .fern/replay.lock .fern/replay.yml .gitattributes diff --git a/src/SchematicHQ.Client.Test/RulesEngine/SchemaVersionGeneratorTests.cs b/src/SchematicHQ.Client.Test/RulesEngine/SchemaVersionGeneratorTests.cs new file mode 100644 index 00000000..e209b3f9 --- /dev/null +++ b/src/SchematicHQ.Client.Test/RulesEngine/SchemaVersionGeneratorTests.cs @@ -0,0 +1,30 @@ +using NUnit.Framework; +using SchematicHQ.Client; +using SchematicHQ.Client.RulesEngine.Utils; + +namespace SchematicHQ.Client.Test.RulesEngine +{ + ///

+ /// Guards the reflection-based resolution of the datastream cache version from the + /// Fern-generated enum. If a future codegen changes + /// the enum's shape so the single real value can't be found, this catches the regression + /// (the resolver would silently fall back to "1"). + /// + [TestFixture] + public class SchemaVersionGeneratorTests + { + [Test] + public void Resolves_Current_Fern_Schema_Version_Not_Fallback() + { + var version = SchemaVersionGenerator.GetGlobalSchemaVersion(); + + Assert.That(version, Is.Not.Null.And.Not.Empty); + // Not the "unexpected enum shape" fallback... + Assert.That(version, Is.Not.EqualTo("1")); + // ...and not the Fern placeholder member. + Assert.That(version, Is.Not.EqualTo("placeholder-for-fern-compatibility")); + // It must be one of the real (non-placeholder) values on the generated enum. + Assert.That(version, Is.EqualTo(RulesEngineSchemaVersion.V5B3E7220.Value)); + } + } +} diff --git a/src/SchematicHQ.Client.Test/RulesEngine/Wasm/WasmRulesEngineTests.cs b/src/SchematicHQ.Client.Test/RulesEngine/Wasm/WasmRulesEngineTests.cs index ce7d7a87..4fabf49e 100644 --- a/src/SchematicHQ.Client.Test/RulesEngine/Wasm/WasmRulesEngineTests.cs +++ b/src/SchematicHQ.Client.Test/RulesEngine/Wasm/WasmRulesEngineTests.cs @@ -26,10 +26,9 @@ public void SetUp() public void TearDown() => _engine.Dispose(); [Test] - public void Initializes_And_Exposes_Version_Key() + public void Initializes_From_Embedded_Wasm() { Assert.That(_engine.IsInitialized, Is.True); - Assert.That(_engine.GetVersionKey(), Is.Not.Empty); } [Test] diff --git a/src/SchematicHQ.Client/RulesEngine/Utils/GeneratedModelHash.cs b/src/SchematicHQ.Client/RulesEngine/Utils/GeneratedModelHash.cs deleted file mode 100644 index 35657a3c..00000000 --- a/src/SchematicHQ.Client/RulesEngine/Utils/GeneratedModelHash.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Auto-generated code - do not modify -// This file is automatically generated based on model file changes - -namespace SchematicHQ.Client.RulesEngine.Utils -{ - public static class GeneratedModelHash - { - /// - /// Auto-generated hash of all model files. - /// This value changes whenever any model file is modified. - /// - public const string Value = "dec34ea6"; - } -} diff --git a/src/SchematicHQ.Client/RulesEngine/Utils/VersionGenerator.cs b/src/SchematicHQ.Client/RulesEngine/Utils/VersionGenerator.cs index 8067a189..f46113dd 100644 --- a/src/SchematicHQ.Client/RulesEngine/Utils/VersionGenerator.cs +++ b/src/SchematicHQ.Client/RulesEngine/Utils/VersionGenerator.cs @@ -1,12 +1,42 @@ +using System.Reflection; + namespace SchematicHQ.Client.RulesEngine.Utils; + +/// +/// Provides the canonical rules-engine schema version used to version the datastream cache. +/// public static class SchemaVersionGenerator { - /// - /// Gets the global version for all models - /// - public static string GetGlobalSchemaVersion() - { - // Use the pre-generated hash for all models - return GeneratedModelHash.Value; - } -} \ No newline at end of file + // Fern requires the generated RulesEngineSchemaVersion enum to carry a placeholder member + // alongside the single real member, which holds the canonical rules-engine schema version. + private const string FernPlaceholderValue = "placeholder-for-fern-compatibility"; + private const string FallbackVersion = "1"; + + private static readonly string _schemaVersion = ResolveSchemaVersion(); + + /// + /// Gets the global schema version for all rules-engine models. + /// + /// Sourced from the Fern-generated enum (the + /// canonical version emitted by codegen, which changes whenever the model schema changes). + /// Resolved by reflection rather than a direct symbol reference because Fern encodes the + /// version into the member name (e.g. V5B3E7220), so a direct reference + /// would break on every schema bump; reflecting for the non-placeholder value is stable. + /// + public static string GetGlobalSchemaVersion() => _schemaVersion; + + private static string ResolveSchemaVersion() + { + var versions = typeof(RulesEngineSchemaVersion) + .GetFields(BindingFlags.Public | BindingFlags.Static) + .Where(f => f.FieldType == typeof(RulesEngineSchemaVersion)) + .Select(f => ((RulesEngineSchemaVersion)f.GetValue(null)!).Value) + .Where(v => !string.IsNullOrEmpty(v) && v != FernPlaceholderValue) + .Distinct() + .ToList(); + + // Exactly one real value is expected. Anything else means Fern changed the enum's + // shape — fall back to a stable constant so cache keys remain well-formed. + return versions.Count == 1 ? versions[0] : FallbackVersion; + } +} diff --git a/src/SchematicHQ.Client/RulesEngine/Wasm/WasmRulesEngine.cs b/src/SchematicHQ.Client/RulesEngine/Wasm/WasmRulesEngine.cs index 87ef8b35..88514425 100644 --- a/src/SchematicHQ.Client/RulesEngine/Wasm/WasmRulesEngine.cs +++ b/src/SchematicHQ.Client/RulesEngine/Wasm/WasmRulesEngine.cs @@ -31,7 +31,6 @@ internal sealed class WasmRulesEngine : IDisposable private readonly object _lock = new(); private volatile bool _initialized; - private string? _versionKey; // Wasmtime objects — kept alive for the lifetime of the engine. private Engine? _engine; @@ -48,7 +47,6 @@ internal sealed class WasmRulesEngine : IDisposable private Action? _setTime; // setCurrentTimeMillis(nowMillis) — optional private Func? _getResultJson; // getResultJson() -> ptr private Func? _getResultJsonLength; // getResultJsonLength() -> len - private Func? _getVersionKey; // get_version_key_wasm() -> ptr (C string) public WasmRulesEngine(ILogger logger) { @@ -123,19 +121,14 @@ public void Initialize() "WASM module does not export 'getResultJsonLength'" ); - // Optional exports — resolved defensively so older wasm builds still load. + // Optional export — resolved defensively so older wasm builds still load. // Without setCurrentTimeMillis the clockless wasmtime host cannot compute // metric-period reset timestamps (SCHY-471); with it, feature_usage_reset_at // is populated. _setTime = _instance.GetAction("setCurrentTimeMillis"); - _getVersionKey = _instance.GetFunction("get_version_key_wasm"); _initialized = true; - - // Cache the version key immediately — the pointer is only stable before - // any other WASM call mutates linear memory. - _versionKey = ReadVersionKeyFromWasm(); - _logger.LogDebug("WASM rules engine initialized (version: {Version})", _versionKey); + _logger.LogDebug("WASM rules engine initialized"); } } @@ -198,12 +191,6 @@ private static CheckFlagResult ToCheckFlagResult(RulesengineCheckFlagResult r) = Value = r.Value, }; - /// - /// Version key from the WASM engine, used for cache-key generation so caches - /// invalidate when the engine changes. Computed once during initialization. - /// - public string GetVersionKey() => _versionKey ?? "1"; - public void Dispose() { _store?.Dispose(); @@ -255,25 +242,6 @@ private string CallWasm(string inputJson) } } - private string ReadVersionKeyFromWasm() - { - if (_getVersionKey == null) - { - return "1"; - } - - try - { - var ptr = _getVersionKey(); - return _memory!.ReadNullTerminatedString(ptr); - } - catch (Exception ex) - { - _logger.LogWarning(ex, "Failed to read WASM version key"); - return "1"; - } - } - /// /// Recursively converts JSON object keys from camelCase to snake_case. /// diff --git a/src/SchematicHQ.Client/SchematicHQ.Client.Custom.props b/src/SchematicHQ.Client/SchematicHQ.Client.Custom.props index b2c9fd92..ff21a8b3 100644 --- a/src/SchematicHQ.Client/SchematicHQ.Client.Custom.props +++ b/src/SchematicHQ.Client/SchematicHQ.Client.Custom.props @@ -34,19 +34,6 @@ Configure additional MSBuild properties for your project in this file: - - - - - $(MSBuildThisFileDirectory)RulesEngine/Utils/GeneratedModelHash.cs - - - - - - - -