Skip to content

Commit

Permalink
fix: Add multivariate values when cloning identities (#3894)
Browse files Browse the repository at this point in the history
  • Loading branch information
novakzaballa authored May 13, 2024
1 parent 9536444 commit 92e3e9f
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 5 deletions.
1 change: 1 addition & 0 deletions api/edge_api/identities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,5 +259,6 @@ def clone_flag_states_from(self, source_identity: "EdgeIdentity") -> None:
feature=feature_in_source.feature,
feature_state_value=feature_in_source.feature_state_value,
enabled=feature_in_source.enabled,
multivariate_feature_state_values=feature_in_source.multivariate_feature_state_values,
)
self.add_feature_override(feature_state_target)
9 changes: 7 additions & 2 deletions api/features/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -987,12 +987,17 @@ def copy_identity_feature_states(
source_feature_id
].enabled

# Copy feature state value from source feature_state
if source_feature_state.feature.type == MULTIVARIATE:
mv_values = [
mv_value.clone(feature_state=target_feature_state, persist=False)
for mv_value in source_feature_state.multivariate_feature_state_values.all()
]
MultivariateFeatureStateValue.objects.bulk_create(mv_values)

target_feature_state.feature_state_value.copy_from(
source_feature_state.feature_state_value
)

# Save changes to target feature_state
target_feature_state.save()

@hook(AFTER_SAVE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
import pytest
from core.constants import BOOLEAN, INTEGER, STRING
from django.urls import reverse
from flag_engine.features.models import FeatureModel, FeatureStateModel
from flag_engine.features.models import (
FeatureModel,
FeatureStateModel,
MultivariateFeatureOptionModel,
MultivariateFeatureStateValueList,
MultivariateFeatureStateValueModel,
)
from mypy_boto3_dynamodb.service_resource import Table
from pytest_lazyfixture import lazy_fixture
from rest_framework import status
Expand All @@ -18,6 +24,7 @@
IdentityModel,
)
from features.models import Feature
from features.multivariate.models import MultivariateFeatureOption
from projects.models import Project
from tests.integration.helpers import create_mv_option_with_api
from util.mappers.engine import map_feature_to_engine
Expand Down Expand Up @@ -1082,9 +1089,24 @@ def features_for_identity_clone_flag_states_from(
project
)

mv_feature = Feature.objects.create(
type="MULTIVARIATE",
name="mv_feature",
initial_value="foo",
project=project,
)

mv_variant_1 = MultivariateFeatureOption.objects.create(
feature=mv_feature,
default_percentage_allocation=0,
type=STRING,
string_value="bar",
)

feature_model_1: FeatureModel = map_feature_to_engine(feature=feature_1)
feature_model_2: FeatureModel = map_feature_to_engine(feature=feature_2)
feature_model_3: FeatureModel = map_feature_to_engine(feature=feature_3)
mv_feature_model: FeatureModel = map_feature_to_engine(feature=mv_feature)

source_identity: EdgeIdentity = create_identity(identifier="source_identity")
target_identity: EdgeIdentity = create_identity(identifier="target_identity")
Expand All @@ -1105,6 +1127,21 @@ def features_for_identity_clone_flag_states_from(
feature_state_value=source_feature_state_2_value,
)

source_mv_feature_state = FeatureStateModel(
feature=mv_feature_model,
environment_id=dynamo_enabled_environment,
enabled=True,
multivariate_feature_state_values=MultivariateFeatureStateValueList(),
)
source_mv_feature_state.multivariate_feature_state_values.append(
MultivariateFeatureStateValueModel(
multivariate_feature_option=MultivariateFeatureOptionModel(
value=mv_variant_1.value
),
percentage_allocation=100,
)
)

