Skip to content

[dotnet] Enable flag eval metrics tests#6689

Open
sameerank wants to merge 6 commits intomainfrom
sameerank/FFL-1946/enable-dotnet-flag-eval-metrics
Open

[dotnet] Enable flag eval metrics tests#6689
sameerank wants to merge 6 commits intomainfrom
sameerank/FFL-1946/enable-dotnet-flag-eval-metrics

Conversation

@sameerank
Copy link
Copy Markdown
Contributor

@sameerank sameerank commented Apr 4, 2026

Motivation

Prepare the .NET weblog for test_flag_eval_metrics.py tests to validate the new feature_flag.evaluations OTel metric implementation.

Related PRs:

Changes

Weblog (utils/build/docker/dotnet/weblog/):

  • Fix JsonElement handling in FeatureFlagEvaluatorController.cs

    • ASP.NET Core's System.Text.Json deserializes object properties as JsonElement, not native types
    • Added helper methods to extract actual values from JsonElement before calling OpenFeature APIs
    • This prevents InvalidCastException that was occurring before OpenFeature hooks could fire
  • Upgrade OpenFeature packages in app.csproj:

    • OpenFeature: 2.0.0 → 2.3.0 (required for FinallyAsync hook signature with FlagEvaluationDetails<T>)
    • Datadog.FeatureFlags.OpenFeature: Use wildcard version to pick up local/CI builds

Note: The tests/ffe/test_flag_eval_metrics.py tests remain marked as missing_feature in the manifest until dd-trace-dotnet v3.42.0 is released with flag eval metrics support.

Workflow

  1. ⚠️ Create your PR as draft ⚠️
  2. Work on you PR until the CI passes
  3. Mark it as ready for review
    • Test logic is modified? -> Get a review from RFC owner.
    • Framework is modified, or non obvious usage of it -> get a review from R&P team

🚀 Once your PR is reviewed and the CI green, you can merge it!

🛟 #apm-shared-testing 🛟

Reviewer checklist

  • Anything but tests/ or manifests/ is modified ? I have the approval from R&P team
  • A docker base image is modified?
    • the relevant build-XXX-image label is present
  • A scenario is added, removed or renamed?

System.Text.Json deserializes JSON values into Dictionary<string, object>
as JsonElement wrappers rather than native strings. The previous code
used `attr.Value as string` which returned null for JsonElement values,
causing targeting rules to fail.

This fix properly extracts string values from JsonElement, enabling
targeting rule evaluation to work correctly.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 4, 2026

CODEOWNERS have been resolved as:

utils/build/docker/dotnet/poc.Dockerfile                                @DataDog/apm-dotnet @DataDog/asm-dotnet @DataDog/system-tests-core
utils/build/docker/dotnet/weblog/Controllers/FeatureFlagEvaluatorController.cs  @DataDog/apm-dotnet @DataDog/asm-dotnet @DataDog/system-tests-core
utils/build/docker/dotnet/weblog/app.csproj                             @DataDog/apm-dotnet @DataDog/asm-dotnet @DataDog/system-tests-core

@sameerank sameerank changed the title Enable dotnet flag eval metrics tests Enable dotnet flag eval metrics tests [dotnet@sameerank/FFL-1946/add-flag-eval-metrics] Apr 4, 2026
@datadog-datadog-prod-us1-2

This comment has been minimized.

