Skip to content

Commit e5f2f7c

Browse files
authored
feat(experimentation): return feature object along with experiment entity (#7609)
1 parent cac20ff commit e5f2f7c

3 files changed

Lines changed: 74 additions & 0 deletions

File tree

api/experimentation/serializers.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
)
1111
from experimentation.types import SNOWFLAKE_DEFAULTS, SnowflakeConfig
1212
from features.feature_types import MULTIVARIATE
13+
from features.models import Feature
14+
from features.multivariate.serializers import NestedMultivariateFeatureOptionSerializer
1315

1416

1517
class WarehouseConnectionSerializer(serializers.ModelSerializer): # type: ignore[type-arg]
@@ -115,3 +117,18 @@ def validate(self, attrs: dict[str, Any]) -> dict[str, Any]:
115117
{"feature": "Cannot change the feature of an existing experiment."}
116118
)
117119
return attrs
120+
121+
122+
class ExperimentFeatureSerializer(serializers.ModelSerializer): # type: ignore[type-arg]
123+
multivariate_options = NestedMultivariateFeatureOptionSerializer(
124+
many=True, read_only=True
125+
)
126+
127+
class Meta:
128+
model = Feature
129+
fields = ("id", "name", "type", "initial_value", "multivariate_options")
130+
read_only_fields = fields
131+
132+
133+
class ExperimentListSerializer(ExperimentSerializer):
134+
feature = ExperimentFeatureSerializer(read_only=True)

api/experimentation/views.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
WarehouseConnectionPermission,
2121
)
2222
from experimentation.serializers import (
23+
ExperimentListSerializer,
2324
ExperimentSerializer,
2425
WarehouseConnectionSerializer,
2526
)
@@ -111,8 +112,17 @@ def get_serializer_context(self) -> dict[str, Any]:
111112
context["environment"] = self._get_environment()
112113
return context
113114

115+
def get_serializer_class(self) -> type[BaseSerializer[Experiment]]:
116+
if self.action in ("list", "retrieve", "start", "pause", "complete"):
117+
return ExperimentListSerializer
118+
return ExperimentSerializer
119+
114120
def get_queryset(self) -> "QuerySet[Experiment]":
115121
qs = super().get_queryset()
122+
if self.action in ("list", "retrieve"):
123+
qs = qs.select_related("feature").prefetch_related(
124+
"feature__multivariate_options"
125+
)
116126
status_filter = self.request.query_params.get("status")
117127
if status_filter:
118128
qs = qs.filter(status=status_filter)

api/tests/unit/experimentation/test_experiment_views.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,53 @@ def test_get_list__with_experiments__returns_all(
269269
assert response.json()[0]["id"] == experiment.id
270270

271271

272+
def test_get_list__with_experiments__returns_nested_feature(
273+
admin_client_new: APIClient,
274+
environment: Environment,
275+
experiment: Experiment,
276+
multivariate_feature: Feature,
277+
enable_features: EnableFeaturesFixture,
278+
) -> None:
279+
# Given
280+
enable_features(EXPERIMENT_FLAG)
281+
282+
# When
283+
response = admin_client_new.get(_list_url(environment))
284+
285+
# Then
286+
assert response.status_code == status.HTTP_200_OK
287+
data = response.json()
288+
assert len(data) == 1
289+
feature_data = data[0]["feature"]
290+
assert isinstance(feature_data, dict)
291+
assert feature_data["id"] == multivariate_feature.id
292+
assert feature_data["name"] == multivariate_feature.name
293+
assert feature_data["type"] == "MULTIVARIATE"
294+
assert feature_data["initial_value"] == "control"
295+
assert len(feature_data["multivariate_options"]) == 3
296+
297+
298+
def test_get_detail__exists__returns_nested_feature(
299+
admin_client_new: APIClient,
300+
environment: Environment,
301+
experiment: Experiment,
302+
multivariate_feature: Feature,
303+
enable_features: EnableFeaturesFixture,
304+
) -> None:
305+
# Given
306+
enable_features(EXPERIMENT_FLAG)
307+
308+
# When
309+
response = admin_client_new.get(_detail_url(environment, experiment))
310+
311+
# Then
312+
assert response.status_code == status.HTTP_200_OK
313+
feature_data = response.json()["feature"]
314+
assert isinstance(feature_data, dict)
315+
assert feature_data["id"] == multivariate_feature.id
316+
assert feature_data["name"] == multivariate_feature.name
317+
318+
272319
def test_get_list__empty__returns_200(
273320
admin_client_new: APIClient,
274321
environment: Environment,

0 commit comments

Comments
 (0)