def test_queryset_annotated_with_latest_change(self): now = datetime.datetime.now() experiment1 = ExperimentFactory.create_with_variants() experiment2 = ExperimentFactory.create_with_variants() ExperimentChangeLogFactory.create( experiment=experiment1, old_status=None, new_status=Experiment.STATUS_DRAFT, changed_on=(now - datetime.timedelta(days=2)), ) ExperimentChangeLogFactory.create( experiment=experiment2, old_status=None, new_status=Experiment.STATUS_DRAFT, changed_on=(now - datetime.timedelta(days=1)), ) self.assertEqual( list(Experiment.objects.order_by("-latest_change")), [experiment2, experiment1], ) ExperimentChangeLogFactory.create( experiment=experiment1, old_status=experiment1.status, new_status=Experiment.STATUS_REVIEW, ) self.assertEqual( list(Experiment.objects.order_by("-latest_change")), [experiment1, experiment2], )
def test_list_view_filters_by_status(self): pending_experiments = [] # new experiments should be excluded for i in range(2): ExperimentFactory.create_with_variants() # pending experiments should be included for i in range(3): experiment = ExperimentFactory.create_with_variants() experiment.status = experiment.STATUS_REVIEW experiment.save() pending_experiments.append(experiment) response = self.client.get(reverse("experiments-api-list"), {"status": Experiment.STATUS_REVIEW}) self.assertEqual(response.status_code, 200) json_data = json.loads(response.content) serialized_experiments = ExperimentSerializer( Experiment.objects.filter(status=Experiment.STATUS_REVIEW), many=True).data self.assertEqual(serialized_experiments, json_data)
def test_most_recently_changed_orders_by_latest_changes(self): now = datetime.datetime.now() experiment1 = ExperimentFactory.create_with_variants() experiment2 = ExperimentFactory.create_with_variants() ExperimentChangeLogFactory.create( experiment=experiment1, old_status=None, new_status=Experiment.STATUS_CREATED, changed_on=(now - datetime.timedelta(days=2)), ) ExperimentChangeLogFactory.create( experiment=experiment2, old_status=None, new_status=Experiment.STATUS_CREATED, changed_on=(now - datetime.timedelta(days=1)), ) self.assertEqual( list(Experiment.objects.most_recently_changed()), [experiment2, experiment1], ) ExperimentChangeLogFactory.create( experiment=experiment1, old_status=experiment1.status, new_status=Experiment.STATUS_PENDING, ) self.assertEqual( list(Experiment.objects.most_recently_changed()), [experiment1, experiment2], )
def test_filters_experiments_with_surveys(self): exp_1 = ExperimentFactory.create_with_variants(survey_required=True) exp_2 = ExperimentFactory.create_with_variants(survey_required=True, review_qa=False) ExperimentFactory.create_with_variants(survey_required=False) filter = ExperimentFilterset({"surveys": "on"}, queryset=Experiment.objects.all()) self.assertEqual(set(filter.qs), set([exp_1, exp_2]))
def test_queryset_filters_is_control_True(self): ExperimentFactory.create_with_variants() self.assertEqual(ExperimentVariant.objects.all().count(), 2) control_admin = ExperimentVariantInlineAdmin(mock.Mock(), mock.Mock()) variants = control_admin.get_queryset(mock.Mock()) self.assertEqual(variants.count(), 1) self.assertEqual(variants.filter(is_control=False).count(), 1) self.assertEqual(variants.filter(is_control=True).count(), 0)
def test_filters_by_review_in_qa(self): exp_1 = ExperimentFactory.create_with_variants( review_qa_requested=True, review_qa=False) ExperimentFactory.create_with_variants(review_qa_requested=False, review_qa=False) ExperimentFactory.create_with_variants(review_qa_requested=True, review_qa=True) filter = ExperimentFilterset({"in_qa": "on"}, queryset=Experiment.objects.all()) self.assertEqual(set(filter.qs), set([exp_1]))
def test_experiment_ending_soon(self): experiment_1 = ExperimentFactory.create_with_variants( proposed_start_date=datetime.date.today(), proposed_duration=5, proposed_enrollment=0, ) self.assertTrue(experiment_1.ending_soon) experiment_2 = ExperimentFactory.create_with_variants( proposed_start_date=datetime.date.today(), proposed_duration=20, proposed_enrollment=0, ) self.assertFalse(experiment_2.ending_soon)
def test_post_to_reject_view_sets_status_rejected(self): user_email = '*****@*****.**' rejection_message = 'This experiment was rejected for reasons.' experiment = ExperimentFactory.create_with_variants() experiment.status = experiment.STATUS_PENDING experiment.save() response = self.client.patch( reverse('experiments-reject', kwargs={'slug': experiment.slug}), data=json.dumps({'message': rejection_message}), content_type='application/json', **{settings.OPENIDC_EMAIL_HEADER: user_email}, ) self.assertEqual(response.status_code, 200) experiment = Experiment.objects.get(pk=experiment.pk) self.assertEqual(experiment.status, experiment.STATUS_REJECTED) change = experiment.changes.get() self.assertEqual(change.old_status, experiment.STATUS_PENDING) self.assertEqual(change.new_status, experiment.STATUS_REJECTED) self.assertEqual(change.changed_by.email, user_email) self.assertEqual(change.message, rejection_message)
def test_clone(self): user_1 = UserFactory.create() user_2 = UserFactory.create() experiment = ExperimentFactory.create_with_variants( name="great experiment", status=Experiment.STATUS_COMPLETE, short_description="This is going to be a great experiment.", proposed_start_date=datetime.date(2019, 4, 1), related_work="See also this other experiment.", proposed_enrollment=2, proposed_duration=30, owner=user_1, bugzilla_id="4455667", pref_type=Experiment.TYPE_ADDON, data_science_bugzilla_url="https://bugzilla.mozilla.org/123/", feature_bugzilla_url="https://bugzilla.mozilla.org/123/", addon_experiment_id="addon-id", addon_release_url="addon-url", archived=True, review_science=True, review_ux=True, firefox_min_version=Experiment.VERSION_CHOICES[1][0], firefox_max_version="", ) experiment.clone("best experiment", user_2) cloned_experiment = Experiment.objects.filter(name="best experiment").get() self.assertTrue(cloned_experiment.parent, experiment.id) self.assertIn(experiment, cloned_experiment.related_to.all()) self.assertEqual(cloned_experiment.status, Experiment.STATUS_DRAFT) self.assertEqual( cloned_experiment.short_description, "This is going to be a great experiment." ) self.assertEqual( cloned_experiment.related_work, "See also this other experiment." ) self.assertEqual(cloned_experiment.proposed_enrollment, 2) self.assertEqual(cloned_experiment.proposed_duration, 30) self.assertEqual(cloned_experiment.pref_type, Experiment.TYPE_ADDON) self.assertEqual(cloned_experiment.proposed_start_date, None) self.assertEqual(cloned_experiment.owner, user_2) self.assertEqual( cloned_experiment.firefox_min_version, Experiment.VERSION_CHOICES[1][0] ) self.assertFalse(cloned_experiment.bugzilla_id) self.assertFalse(cloned_experiment.archived) self.assertFalse(cloned_experiment.review_science) self.assertFalse(cloned_experiment.review_ux) self.assertFalse(cloned_experiment.addon_experiment_id) self.assertFalse(cloned_experiment.addon_release_url) self.assertEqual(cloned_experiment.changes.count(), 1) change = cloned_experiment.changes.latest() self.assertEqual(change.old_status, None) self.assertEqual(change.new_status, experiment.STATUS_DRAFT)
def test_filters_by_firefox_channel(self): include_channel = Experiment.CHANNEL_CHOICES[1][0] exclude_channel = Experiment.CHANNEL_CHOICES[2][0] for i in range(3): ExperimentFactory.create_with_variants( firefox_channel=include_channel) ExperimentFactory.create_with_variants( firefox_channel=exclude_channel) filter = ExperimentFilterset({"firefox_channel": include_channel}, queryset=Experiment.objects.all()) self.assertEqual( set(filter.qs), set(Experiment.objects.filter(firefox_channel=include_channel)), )
def test_enrollment_end_date_uses_enrollment_duration(self): experiment = ExperimentFactory.create_with_variants( proposed_start_date=datetime.date(2019, 1, 1), proposed_duration=20, proposed_enrollment=10, ) self.assertEqual(experiment.end_date, datetime.date(2019, 1, 21))
def test_serializer_saves_branched_addon_experiment(self): experiment = ExperimentFactory.create_with_variants( type=ExperimentConstants.TYPE_ADDON, is_branched_addon=False) variant_1 = { "addon_release_url": "http://example.com", "name": "Terrific branch", "ratio": 50, "description": "Very terrific branch.", "is_control": True, } variant_2 = { "addon_release_url": "http://example2.com", "name": "Great branch", "ratio": 50, "description": "Very great branch.", "is_control": False, } data = {"is_branched_addon": True, "variants": [variant_1, variant_2]} serializer = ExperimentDesignBranchedAddonSerializer( instance=experiment, data=data, context={"request": self.request}) self.assertTrue(serializer.is_valid()) self.assertEqual(experiment.changes.count(), 0) experiment = serializer.save() self.assertTrue(experiment.is_branched_addon) self.assertEqual(experiment.changes.count(), 1)
def test_compute_end_date_accepts_invalid_duration(self): experiment = ExperimentFactory.create_with_variants( proposed_start_date=datetime.date(2019, 1, 1) ) self.assertEqual( experiment._compute_end_date(experiment.MAX_DURATION + 1), None )
def test_dates_returns_date_string(self): experiment = ExperimentFactory.create_with_variants( proposed_start_date=datetime.date(2019, 1, 1), proposed_duration=20 ) self.assertEqual( experiment.dates, "Jan 01, 2019 - Jan 21, 2019 (20 days)" )
def test_show_dashboard_url_returns_link(self): experiment_admin = ExperimentAdmin(mock.Mock(), mock.Mock()) experiment = ExperimentFactory.create_with_variants() self.assertEqual( experiment_admin.show_dashboard_url(experiment), '<a href="{url}" target="_blank">{url}</a>'.format( url=experiment.dashboard_url), )
def test_filters_by_firefox_version(self): exp_1 = ExperimentFactory.create_with_variants( name="Experiment 1", firefox_min_version="58.0", firefox_max_version="62.0", ) exp_2 = ExperimentFactory.create_with_variants( name="Experiment 2", firefox_min_version="59.0", firefox_max_version="60.0", ) ExperimentFactory.create_with_variants( name="Experiment 4", firefox_min_version="62.0", firefox_max_version="68.0", ) exp_3 = ExperimentFactory.create_with_variants( name="Experiment 3", firefox_min_version="59.0", firefox_max_version="", ) ExperimentFactory.create_with_variants( name="Experiment 5", firefox_min_version="54.0", firefox_max_version="56.0", ) filter = ExperimentFilterset({"firefox_version": "59.0"}, queryset=Experiment.objects.all()) self.assertEqual(set(filter.qs), set([exp_1, exp_2, exp_3]))
def test_filters_by_firefox_version(self): include_version = Experiment.VERSION_CHOICES[1][0] exclude_version = Experiment.VERSION_CHOICES[2][0] for i in range(3): ExperimentFactory.create_with_variants( firefox_version=include_version) ExperimentFactory.create_with_variants( firefox_version=exclude_version) filter = ExperimentFilterset( {"firefox_version": include_version}, queryset=Experiment.objects.all(), ) self.assertEqual( set(filter.qs), set(Experiment.objects.filter(firefox_version=include_version)), )
def test_post_to_reject_raises_404_for_non_pending_experiment(self): experiment = ExperimentFactory.create_with_variants() response = self.client.patch( reverse('experiments-reject', kwargs={'slug': experiment.slug}), **{settings.OPENIDC_EMAIL_HEADER: '*****@*****.**'}, ) self.assertEqual(response.status_code, 404)
def test_observation_dates_returns_date_string(self): experiment = ExperimentFactory.create_with_variants( proposed_start_date=datetime.date(2019, 1, 1), proposed_duration=20, proposed_enrollment=10, ) self.assertEqual( experiment.observation_dates, "Jan 11, 2019 - Jan 21, 2019 (10 days)" )
def test_change_message(self): experiment = ExperimentFactory.create_with_variants() changelog = ExperimentChangeLogFactory.create( experiment=experiment, old_status=Experiment.STATUS_DRAFT, new_status=Experiment.STATUS_REVIEW, message="its a message!", ) self.assertEqual(str(changelog), "its a message!")
def test_post_to_accept_raises_404_for_non_pending_experiment(self): experiment = ExperimentFactory.create_with_variants() response = self.client.patch( reverse("experiments-api-accept", kwargs={"slug": experiment.slug}), **{settings.OPENIDC_EMAIL_HEADER: "*****@*****.**"}, ) self.assertEqual(response.status_code, 404)
def test_pretty_status_created_draft(self): experiment = ExperimentFactory.create_with_variants() for ( old_status, new_statuses, ) in ExperimentChangeLog.PRETTY_STATUS_LABELS.items(): for new_status, expected_label in new_statuses.items(): changelog = ExperimentChangeLogFactory.create( experiment=experiment, old_status=old_status, new_status=new_status ) self.assertEqual(changelog.pretty_status, expected_label)
def test_put_raises_409_if_email_already_sent(self): experiment = ExperimentFactory.create_with_variants( review_intent_to_ship=True, status=Experiment.STATUS_REVIEW) response = self.client.put( reverse( "experiments-api-send-intent-to-ship-email", kwargs={"slug": experiment.slug}, ), **{settings.OPENIDC_EMAIL_HEADER: "*****@*****.**"}, ) self.assertEqual(response.status_code, 409)
def test_get_experiment_returns_experiment_info(self): user_email = "*****@*****.**" experiment = ExperimentFactory.create_with_variants() response = self.client.get( reverse("experiments-api-detail", kwargs={"slug": experiment.slug}), **{settings.OPENIDC_EMAIL_HEADER: user_email}, ) self.assertEqual(response.status_code, 200) json_data = json.loads(response.content) serialized_experiment = ExperimentSerializer(experiment).data self.assertEqual(serialized_experiment, json_data)
def test_get_rapid_experiment_recipe_returns_404_for_draft(self): experiment = ExperimentFactory.create_with_variants( status=Experiment.STATUS_DRAFT, type=ExperimentConstants.TYPE_RAPID, ) response = self.client.get( reverse( "experiment-rapid-recipe-detail", kwargs={"recipe_slug": experiment.recipe_slug}, ), ) self.assertEqual(response.status_code, 404)
def test_view_filters_by_project(self): user_email = "*****@*****.**" project = ProjectFactory.create() experiment1 = ExperimentFactory.create_with_status( Experiment.STATUS_DRAFT, name="a", projects=[project]) experiment2 = ExperimentFactory.create_with_status( Experiment.STATUS_DRAFT, name="b", projects=[project]) ExperimentFactory.create_with_variants() url = reverse("experiments-api-csv") response = self.client.get( f"{url}?projects={project.id}", **{settings.OPENIDC_EMAIL_HEADER: user_email}) self.assertEqual(response.status_code, 200) csv_data = response.content expected_csv_data = ExperimentCSVRenderer().render( ExperimentCSVSerializer([experiment1, experiment2], many=True).data, renderer_context={"header": ExperimentCSVSerializer.Meta.fields}, ) self.assertEqual(csv_data, expected_csv_data)
def setUp(self): self.experiment = ExperimentFactory.create_with_variants( name="Greatest Experiment", slug="greatest-experiment", firefox_min_version="68.0", firefox_max_version="69.0", firefox_channel="Nightly", proposed_start_date=date(2019, 5, 1), proposed_enrollment=5, proposed_duration=10, ) self.subscribing_user = UserFactory.create() self.experiment.subscribers.add(self.subscribing_user)
def test_pretty_status_created_draft(self): experiment = ExperimentFactory.create_with_variants() for old_status in ExperimentChangeLog.PRETTY_STATUS_LABELS.keys(): for new_status in ExperimentChangeLog.PRETTY_STATUS_LABELS[ old_status].keys(): expected_label = ExperimentChangeLog.PRETTY_STATUS_LABELS[ old_status][new_status] changelog = ExperimentChangeLogFactory.create( experiment=experiment, old_status=old_status, new_status=new_status, ) self.assertEqual(changelog.pretty_status, expected_label)
def test_view_filters_by_subscriber(self): user = UserFactory(email="*****@*****.**") experiment1 = ExperimentFactory.create_with_status( Experiment.STATUS_DRAFT, name="a") experiment1.subscribers.add(user) experiment2 = ExperimentFactory.create_with_status( Experiment.STATUS_DRAFT, name="b") experiment2.subscribers.add(user) ExperimentFactory.create_with_variants() url = reverse("experiments-api-csv") response = self.client.get( f"{url}?subscribed=on", **{settings.OPENIDC_EMAIL_HEADER: user.email}) self.assertEqual(response.status_code, 200) csv_data = response.content expected_csv_data = ExperimentCSVRenderer().render( ExperimentCSVSerializer([experiment1, experiment2], many=True).data, renderer_context={"header": ExperimentCSVSerializer.Meta.fields}, ) self.assertEqual(csv_data, expected_csv_data)
def test_list_view_filters_by_project_slug(self): project = ProjectFactory.create() project_experiments = [] # another projects experiments should be excluded for i in range(2): ExperimentFactory.create_with_variants() # started project experiments should be included for i in range(3): experiment = ExperimentFactory.create_with_variants( project=project) project_experiments.append(experiment) response = self.client.get(reverse('experiments-list'), {'project__slug': project.slug}) self.assertEqual(response.status_code, 200) json_data = json.loads(response.content) serialized_experiments = ExperimentSerializer( project.experiments.all(), many=True).data self.assertEqual(serialized_experiments, json_data)