{
value = request.VariationType?.ToUpper() switch
{
"BOOLEAN" => await _client.GetBooleanValueAsync(request.Flag, Convert.ToBoolean(request.DefaultValue), context),
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Problem

The EvaluateRequest class has a DefaultValue property typed as object:

public class EvaluateRequest
{
    public object DefaultValue { get; set; }  // Can be bool, int, string, etc.
}

When ASP.NET Core's System.Text.Json deserializes JSON into an object property, it does not convert to native .NET types. Instead, it wraps the value in a JsonElement:

{ "defaultValue": true }     // Becomes JsonElement, not bool
{ "defaultValue": 42 }       // Becomes JsonElement, not int
{ "defaultValue": "hello" }  // Becomes JsonElement, not string

The original code assumed native types:

Convert.ToBoolean(request.DefaultValue)  // Throws! DefaultValue is JsonElement

Convert.ToBoolean() has no knowledge of JsonElement and throws InvalidCastException.

Why Previous Tests Didn't Fail

The original code had a catch block that swallowed all exceptions:

try
{
    value = ... Convert.ToBoolean(request.DefaultValue) ...
}
catch (Exception ex)
{
    value = request.DefaultValue;
    reason = "ERROR";
}

Previous tests (test_dynamic_evaluation.py, test_exposures.py) were asserting on:

  • The evaluated flag value (returned by the endpoint)
  • The reason field in the response

When InvalidCastException was thrown, the catch block returned reason = "ERROR" and value = request.DefaultValue. If a test expected an error case or didn't care about the reason, it would pass.

Why Flag Eval Metrics Tests Failed

The metrics tests need OpenFeature hooks to fire. The exception was thrown before calling the OpenFeature API:

  1. Convert.ToBoolean(JsonElement) throws
  2. The catch block catches it and returns "ERROR"
  3. OpenFeature is never called → hooks never fire → no metrics emitted

The tests assert on metrics received by the OTLP intake, not on the HTTP response. No OpenFeature call = no hooks = no metrics = test failure.

The Fix

Check if the value is a JsonElement and extract the actual value:

private static bool GetDefaultValueAsBool(object defaultValue)
{
    if (defaultValue is JsonElement jsonElement)
    {
        return jsonElement.ValueKind switch
        {
            JsonValueKind.True => true,
            JsonValueKind.False => false,
            JsonValueKind.String => bool.Parse(jsonElement.GetString()),
            _ => false
        };
    }
    return Convert.ToBoolean(defaultValue);  // Fallback for non-JsonElement
}

@sameerank sameerank force-pushed the sameerank/FFL-1946/enable-dotnet-flag-eval-metrics branch from 136dee4 to 84f94a9 Compare April 7, 2026 13:50
@sameerank sameerank changed the title Enable dotnet flag eval metrics tests [dotnet@sameerank/FFL-1946/add-flag-eval-metrics] Enable dotnet flag eval metrics tests [dotnet@b2040ea748a07f13cf4d6cb3a78b592e6108f577] Apr 7, 2026
@sameerank sameerank force-pushed the sameerank/FFL-1946/enable-dotnet-flag-eval-metrics branch from 84f94a9 to 05a4aed Compare April 7, 2026 14:18
Remove irrelevant skips for:
- Test_FFE_Eval_Metric_Parse_Error_Invalid_Regex
- Test_FFE_Eval_No_Config_Loaded

The .NET SDK uses a managed evaluator (not libdatadog), and now
correctly returns PARSE_ERROR for invalid regex patterns and
PROVIDER_NOT_READY when no config is loaded.

Related: DataDog/dd-trace-dotnet#8367
@sameerank sameerank changed the title Enable dotnet flag eval metrics tests [dotnet@b2040ea748a07f13cf4d6cb3a78b592e6108f577] Enable dotnet flag eval metrics tests [dotnet@c448add68042e4dbf059960db74c28c42556c07f] Apr 7, 2026
@sameerank sameerank changed the title Enable dotnet flag eval metrics tests [dotnet@c448add68042e4dbf059960db74c28c42556c07f] [dotnet] Enable FFE flag eval metrics tests (dd-trace-dotnet@9c81be358efcf3eb5d4f4e6bc494c73e8f39d8a1) Apr 7, 2026
@sameerank sameerank changed the title [dotnet] Enable FFE flag eval metrics tests (dd-trace-dotnet@9c81be358efcf3eb5d4f4e6bc494c73e8f39d8a1) [dotnet] Enable flag eval metrics tests (dd-trace-dotnet@5cf5bc37f758dfdb95aa9b83244d6b9c76762f48) Apr 7, 2026
- Add local NuGet source from binaries folder if nupkg files present
- Update OpenFeature to 2.3.0 (required by Datadog.FeatureFlags.OpenFeature 2.0.1)
- Use wildcard version for Datadog.FeatureFlags.OpenFeature to pick up local builds
@sameerank sameerank changed the title [dotnet] Enable flag eval metrics tests (dd-trace-dotnet@5cf5bc37f758dfdb95aa9b83244d6b9c76762f48) [dotnet] Enable flag eval metrics tests [dotnet@5cf5bc37f758dfdb95aa9b83244d6b9c76762f48] Apr 7, 2026
The flag eval metrics feature is implemented in dd-trace-dotnet PR #8367
but not yet released. Mark as missing_feature until v3.42.0 is published.
@sameerank sameerank changed the title [dotnet] Enable flag eval metrics tests [dotnet@5cf5bc37f758dfdb95aa9b83244d6b9c76762f48] [dotnet] Enable flag eval metrics tests Apr 8, 2026
@sameerank
Copy link
Copy Markdown
Contributor Author

sameerank commented Apr 8, 2026

Leaving the test disabled for now because the changes in DataDog/dd-trace-dotnet#8367 haven't been published yet. Tests pass when run this locally: DataDog/dd-trace-dotnet#8367 (comment)

Copy-pasted from the referenced comment:

This is what I did (not 100% that this is the most efficient approach, but it works). I downloaded and extracted these .zip files:

Screenshot 2026-04-08 at 12 30 58 PM

and

Screenshot 2026-04-08 at 12 31 26 PM

And extracted datadog-dotnet-apm-3.42.0.arm64.tar.gz and copied the contents to
/Users/.../system-tests/binaries along with two *.nupkg files from nuget-packages:

Screenshot 2026-04-08 at 12 41 31 PM

And then did the following steps to run system tests locally

cd /Users/../system-tests
# Build the docker image
./build.sh --library dotnet --weblog-variant poc --images weblog
# Run tests
./run.sh FEATURE_FLAGGING_AND_EXPERIMENTATION --library dotnet -k "test_ffe_eval"
# Output shows that we are using the not-yet-published version 3.42.0 and tests are passing
=============================== test context ================================
Scenario: FEATURE_FLAGGING_AND_EXPERIMENTATION
Logs folder: ./logs_feature_flagging_and_experimentation
Starting containers...
Agent: 7.77.2
Backend: datad0g.com
Library: dotnet@3.42.0
Weblog variant: poc
Weblog system: Linux weblog 6.12.76-linuxkit #1 SMP Fri Mar  6 10:10:19 UTC 2026 aarch64 GNU/Linux

============================ test session starts ============================
collected 2427 items / 2410 deselected / 17 selected                        
-------------------------------- tests setup --------------------------------

tests/ffe/test_flag_eval_metrics.py .................

--------------------- Wait for library interface (40s) ----------------------
---------------------- Wait for agent interface (30s) -----------------------
---------------------- Wait for backend interface (0s) ----------------------

tests/ffe/test_flag_eval_metrics.py .................                 [100%]

- generated xml file: /Users/.../system-tests/logs_feature_flagging_and_experimentation/reportJunit.xml -
============== 17 passed, 2410 deselected in 175.48s (0:02:55) ==============

RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y curl

# install dd-trace-dotnet (must be done before setting LD_PRELOAD)
COPY utils/build/docker/dotnet/install_ddtrace.sh binaries/ /binaries/
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why run COPY binaries/ commands twice?

Stage 1: build-app (SDK image)

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-app

# NEW: Copy binaries for NuGet package resolution
COPY binaries/ /binaries/
RUN if ls /binaries/*.nupkg 1> /dev/null 2>&1; then \
        dotnet nuget add source /binaries --name local-packages; \
    fi

# NuGet packages are resolved HERE
RUN dotnet restore
RUN dotnet publish

Purpose: Build the weblog application. NuGet packages (like Datadog.FeatureFlags.OpenFeature.*.nupkg) must be available as a NuGet source before dotnet restore runs.

Stage 2: runtime (ASP.NET image)

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime

# EXISTING: Copy binaries for tracer installation
COPY utils/build/docker/dotnet/install_ddtrace.sh binaries/ /binaries/
RUN /binaries/install_ddtrace.sh

Purpose: Install the Datadog tracer into the runtime image. The install_ddtrace.sh script uses:

  • Native profiler: Datadog.Trace.ClrProfiler.Native.so
  • Managed tracer DLLs: net6.0/Datadog.Trace.dll, etc.

@sameerank sameerank marked this pull request as ready for review April 9, 2026 07:19
@sameerank sameerank requested review from a team as code owners April 9, 2026 07:19
Copy link
Copy Markdown
Collaborator

@nccatoni nccatoni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (for @DataDog/system-tests-core) but you should get a review from someone more familiar with the weblog

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants