Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
/tests/ @DataDog/system-tests-reviewers

# FFE
/.github/chainguard/self.update-ffe-fixtures.create-pr.sts.yaml @DataDog/feature-flagging-and-experimentation-sdk @DataDog/system-tests-core
/.github/workflows/update-ffe-fixtures.yml @DataDog/feature-flagging-and-experimentation-sdk @DataDog/system-tests-core
/utils/scripts/update_ffe_fixtures.py @DataDog/feature-flagging-and-experimentation-sdk @DataDog/system-tests-core
/utils/docker_fixtures/_mock_ffe_agentless_backend.py @DataDog/feature-flagging-and-experimentation-sdk @DataDog/system-tests-core
/utils/build/docker/dotnet/parametric/Endpoints/FfeTestApi.cs @DataDog/feature-flagging-and-experimentation-sdk @DataDog/system-tests-core
/utils/build/docker/dotnet/weblog/Controllers/FeatureFlagEvaluatorController.cs @DataDog/feature-flagging-and-experimentation-sdk @DataDog/system-tests-core
Expand All @@ -23,6 +26,7 @@
/utils/build/docker/php/common/ffe.php @DataDog/feature-flagging-and-experimentation-sdk @DataDog/system-tests-core
/tests/ffe/ @DataDog/feature-flagging-and-experimentation-sdk
/tests/test_the_test/test_mock_ffe_agentless_backend.py @DataDog/feature-flagging-and-experimentation-sdk
/tests/test_the_test/test_update_ffe_fixtures.py @DataDog/feature-flagging-and-experimentation-sdk
/tests/parametric/test_ffe/ @DataDog/feature-flagging-and-experimentation-sdk

# SDK cap
Expand Down
14 changes: 14 additions & 0 deletions .github/chainguard/self.update-ffe-fixtures.create-pr.sts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
issuer: https://token.actions.githubusercontent.com

subject: repo:DataDog/system-tests:ref:refs/heads/main

claim_pattern:
event_name: (workflow_dispatch|schedule)
ref: refs/heads/main
ref_protected: "true"
job_workflow_ref: DataDog/system-tests/\.github/workflows/update-ffe-fixtures\.yml@refs/heads/main

permissions:
contents: write
pull_requests: write
87 changes: 87 additions & 0 deletions .github/workflows/update-ffe-fixtures.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
name: Update FFE fixtures

on:
workflow_dispatch:
inputs:
fixture_ref:
description: Branch, tag, or commit from DataDog/ffe-system-test-data
required: true
default: main
type: string
schedule:
- cron: "0 0 * * 0"

concurrency:
group: update-ffe-fixtures
cancel-in-progress: false

jobs:
update-ffe-fixtures:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write

steps:
- uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98
with:
persist-credentials: false

- name: Update fixture snapshot
id: fixtures
env:
FFE_FIXTURE_REF: ${{ inputs.fixture_ref || 'main' }}
run: python3 utils/scripts/update_ffe_fixtures.py --ref "$FFE_FIXTURE_REF"

- uses: DataDog/dd-octo-sts-action@96a25462dbcb10ebf0bfd6e2ccc917d2ab235b9a # v1.0.4
if: steps.fixtures.outputs.changed == 'true'
id: octo-sts
with:
scope: DataDog/system-tests
policy: self.update-ffe-fixtures.create-pr

- name: Check for an open fixture update PR
if: steps.fixtures.outputs.changed == 'true'
id: existing-pr
env:
GH_TOKEN: ${{ steps.octo-sts.outputs.token }}
run: |
count=$(gh pr list --repo "$GITHUB_REPOSITORY" \
--head actions/update-ffe-fixtures --state open \
--json headRefName,headRepositoryOwner,isCrossRepository \
--jq '[.[] | select(
.headRefName == "actions/update-ffe-fixtures" and
.headRepositoryOwner.login == "DataDog" and
(.isCrossRepository | not)
)] | length')
echo "count=$count" >> "$GITHUB_OUTPUT"

- name: Create Pull Request
if: >-
steps.fixtures.outputs.changed == 'true' && steps.existing-pr.outputs.count == '0'
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
token: ${{ steps.octo-sts.outputs.token }}
branch: actions/update-ffe-fixtures
base: main
commit-message: "test(ffe): update canonical fixtures"
title: "test(ffe): update canonical fixtures"
draft: true
sign-commits: true
add-paths: tests/parametric/test_ffe/ffe-system-test-data
body: |
## Motivation

Keep SDK behavior consistent with the shared FFE evaluator contract.

## Changes

