Exemplo n.º 1
0
    def create_with_status(cls, target_status, **kwargs):
        experiment = cls.create(**kwargs)

        for status, _ in NimbusExperiment.Status.choices:
            if status == NimbusExperiment.Status.REVIEW.value:
                NimbusIsolationGroup.request_isolation_group_buckets(
                    experiment.slug,
                    experiment,
                    100,
                )

            if status == target_status:
                break

        return NimbusExperiment.objects.get(id=experiment.id)
Exemplo n.º 2
0
    def test_full_isolation_group_creates_next_isolation_group_adds_bucket_range(
        self, ):
        """
        Rare case:  An isolation group with experiment bucket allocations exists, and the
        next requested bucket allocation would overflow its total bucket range, and so a
        an isolation group with the same name but subsequent instance ID is created.

        This is currently treated naively, ie does not account for possible collisions and
        overlaps.  When this case becomes more common this will likely need to be given
        more thought.
        """
        experiment = NimbusExperimentFactory.create(
            application=self.application)
        isolation_group = NimbusIsolationGroupFactory.create(
            name=experiment.slug, application=self.application, total=100)
        NimbusBucketRangeFactory(isolation_group=isolation_group, count=100)
        bucket = NimbusIsolationGroup.request_isolation_group_buckets(
            experiment.slug, experiment, 100)
        self.assertEqual(bucket.start, 0)
        self.assertEqual(bucket.end, 99)
        self.assertEqual(bucket.count, 100)
        self.assertEqual(bucket.isolation_group.name, isolation_group.name)
        self.assertEqual(bucket.isolation_group.instance,
                         isolation_group.instance + 1)
        self.assertEqual(
            bucket.isolation_group.randomization_unit,
            self.randomization_unit,
        )
Exemplo n.º 3
0
def nimbus_push_experiment_to_kinto(experiment_id):
    """
    An invoked task that given a single experiment id, query it in the db, serialize it,
    and push its data to the configured collection. If it fails for any reason, log the
    error and reraise it so it will be forwarded to sentry.
    """

    metrics.incr("push_experiment_to_kinto.started")

    try:
        experiment = NimbusExperiment.objects.get(id=experiment_id)
        logger.info(f"Pushing {experiment} to Kinto")

        kinto_client = KintoClient(
            NimbusExperiment.KINTO_APPLICATION_COLLECTION[
                experiment.application])

        if not NimbusBucketRange.objects.filter(
                experiment=experiment).exists():
            NimbusIsolationGroup.request_isolation_group_buckets(
                experiment.slug,
                experiment,
                int(experiment.population_percent / Decimal("100.0") *
                    NimbusExperiment.BUCKET_TOTAL),
            )

        data = NimbusExperimentSerializer(experiment).data

        kinto_client.push_to_kinto(data)

        experiment.status = NimbusExperiment.Status.ACCEPTED
        experiment.save()

        generate_nimbus_changelog(experiment, get_kinto_user())

        logger.info(f"{experiment} pushed to Kinto")
        metrics.incr("push_experiment_to_kinto.completed")
    except Exception as e:
        metrics.incr("push_experiment_to_kinto.failed")
        logger.info(
            f"Pushing experiment id {experiment_id} to Kinto failed: {e}")
        raise e
Exemplo n.º 4
0
 def test_existing_isolation_group_adds_bucket_range(self):
     """
     Rare case: An isolation group with no buckets allocated already exists.
     This may become common when users can create their own isolation groups
     and then later assign experiments to them.
     """
     experiment = NimbusExperimentFactory.create()
     isolation_group = NimbusIsolationGroupFactory.create(
         name=experiment.slug)
     bucket = NimbusIsolationGroup.request_isolation_group_buckets(
         experiment.slug, experiment, 100)
     self.assertEqual(bucket.start, 0)
     self.assertEqual(bucket.end, 99)
     self.assertEqual(bucket.count, 100)
     self.assertEqual(bucket.isolation_group, isolation_group)
Exemplo n.º 5
0
 def test_existing_isolation_group_with_matching_name_but_not_application_is_filtered(
     self, ):
     """
     Now that isolation groups are bound to applications, we have to check for the
     case where isolation groups with the same name but different applications are
     treated separately.
     """
     name = "isolation group name"
     NimbusIsolationGroupFactory.create(
         name=name, application=NimbusExperiment.Application.DESKTOP)
     experiment = NimbusExperimentFactory.create(
         name=name,
         slug=name,
         application=NimbusExperiment.Application.FENIX)
     bucket = NimbusIsolationGroup.request_isolation_group_buckets(
         name, experiment, 100)
     self.assertEqual(bucket.isolation_group.name, name)
     self.assertEqual(bucket.isolation_group.application,
                      NimbusExperiment.Application.FENIX)
Exemplo n.º 6
0
 def test_existing_isolation_group_with_buckets_adds_next_bucket_range(
         self):
     """
     Common case: An isolation group with experiment bucket allocations exists,
     and a subsequent bucket allocation is requested.  This will be the common case
     for any experiments that share an isolation group.
     """
     experiment = NimbusExperimentFactory.create()
     isolation_group = NimbusIsolationGroupFactory.create(
         name=experiment.slug)
     NimbusBucketRangeFactory.create(isolation_group=isolation_group,
                                     start=0,
                                     count=100)
     bucket = NimbusIsolationGroup.request_isolation_group_buckets(
         experiment.slug, experiment, 100)
     self.assertEqual(bucket.start, 100)
     self.assertEqual(bucket.end, 199)
     self.assertEqual(bucket.count, 100)
     self.assertEqual(bucket.isolation_group, isolation_group)
Exemplo n.º 7
0
 def test_empty_isolation_group_creates_isolation_group_and_bucket_range(self):
     """
     Common case: A new empty isolation group for an experiment
     that is orthogonal to all other current experiments.  This will
     likely describe most experiment launches.
     """
     experiment = NimbusExperimentFactory.create(application=self.application)
     bucket = NimbusIsolationGroup.request_isolation_group_buckets(
         experiment.slug, experiment, 100
     )
     self.assertEqual(bucket.start, 0)
     self.assertEqual(bucket.end, 99)
     self.assertEqual(bucket.count, 100)
     self.assertEqual(bucket.isolation_group.name, experiment.slug)
     self.assertEqual(bucket.isolation_group.instance, 1)
     self.assertEqual(bucket.isolation_group.total, NimbusExperiment.BUCKET_TOTAL)
     self.assertEqual(
         bucket.isolation_group.randomization_unit,
         experiment.application_config.randomization_unit,
     )