Skip to content

Commit 0875c96

Browse files
Validate branch sizes for all experiment types fixes #1030 (#1034)
* Validate branch sizes for all experiment types fixes #1030 * Use parameterized to repeat the tests for the subclasses
1 parent eb9cbad commit 0875c96

3 files changed

Lines changed: 63 additions & 32 deletions

File tree

app/experimenter/experiments/forms.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,11 @@ def clean(self):
267267
form._errors["name"] = ["All branches must have a unique name"]
268268

269269

270-
class ExperimentVariantsPrefFormSet(BaseInlineFormSet):
270+
class ExperimentVariantsPrefFormSet(ExperimentVariantsFormSet):
271271

272272
def clean(self):
273+
super().clean()
274+
273275
alive_forms = [
274276
form
275277
for form in self.forms

app/experimenter/experiments/tests/test_forms.py

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
from django import forms
66
from django.core.exceptions import ValidationError
7-
from django.forms import inlineformset_factory
87
from django.test import TestCase
98
from django.utils import timezone
9+
from parameterized import parameterized_class
1010

1111
from experimenter.experiments.forms import (
1212
BugzillaURLField,
@@ -21,7 +21,6 @@
2121
ExperimentVariantAddonForm,
2222
ExperimentVariantPrefForm,
2323
ExperimentVariantsAddonForm,
24-
ExperimentVariantsFormSet,
2524
ExperimentVariantsPrefForm,
2625
JSONField,
2726
)
@@ -256,70 +255,97 @@ def test_empty_slug_raises_error(self):
256255
self.assertFalse(form.is_valid())
257256

258257

259-
class TestExperimentVariantsFormSet(TestCase):
258+
@parameterized_class(
259+
["form_class"],
260+
[[ExperimentVariantsAddonForm], [ExperimentVariantsPrefForm]],
261+
)
262+
class TestExperimentVariantsFormSet(MockRequestMixin, TestCase):
260263

261264
def setUp(self):
262-
self.FormSet = inlineformset_factory(
263-
formset=ExperimentVariantsFormSet,
264-
model=ExperimentVariant,
265-
parent_model=Experiment,
266-
fields=["is_control", "ratio", "name", "slug", "description"],
265+
super().setUp()
266+
267+
self.experiment = ExperimentFactory.create_with_status(
268+
Experiment.STATUS_DRAFT, num_variants=0
267269
)
268270

269271
self.data = {
272+
"population_percent": "10",
273+
"firefox_version": Experiment.VERSION_CHOICES[-1][0],
274+
"firefox_channel": Experiment.CHANNEL_NIGHTLY,
275+
"client_matching": "en-us only please",
276+
"pref_key": "browser.test.example",
277+
"pref_type": Experiment.PREF_TYPE_STR,
278+
"pref_branch": Experiment.PREF_BRANCH_DEFAULT,
270279
"variants-TOTAL_FORMS": "3",
271280
"variants-INITIAL_FORMS": "0",
272281
"variants-MIN_NUM_FORMS": "0",
273282
"variants-MAX_NUM_FORMS": "1000",
274283
"variants-0-is_control": True,
275284
"variants-0-ratio": "34",
276285
"variants-0-name": "control name",
277-
"variants-0-slug": "control-slug",
278286
"variants-0-description": "control desc",
287+
"variants-0-value": '"control value"',
279288
"variants-1-is_control": False,
280289
"variants-1-ratio": "33",
281290
"variants-1-name": "branch 1 name",
282-
"variants-1-slug": "branch-1-slug",
283291
"variants-1-description": "branch 1 desc",
292+
"variants-1-value": '"branch 1 value"',
284293
"variants-2-is_control": False,
285294
"variants-2-ratio": "33",
286295
"variants-2-name": "branch 2 name",
287-
"variants-2-slug": "branch-2-slug",
288296
"variants-2-description": "branch 2 desc",
297+
"variants-2-value": '"branch 2 value"',
289298
}
290299

291-
def test_formset_valid_if_sizes_sum_to_100(self):
292-
formset = self.FormSet(data=self.data)
293-
self.assertTrue(formset.is_valid())
300+
def test_form_valid_if_sizes_sum_to_100(self):
301+
self.data["variants-0-ratio"] = "34"
302+
self.data["variants-1-ratio"] = "33"
303+
self.data["variants-2-ratio"] = "33"
304+
form = self.form_class(
305+
request=self.request, data=self.data, instance=self.experiment
306+
)
307+
self.assertTrue(form.is_valid())
294308

295-
def test_formset_invalid_if_sizes_sum_to_less_than_100(self):
296-
self.data["variants-0-ratio"] = 30
297-
formset = self.FormSet(data=self.data)
298-
self.assertFalse(formset.is_valid())
309+
def test_form_invalid_if_sizes_sum_to_less_than_100(self):
310+
self.data["variants-0-ratio"] = "33"
311+
self.data["variants-1-ratio"] = "33"
312+
self.data["variants-2-ratio"] = "33"
313+
form = self.form_class(
314+
request=self.request, data=self.data, instance=self.experiment
315+
)
316+
self.assertFalse(form.is_valid())
299317

300-
for form in formset.forms:
318+
for form in form.variants_formset.forms:
301319
self.assertIn("ratio", form.errors)
302320

303-
def test_formset_invalid_if_sizes_sum_to_more_than_100(self):
304-
self.data["variants-0-ratio"] = 40
305-
formset = self.FormSet(data=self.data)
306-
self.assertFalse(formset.is_valid())
321+
def test_form_invalid_if_sizes_sum_to_more_than_100(self):
322+
self.data["variants-0-ratio"] = "35"
323+
self.data["variants-1-ratio"] = "33"
324+
self.data["variants-2-ratio"] = "33"
325+
form = self.form_class(
326+
request=self.request, data=self.data, instance=self.experiment
327+
)
328+
self.assertFalse(form.is_valid())
307329

308-
for form in formset.forms:
330+
for form in form.variants_formset.forms:
309331
self.assertIn("ratio", form.errors)
310332

311-
def test_formset_invalid_if_duplicate_slugs_appear(self):
312-
self.data["variants-0-slug"] = self.data["variants-1-slug"]
313-
formset = self.FormSet(data=self.data)
314-
self.assertFalse(formset.is_valid())
333+
def test_form_invalid_if_duplicate_names_appear(self):
334+
self.data["variants-0-name"] = self.data["variants-1-name"]
335+
form = self.form_class(
336+
request=self.request, data=self.data, instance=self.experiment
337+
)
338+
self.assertFalse(form.is_valid())
315339

316-
for form in formset.forms:
340+
for form in form.variants_formset.forms:
317341
self.assertIn("name", form.errors)
318342

319343
def test_empty_branch_size_raises_validation_error(self):
320344
del self.data["variants-0-ratio"]
321-
formset = self.FormSet(data=self.data)
322-
self.assertFalse(formset.is_valid())
345+
form = self.form_class(
346+
request=self.request, data=self.data, instance=self.experiment
347+
)
348+
self.assertFalse(form.is_valid())
323349

324350

325351
class TestExperimentVariantsAddonForm(MockRequestMixin, TestCase):

app/requirements/default.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,6 @@ requests[security]==2.20.0 \
138138
whitenoise==4.1.2 \
139139
--hash=sha256:118ab3e5f815d380171b100b05b76de2a07612f422368a201a9ffdeefb2251c1 \
140140
--hash=sha256:42133ddd5229eeb6a0c9899496bdbe56c292394bf8666da77deeb27454c0456a
141+
parameterized==0.7.0 \
142+
--hash=sha256:020343a281efcfe9b71b9028a91817f981202c14d72104b5a2fbe401dee25a18 \
143+
--hash=sha256:d8c8837fb677ed2d5a93b9e2308ce0da3aeb58cf513120d501e0b7af14da78d5

0 commit comments

Comments
 (0)