Refresh the checked-in snapshot to [${{ steps.fixtures.outputs.source_commit }}](https://github.com/DataDog/ffe-system-test-data/commit/${{ steps.fixtures.outputs.source_commit }}), containing ${{ steps.fixtures.outputs.fixture_count }} evaluation cases.

Ordinary test runs use the snapshot without network access. Resolve newly exposed evaluator failures before merging; correct shared expectations upstream only when they are wrong. Scheduled updates leave an existing update PR untouched to preserve review and fixes.

## Workflow

1. Keep this PR as a draft while validating the updated fixtures against the supported SDKs.
2. Follow the repository's [review workflow](https://github.com/DataDog/system-tests/blob/main/.github/pull_request_template.md).
31 changes: 30 additions & 1 deletion tests/ffe/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,35 @@ This directory contains system tests for the Feature Flags & Experimentation (FF
| `test_flag_eval_metrics.py` | Evaluation metrics (OTel counter) |
| `test_flag_eval_evp.py` | Server-side EVP flagevaluation payloads, aggregation, and bounds |

## Canonical parametric fixtures

The parametric evaluation suite reads the checked-in snapshot under
`tests/parametric/test_ffe/ffe-system-test-data`. Its upstream source and exact
commit are recorded in `SOURCE.md` inside that directory.

Change shared evaluator cases in
[`DataDog/ffe-system-test-data`](https://github.com/DataDog/ffe-system-test-data)
first, then refresh the snapshot:

```bash
python3 utils/scripts/update_ffe_fixtures.py --ref <branch-tag-or-commit>
```

The updater imports `ufc-config.json` and `evaluation-cases/*.json` only. Ordinary
test runs use those checked-in files without submodules or network access. A
weekly/manual workflow opens a signed draft PR when their contents change and
leaves any existing fixture update PR untouched. Review and resolve newly exposed
SDK failures before merging an update.

Dynamic evaluation checks each case's value, reason, and explicit error code.
Cases with optional `capabilities` still run their baseline `result`; enabling
capability-specific provider options requires separate harness support.
Remote Configuration tests and the mocked agentless backend read the same UFC.
Serial-ID metadata and span-enrichment tests select their flag definitions from
the shared corpus using their dedicated evaluation-case files. Their integration
harnesses retain trace construction and metadata assertions; no separate local
configuration copies are needed.

## Running FFE Tests

```bash
Expand Down Expand Up @@ -197,7 +226,7 @@ The tests use `interfaces.agent.get_metrics()` to retrieve metrics from the agen

### 1. Test returns `parse_error` instead of expected reason
- Check UFC fixture format (especially `totalShards` placement)
- Verify the fixture matches `flags-v1.json` format in dd-trace-py
- Verify the fixture matches the canonical `ffe-system-test-data/ufc-config.json` format

### 2. Test returns `static` instead of `split`
- Need multiple variations with different shard ranges
Expand Down
2 changes: 1 addition & 1 deletion tests/ffe/test_flag_eval_evp.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def assert_no_duplicate_visible_events(events: list[tuple[JSON, JSON]]) -> None:
class FlagevaluationEgressContract:
"""One flag-evaluation contract inherited by each supported topology adapter."""

# Agentless scenarios preload flags-v1.json before the weblog starts. Use the
# Agentless scenarios preload the canonical UFC before the weblog starts. Use the
# same known fixture key in every topology; the Agent scenario installs an
# equivalent fixture through Remote Config below.
flag_key = "empty-targeting-key-flag"
Expand Down
12 changes: 12 additions & 0 deletions tests/parametric/test_ffe/ffe-system-test-data/SOURCE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# FFE Fixture Snapshot

These files are copied from the canonical FFE fixture repository.

Canonical source: https://github.com/DataDog/ffe-system-test-data
Source commit: cb4a8620adb90f4ada757e1042e346efa8035364

Do not edit these fixtures directly in system-tests. Add or update shared FFE behavior in
ffe-system-test-data first, then refresh this snapshot.

The weekly update workflow runs `python3 utils/scripts/update_ffe_fixtures.py` and opens a signed
draft test PR only when the server evaluator fixture contents change.
Original file line number Diff line number Diff line change
@@ -1,38 +1,41 @@
[
{
"flag": "boolean-false-assignment",
"variationType": "BOOLEAN",
"defaultValue": true,
"targetingKey": "alice",
"attributes": {
"should_disable_feature": true
},
"defaultValue": true,
"flag": "boolean-false-assignment",
"result": {
"reason": "TARGETING_MATCH",
"value": false
}
},
"targetingKey": "alice",
"variationType": "BOOLEAN"
},
{
"flag": "boolean-false-assignment",
"variationType": "BOOLEAN",
"defaultValue": true,
"targetingKey": "bob",
"attributes": {
"should_disable_feature": false
},
"defaultValue": true,
"flag": "boolean-false-assignment",
"result": {
"reason": "TARGETING_MATCH",
"value": true
}
},
"targetingKey": "bob",
"variationType": "BOOLEAN"
},
{
"flag": "boolean-false-assignment",
"variationType": "BOOLEAN",
"defaultValue": true,
"targetingKey": "charlie",
"attributes": {
"unknown_attribute": "value"
},
"defaultValue": true,
"flag": "boolean-false-assignment",
"result": {
"reason": "DEFAULT",
"value": true
}
},
"targetingKey": "charlie",
"variationType": "BOOLEAN"
}
]
]
Loading
Loading