-
Notifications
You must be signed in to change notification settings - Fork 15
Enable PHP FFE evaluation system tests #7003
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
224c241
8fbb3a5
9bcf43d
e2d4370
19b9c41
83bc16b
afd0d5f
1d6ac67
552010f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3644,7 +3644,6 @@ manifest: | |
| tests/parametric/test_dynamic_configuration.py::TestDynamicConfigV1_ServiceTargets::test_not_match_service_target: irrelevant (APMAPI-1003) | ||
| tests/parametric/test_dynamic_configuration.py::TestDynamicConfigV2: v1.31.0 | ||
| tests/parametric/test_ffe/test_dynamic_evaluation.py::Test_Feature_Flag_Dynamic_Evaluation: v1.56.0 | ||
| tests/parametric/test_ffe/test_dynamic_evaluation.py::Test_Feature_Flag_Dynamic_Evaluation::test_ffe_of7_empty_targeting_key: bug (FFL-1729) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was fixed; removing |
||
| tests/parametric/test_ffe/test_span_enrichment.py: missing_feature | ||
| tests/parametric/test_headers_b3.py::Test_Headers_B3::test_headers_b3_migrated_extract_invalid: # Modified by easy win activation script | ||
| - declaration: missing_feature (Need to remove b3=b3multi alias) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2014,7 +2014,6 @@ manifest: | |
| tests/parametric/test_dynamic_configuration.py::TestDynamicConfigV1_ServiceTargets::test_not_match_service_target: bug (APMAPI-865) | ||
| tests/parametric/test_dynamic_configuration.py::TestDynamicConfigV2: *ref_4_23_0 | ||
| tests/parametric/test_ffe/test_dynamic_evaluation.py::Test_Feature_Flag_Dynamic_Evaluation: *ref_5_75_0 | ||
| tests/parametric/test_ffe/test_dynamic_evaluation.py::Test_Feature_Flag_Dynamic_Evaluation::test_ffe_of7_empty_targeting_key: bug (FFL-1730) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was fixed; removing |
||
| tests/parametric/test_ffe/test_span_enrichment.py: "missing_feature (dd-trace-js#8343)" | ||
| tests/parametric/test_headers_b3.py::Test_Headers_B3::test_headers_b3_migrated_extract_invalid: missing_feature (Need to remove b3=b3multi alias) | ||
| tests/parametric/test_headers_b3.py::Test_Headers_B3::test_headers_b3_migrated_extract_valid: missing_feature (Need to remove b3=b3multi alias) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,11 +2,11 @@ | |
|
|
||
| import json | ||
| import pytest | ||
| import time | ||
| from pathlib import Path | ||
| from typing import Any | ||
|
|
||
| from utils import ( | ||
| context, | ||
| features, | ||
| scenarios, | ||
| ) | ||
|
|
@@ -16,6 +16,8 @@ | |
|
|
||
| RC_PRODUCT = "FFE_FLAGS" | ||
| RC_PATH = f"datadog/2/{RC_PRODUCT}" | ||
| FFE_READY_RETRY_ATTEMPTS = 10 | ||
| FFE_READY_RETRY_INTERVAL_SECONDS = 0.2 | ||
|
|
||
| parametrize = pytest.mark.parametrize | ||
|
|
||
|
|
@@ -81,6 +83,44 @@ def _set_and_wait_ffe_rc( | |
| return test_agent.wait_for_rc_apply_state(RC_PRODUCT, state=RemoteConfigApplyState.ACKNOWLEDGED, clear=True) | ||
|
|
||
|
|
||
| def _is_ffe_waiting_for_rc(result: dict[str, Any]) -> bool: | ||
| provider_state = result.get("providerState") | ||
| return result.get("errorCode") == "PROVIDER_NOT_READY" or ( | ||
| isinstance(provider_state, dict) and provider_state.get("hasConfig") is False | ||
| ) | ||
|
|
||
|
|
||
| def _ffe_evaluate_with_rc_retry( | ||
| test_library: APMLibrary, | ||
| *, | ||
| flag: str, | ||
| variation_type: str, | ||
| default_value: bool | str | float | dict[str, Any], | ||
| targeting_key: str, | ||
| attributes: dict[str, Any] | None = None, | ||
| ) -> dict[str, Any]: | ||
| result = test_library.ffe_evaluate( | ||
| flag=flag, | ||
| variation_type=variation_type, | ||
| default_value=default_value, | ||
| targeting_key=targeting_key, | ||
| attributes=attributes, | ||
| ) | ||
| for _ in range(FFE_READY_RETRY_ATTEMPTS - 1): | ||
| if not _is_ffe_waiting_for_rc(result): | ||
| return result | ||
| time.sleep(FFE_READY_RETRY_INTERVAL_SECONDS) | ||
| result = test_library.ffe_evaluate( | ||
| flag=flag, | ||
| variation_type=variation_type, | ||
| default_value=default_value, | ||
| targeting_key=targeting_key, | ||
| attributes=attributes, | ||
| ) | ||
|
|
||
| return result | ||
|
|
||
|
|
||
| @scenarios.parametric | ||
| @features.feature_flags_dynamic_evaluation | ||
| class Test_Feature_Flag_Dynamic_Evaluation: | ||
|
|
@@ -111,13 +151,6 @@ def test_ffe_flag_evaluation(self, test_case_file: str, test_agent: TestAgentAPI | |
| 4. Handles user targeting, attribute matching, and rollout percentages | ||
|
|
||
| """ | ||
| # Skip OF.7 (empty targeting key) test for libraries with known bugs | ||
| # Java: FFL-1729 - OpenFeature Java SDK rejects empty targeting keys | ||
| # Node.js: FFL-1730 - OpenFeature JS SDK rejects empty targeting keys | ||
| if test_case_file == "test-case-of-7-empty-targeting-key.json": | ||
| if context.library.name in ("java", "nodejs"): | ||
| pytest.skip("OF.7 empty targeting key bug: FFL-1729 (java), FFL-1730 (nodejs)") | ||
|
Comment on lines
-114
to
-119
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was fixed; removing - works for php as well |
||
|
|
||
| # Load the test case file | ||
| test_case_path = Path(__file__).parent / test_case_file | ||
|
|
||
|
|
@@ -131,7 +164,7 @@ def test_ffe_flag_evaluation(self, test_case_file: str, test_agent: TestAgentAPI | |
| _set_and_wait_ffe_rc(test_agent, UFC_FIXTURE_DATA) | ||
|
|
||
| # Initialize FFE provider | ||
| success = test_library.ffe_start() | ||
| success = test_library.ffe_start(UFC_FIXTURE_DATA) | ||
| assert success, "Failed to start FFE provider" | ||
|
|
||
| # Run each test case | ||
|
|
@@ -143,13 +176,18 @@ def test_ffe_flag_evaluation(self, test_case_file: str, test_agent: TestAgentAPI | |
| attributes = test_case.get("attributes", {}) | ||
| expected_result = test_case["result"]["value"] | ||
|
|
||
| result = test_library.ffe_evaluate( | ||
| result = _ffe_evaluate_with_rc_retry( | ||
| test_library, | ||
| flag=flag, | ||
| variation_type=variation_type, | ||
| default_value=default_value, | ||
| targeting_key=targeting_key, | ||
| attributes=attributes, | ||
| ) | ||
| assert not _is_ffe_waiting_for_rc(result), ( | ||
| f"Test case {i} in {test_case_file} failed: FFE provider did not load RC data after " | ||
| f"{FFE_READY_RETRY_ATTEMPTS} attempts; result={result}" | ||
| ) | ||
| actual_value = result.get("value") | ||
|
|
||
| # Assert the evaluation result matches expected value | ||
|
|
@@ -158,33 +196,3 @@ def test_ffe_flag_evaluation(self, test_case_file: str, test_agent: TestAgentAPI | |
| f"flag='{flag}', targetingKey='{targeting_key}', " | ||
| f"expected={expected_result}, actual={actual_value}" | ||
| ) | ||
|
|
||
| @parametrize("library_env", [{**DEFAULT_ENVVARS}]) | ||
| def test_ffe_of7_empty_targeting_key(self, test_agent: TestAgentAPI, test_library: APMLibrary) -> None: | ||
| """OF.7: Empty string is a valid targeting key. | ||
|
Comment on lines
-162
to
-164
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. special test not needed; using the centralized fixtures again for all languages |
||
|
|
||
| This test validates that flag evaluation succeeds when the targeting key | ||
| is an empty string. The flag should still match allocations and return | ||
| the expected value, not fail with TARGETING_KEY_MISSING. | ||
|
|
||
| Temporary dedicated test until FFL-1729 (Java) and FFL-1730 (Node.js) are resolved. | ||
| """ | ||
| # Set up UFC Remote Config and wait for it to be applied | ||
| _set_and_wait_ffe_rc(test_agent, UFC_FIXTURE_DATA) | ||
|
|
||
| # Initialize FFE provider | ||
| success = test_library.ffe_start() | ||
| assert success, "Failed to start FFE provider" | ||
|
|
||
| # Evaluate flag with empty targeting key | ||
| result = test_library.ffe_evaluate( | ||
| flag="empty-targeting-key-flag", | ||
| variation_type="STRING", | ||
| default_value="default", | ||
| targeting_key="", | ||
| attributes={}, | ||
| ) | ||
|
|
||
| assert result.get("value") == "on-value", ( | ||
| f"OF.7 failed: empty targeting key should return 'on-value', got '{result.get('value')}'" | ||
| ) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was fixed; removing