From 47f5e050565e054fb804f11d84fe4ccba4c8f7bb Mon Sep 17 00:00:00 2001 From: Sanjay Santhanam <51058514+Sanjays2402@users.noreply.github.com> Date: Tue, 21 Jul 2026 02:26:57 -0700 Subject: [PATCH] fix: preserve LaunchDarkly boolean defaults Resolve boolean flag defaults from the served fallthrough or off variation instead of the LaunchDarkly on toggle. Add focused coverage for both inverted cases. --- api/integrations/launch_darkly/services.py | 14 ++++- .../launch_darkly/test_services.py | 57 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/api/integrations/launch_darkly/services.py b/api/integrations/launch_darkly/services.py index 9c33997bb588..5a432b4c7a79 100644 --- a/api/integrations/launch_darkly/services.py +++ b/api/integrations/launch_darkly/services.py @@ -665,11 +665,23 @@ def _create_boolean_feature_states_with_segments_identities( ) -> None: for ld_environment_key, environment in environments_by_ld_environment_key.items(): ld_flag_config = ld_flag["environments"][ld_environment_key] + is_flag_on = ld_flag_config["on"] + variation_idx = ( + ld_flag_config.get("fallthrough", {}).get("variation") + if is_flag_on + else ld_flag_config.get("offVariation") + ) + enabled = is_flag_on + if variation_idx is not None: + variation_value = ld_flag["variations"][variation_idx]["value"] + if isinstance(variation_value, bool): + enabled = variation_value + feature_state, _ = FeatureState.objects.update_or_create( feature=feature, feature_segment=None, environment=environment, - defaults={"enabled": ld_flag_config["on"]}, + defaults={"enabled": enabled}, ) FeatureStateValue.objects.update_or_create( diff --git a/api/tests/unit/integrations/launch_darkly/test_services.py b/api/tests/unit/integrations/launch_darkly/test_services.py index 251bbc6b6761..5378288b4139 100644 --- a/api/tests/unit/integrations/launch_darkly/test_services.py +++ b/api/tests/unit/integrations/launch_darkly/test_services.py @@ -2,6 +2,7 @@ import io import json from operator import attrgetter +from typing import cast from unittest.mock import MagicMock import pytest @@ -17,8 +18,10 @@ from environments.identities.traits.models import Trait from environments.models import Environment from features.models import Feature, FeatureState +from integrations.launch_darkly import types as ld_types from integrations.launch_darkly.models import LaunchDarklyImportRequest from integrations.launch_darkly.services import ( + _create_boolean_feature_states_with_segments_identities, _serialize_variation_value, create_import_request, process_import_request, @@ -263,6 +266,60 @@ def test_process_import_request__success__expected_status( # type: ignore[no-un [tag.label for tag in tagged_feature.tags.all()] == ["testtag", "testtag2"] +@pytest.mark.parametrize( + ("is_on", "default_config", "expected_enabled"), + [ + (True, {"fallthrough": {"variation": 1}}, False), + (False, {"offVariation": 0}, True), + ], +) +def test_create_boolean_feature_states__served_variation__sets_expected_state( + is_on: bool, + default_config: dict[str, object], + expected_enabled: bool, + mocker: MockerFixture, +) -> None: + # Given + ld_flag = cast( + ld_types.FeatureFlag, + { + "kind": "boolean", + "variations": [{"value": True}, {"value": False}], + "environments": { + "test": { + "on": is_on, + **default_config, + } + }, + }, + ) + environment = cast(Environment, MagicMock(spec=Environment)) + feature_state = MagicMock(spec=FeatureState) + feature_state_manager = mocker.patch( + "integrations.launch_darkly.services.FeatureState.objects.update_or_create", + return_value=(feature_state, True), + ) + mocker.patch( + "integrations.launch_darkly.services.FeatureStateValue.objects.update_or_create" + ) + mocker.patch("integrations.launch_darkly.services._import_targets") + mocker.patch("integrations.launch_darkly.services._import_rules") + + # When + _create_boolean_feature_states_with_segments_identities( + import_request=MagicMock(spec=LaunchDarklyImportRequest), + ld_flag=ld_flag, + feature=MagicMock(spec=Feature), + environments_by_ld_environment_key={"test": environment}, + segments_by_ld_key={}, + ) + + # Then + assert feature_state_manager.call_args.kwargs["defaults"] == { + "enabled": expected_enabled + } + + @pytest.mark.django_db(transaction=True) def test_process_import_request__already_completed__does_not_reprocess( ld_client_class_mock: MagicMock,