예제 #1
0
    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],
        )
예제 #2
0
    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)
예제 #3
0
    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],
        )
예제 #4
0
    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]))
예제 #5
0
    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)
예제 #6
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]))
예제 #7
0
    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)
예제 #8
0
    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)
예제 #9
0
    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)
예제 #10
0
    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)),
        )
예제 #11
0
 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))
예제 #12
0
    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)"
     )
예제 #15
0
 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),
     )
예제 #16
0
    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]))
예제 #17
0
    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)),
        )
예제 #18
0
    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)
예제 #19
0
 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)"
     )
예제 #20
0
    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!")
예제 #21
0
    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)
예제 #22
0
    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)
예제 #23
0
    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)
예제 #24
0
    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)
예제 #25
0
    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)
예제 #26
0
    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)
예제 #27
0
    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)
예제 #28
0
    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)
예제 #29
0
    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)
예제 #30
0
    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)