Skip to content
Open
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
9 changes: 5 additions & 4 deletions api/experimentation/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,14 @@ def get_queryset(self) -> "QuerySet[Experiment]":
"feature__feature_states__multivariate_feature_state_values",
"experiment_metrics__metric",
)
status_filter = self.request.query_params.get("status")
status_filter = self.request.query_params.getlist("status")
if status_filter:
if status_filter not in ExperimentStatus.values:
invalid = [s for s in status_filter if s not in ExperimentStatus.values]
if invalid:
raise serializers.ValidationError(
{"status": f"Invalid status '{status_filter}'."}
{"status": f"Invalid status value(s): {', '.join(invalid)}."}
)
qs = qs.filter(status=status_filter)
qs = qs.filter(status__in=status_filter)

q = self.request.query_params.get("q")
if q:
Expand Down
60 changes: 60 additions & 0 deletions api/tests/unit/experimentation/test_experiment_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,48 @@ def test_delete__valid_delete__creates_audit_log(
assert "deleted" in audit.log


def test_get_list__filter_by_multiple_statuses__returns_matching(
admin_client_new: APIClient,
environment: Environment,
experiment: Experiment,
project: "Project",
enable_features: EnableFeaturesFixture,
) -> None:
# Given
enable_features(EXPERIMENT_FLAG)
second_feature = Feature.objects.create(
name="mv_feature_2",
project=project,
type=MULTIVARIATE,
initial_value="control",
)
for pct in (50, 50):
MultivariateFeatureOption.objects.create(
feature=second_feature,
default_percentage_allocation=pct,
type="unicode",
string_value=f"option_{pct}",
)
running_experiment = Experiment.objects.create(
environment=environment,
feature=second_feature,
name="Running Experiment",
hypothesis="hypothesis",
status=ExperimentStatus.RUNNING,
)

# When — filter for both created and running
response = admin_client_new.get(
_list_url(environment),
{"status": ["created", "running"]},
)

# Then
assert response.status_code == status.HTTP_200_OK
result_ids = {r["id"] for r in response.json()["results"]}
assert result_ids == {experiment.id, running_experiment.id}


def test_get_list__invalid_status__returns_400(
admin_client_new: APIClient,
environment: Environment,
Expand All @@ -1171,6 +1213,24 @@ def test_get_list__invalid_status__returns_400(
assert response.status_code == status.HTTP_400_BAD_REQUEST


def test_get_list__mixed_valid_and_invalid_status__returns_400(
admin_client_new: APIClient,
environment: Environment,
enable_features: EnableFeaturesFixture,
) -> None:
# Given
enable_features(EXPERIMENT_FLAG)

# When
response = admin_client_new.get(
_list_url(environment),
{"status": ["running", "garbage"]},
)

# Then
assert response.status_code == status.HTTP_400_BAD_REQUEST


def test_delete__running_experiment__returns_400(
admin_client_new: APIClient,
environment: Environment,
Expand Down
Loading