target_feature_state_2_value = "Target Identity value for feature 2"
target_feature_state_2 = FeatureStateModel(
feature=feature_model_2,
Expand All @@ -1122,6 +1159,7 @@ def features_for_identity_clone_flag_states_from(
# Add feature states for features 1 and 2 to source identity
source_identity.add_feature_override(feature_state=source_feature_state_1)
source_identity.add_feature_override(feature_state=source_feature_state_2)
source_identity.add_feature_override(feature_state=source_mv_feature_state)

# Add feature states for features 2 and 3 to target identity.
target_identity.add_feature_override(feature_state=target_feature_state_2)
Expand Down Expand Up @@ -1156,7 +1194,7 @@ def features_for_identity_clone_flag_states_from(
response = clone_identity_feature_states_response.json()

# Target identity contains only the 2 cloned overridden features states and 1 environment feature state
assert len(response) == 3
assert len(response) == 4

assert response[0]["feature"]["id"] == feature_1.id
assert response[0]["enabled"] == source_feature_state_1.enabled
Expand All @@ -1172,3 +1210,14 @@ def features_for_identity_clone_flag_states_from(
assert response[2]["enabled"] == feature_3.default_enabled
assert response[2]["feature_state_value"] == feature_3.initial_value
assert response[2]["overridden_by"] is None

assert response[3]["feature"]["id"] == mv_feature.id
assert response[3]["enabled"] == source_mv_feature_state.enabled
assert response[3]["feature_state_value"] == mv_variant_1.value
assert (
response[3]["multivariate_feature_state_values"][0][
"multivariate_feature_option"
]["value"]
== mv_variant_1.value
)
assert response[3]["overridden_by"] == "IDENTITY"
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json

import pytest
from core.constants import STRING
from django.test import Client
from django.urls import reverse
from rest_framework import status
Expand All @@ -12,6 +13,10 @@
VIEW_ENVIRONMENT,
)
from features.models import Feature, FeatureState, FeatureStateValue
from features.multivariate.models import (
MultivariateFeatureOption,
MultivariateFeatureStateValue,
)
from projects.models import Project
from tests.unit.environments.helpers import get_environment_user_client

Expand Down Expand Up @@ -136,6 +141,20 @@ def features_for_identity_clone_flag_states_from(
project
)

mv_feature = Feature.objects.create(
type="MULTIVARIATE",
name="mv_feature",
initial_value="foo",
project=project,
)

mv_variant_1 = MultivariateFeatureOption.objects.create(
feature=mv_feature,
default_percentage_allocation=0,
type=STRING,
string_value="bar",
)

source_identity: Identity = Identity.objects.create(
identifier="source_identity", environment=environment
)
Expand Down Expand Up @@ -165,6 +184,18 @@ def features_for_identity_clone_flag_states_from(
string_value=source_feature_state_2_value
)

source_mv_feature_state: FeatureState = FeatureState.objects.create(
feature=mv_feature,
environment=environment,
identity=source_identity,
enabled=True,
)
MultivariateFeatureStateValue.objects.create(
feature_state=source_mv_feature_state,
multivariate_feature_option=mv_variant_1,
percentage_allocation=100,
)

target_feature_state_2: FeatureState = FeatureState.objects.create(
feature=feature_2,
environment=environment,
Expand Down Expand Up @@ -201,7 +232,7 @@ def features_for_identity_clone_flag_states_from(
response = clone_identity_feature_states_response.json()

# Target identity contains only the 2 cloned overridden features states and 1 environment feature state
assert len(response) == 3
assert len(response) == 4

# Assert cloned data is correct
assert response[0]["feature"]["id"] == feature_1.id
Expand All @@ -219,6 +250,17 @@ def features_for_identity_clone_flag_states_from(
assert response[2]["feature_state_value"] == feature_3.initial_value
assert response[2]["overridden_by"] is None

assert response[3]["feature"]["id"] == mv_feature.id
assert response[3]["enabled"] == source_mv_feature_state.enabled
assert response[3]["feature_state_value"] == mv_variant_1.value
assert (
response[3]["multivariate_feature_state_values"][0][
"multivariate_feature_option"
]["value"]
== mv_variant_1.value
)
assert response[3]["overridden_by"] == "IDENTITY"

# Target identity feature 3 override has been removed
assert not FeatureState.objects.filter(
feature=feature_3,
Expand Down

0 comments on commit 92e3e9f

Please sign in to comment.