def test_schema_check_fails(self): data = {} with pytest.raises(mozilla_nimbus_shared.NimbusValidationError) as excinfo: mozilla_nimbus_shared.check_schema("normandy/ConsoleLogArguments", data) assert "Data does not match schema" in str(excinfo.value) errors = list(excinfo.value.errors) assert len(errors) == 1 assert "'message' is a required property" in str(errors[0])
def test_serializer_outputs_empty_targeting(self): experiment = NimbusExperimentFactory.create_with_lifecycle( NimbusExperimentFactory.Lifecycles.LAUNCH_APPROVE, publish_status=NimbusExperiment.PublishStatus.APPROVED, targeting_config_slug=NimbusExperiment.TargetingConfig.NO_TARGETING, application=NimbusExperiment.Application.FENIX, ) serializer = NimbusExperimentSerializer(experiment) self.assertEqual(serializer.data["targeting"], "true") check_schema("experiments/NimbusExperiment", serializer.data)
def test_serializer_outputs_targeting(self): experiment = NimbusExperimentFactory.create_with_lifecycle( NimbusExperimentFactory.Lifecycles.LAUNCH_APPROVE, firefox_min_version=NimbusExperiment.Version.FIREFOX_83, targeting_config_slug=NimbusExperiment.TargetingConfig.ALL_ENGLISH, application=NimbusExperiment.Application.DESKTOP, channel=NimbusExperiment.Channel.NO_CHANNEL, ) serializer = NimbusExperimentSerializer(experiment) self.assertEqual(serializer.data["targeting"], experiment.targeting) check_schema("experiments/NimbusExperiment", serializer.data)
def test_serializers_with_feature_value_None(self): experiment = NimbusExperimentFactory.create_with_status( NimbusExperiment.Status.ACCEPTED, branches=[], ) experiment.reference_branch = NimbusBranchFactory( experiment=experiment, feature_value=None) experiment.save() serializer = NimbusExperimentSerializer(experiment) self.assertIsNone(serializer.data["branches"][0]["feature"]["value"]) check_schema("experiments/NimbusExperiment", serializer.data)
def test_sets_application_channel_for_fenix_experiment(self): experiment = NimbusExperimentFactory.create_with_status( NimbusExperiment.Status.ACCEPTED, application=NimbusExperiment.Application.FENIX, channel=NimbusExperiment.Channel.FENIX_NIGHTLY, ) serializer = NimbusExperimentSerializer(experiment) self.assertEqual(serializer.data["application"], NimbusExperiment.Channel.FENIX_NIGHTLY) self.assertEqual(serializer.data["channel"], NimbusExperiment.Channel.FENIX_NIGHTLY) check_schema("experiments/NimbusExperiment", serializer.data)
def test_serializers_with_missing_feature_value(self, application): experiment = NimbusExperimentFactory.create_with_lifecycle( NimbusExperimentFactory.Lifecycles.LAUNCH_APPROVE, application=application, branches=[], ) experiment.reference_branch = NimbusBranchFactory( experiment=experiment, feature_value=None ) experiment.save() serializer = NimbusExperimentSerializer(experiment) self.assertEqual(serializer.data["branches"][0]["feature"]["value"], {}) check_schema("experiments/NimbusExperiment", serializer.data)
def test_serializer_outputs_targeting_for_experiment_without_firefox_min_version( self, ): experiment = NimbusExperimentFactory.create_with_status( NimbusExperiment.Status.ACCEPTED, firefox_min_version=None, targeting_config_slug=NimbusExperiment.TargetingConfig.ALL_ENGLISH, channel=NimbusExperiment.Channel.DESKTOP_NIGHTLY, ) serializer = NimbusExperimentSerializer(experiment) self.assertEqual( serializer.data["targeting"], ('browserSettings.update.channel == "nightly" ' "&& localeLanguageCode == 'en' " "&& 'app.shield.optoutstudies.enabled'|preferenceValue"), ) check_schema("experiments/NimbusExperiment", serializer.data)
def test_serializer_outputs_targeting_for_experiment_without_channels( self): experiment = NimbusExperimentFactory.create_with_status( NimbusExperiment.Status.ACCEPTED, firefox_min_version=NimbusExperiment.Version.FIREFOX_80, targeting_config_slug=NimbusExperiment.TargetingConfig.ALL_ENGLISH, application=NimbusExperiment.Application.DESKTOP, channel=None, ) serializer = NimbusExperimentSerializer(experiment) self.assertEqual( serializer.data["targeting"], ("version|versionCompare('80.!') >= 0 " "&& localeLanguageCode == 'en' " "&& 'app.shield.optoutstudies.enabled'|preferenceValue"), ) check_schema("experiments/NimbusExperiment", serializer.data)
def test_serializer_outputs_expected_schema_without_feature(self): experiment = NimbusExperimentFactory.create_with_status( NimbusExperiment.Status.ACCEPTED, feature_config=None, ) serializer = NimbusExperimentSerializer(experiment) experiment_data = serializer.data.copy() branches_data = [dict(b) for b in experiment_data.pop("branches")] self.assertEqual(len(branches_data), 2) for branch in experiment.branches.all(): self.assertIn( { "slug": branch.slug, "ratio": branch.ratio }, branches_data, ) check_schema("experiments/NimbusExperiment", serializer.data)
def test_sets_app_id_name_channel_for_application( self, application, channel, expected_application, expected_appId, expected_appName, ): experiment = NimbusExperimentFactory.create_with_lifecycle( NimbusExperimentFactory.Lifecycles.LAUNCH_APPROVE, application=application, channel=channel, ) serializer = NimbusExperimentSerializer(experiment) self.assertEqual(serializer.data["application"], expected_application) self.assertEqual(serializer.data["channel"], channel) self.assertEqual(serializer.data["appName"], expected_appName) self.assertEqual(serializer.data["appId"], expected_appId) check_schema("experiments/NimbusExperiment", serializer.data)
def test_serializer_outputs_expected_schema_with_feature(self): experiment = NimbusExperimentFactory.create_with_lifecycle( NimbusExperimentFactory.Lifecycles.ENDING_APPROVE_APPROVE, application=NimbusExperiment.Application.DESKTOP, firefox_min_version=NimbusExperiment.Version.FIREFOX_83, targeting_config_slug=NimbusExperiment.TargetingConfig.ALL_ENGLISH, channel=NimbusExperiment.Channel.NIGHTLY, primary_outcomes=["foo", "bar", "baz"], secondary_outcomes=["quux", "xyzzy"], ) serializer = NimbusExperimentSerializer(experiment) experiment_data = serializer.data.copy() bucket_data = dict(experiment_data.pop("bucketConfig")) branches_data = [dict(b) for b in experiment_data.pop("branches")] self.assertDictEqual( experiment_data, { "arguments": {}, "application": "firefox-desktop", "appName": "firefox_desktop", "appId": "firefox-desktop", "channel": "nightly", # DRF manually replaces the isoformat suffix so we have to do the same "endDate": experiment.end_date.isoformat().replace("+00:00", "Z"), "id": experiment.slug, "isEnrollmentPaused": True, "proposedDuration": experiment.proposed_duration, "proposedEnrollment": experiment.proposed_enrollment, "referenceBranch": experiment.reference_branch.slug, "schemaVersion": settings.NIMBUS_SCHEMA_VERSION, "slug": experiment.slug, # DRF manually replaces the isoformat suffix so we have to do the same "startDate": experiment.start_date.isoformat().replace("+00:00", "Z"), "targeting": ( 'browserSettings.update.channel == "nightly" ' "&& version|versionCompare('83.!') >= 0 " "&& 'app.shield.optoutstudies.enabled'|preferenceValue " "&& localeLanguageCode == 'en'" ), "userFacingDescription": experiment.public_description, "userFacingName": experiment.name, "probeSets": [], "outcomes": [ {"priority": "primary", "slug": "foo"}, {"priority": "primary", "slug": "bar"}, {"priority": "primary", "slug": "baz"}, {"priority": "secondary", "slug": "quux"}, {"priority": "secondary", "slug": "xyzzy"}, ], "featureIds": [experiment.feature_config.slug], }, ) self.assertEqual( bucket_data, { "randomizationUnit": ( experiment.bucket_range.isolation_group.randomization_unit ), "namespace": experiment.bucket_range.isolation_group.namespace, "start": experiment.bucket_range.start, "count": experiment.bucket_range.count, "total": experiment.bucket_range.isolation_group.total, }, ) self.assertEqual(len(branches_data), 2) for branch in experiment.branches.all(): self.assertIn( { "slug": branch.slug, "ratio": branch.ratio, "feature": { "featureId": experiment.feature_config.slug, "enabled": branch.feature_enabled, "value": json.loads(branch.feature_value), }, }, branches_data, ) check_schema("experiments/NimbusExperiment", serializer.data)
def test_schema_check_fails(): data = {} with pytest.raises(jsonschema.exceptions.ValidationError): mozilla_nimbus_shared.check_schema("normandy/ConsoleLogArguments", data)
def test_schema_check_passes(): data = {"message": "test"} assert mozilla_nimbus_shared.check_schema("normandy/ConsoleLogArguments", data)
def test_missing_schema_throws_the_right_error(self): with pytest.raises(mozilla_nimbus_shared.NimbusSchemaNotFoundError): mozilla_nimbus_shared.check_schema("Bogus/Schema", {})
def test_serializer_outputs_expected_schema_with_feature(self): probe_set = NimbusProbeSetFactory.create() experiment = NimbusExperimentFactory.create_with_status( NimbusExperiment.Status.COMPLETE, application=NimbusExperiment.Application.DESKTOP, firefox_min_version=NimbusExperiment.Version.FIREFOX_80, targeting_config_slug=NimbusExperiment.TargetingConfig.ALL_ENGLISH, channel=NimbusExperiment.Channel.DESKTOP_NIGHTLY, probe_sets=[probe_set], ) serializer = NimbusExperimentSerializer(experiment) all_experiment_data = serializer.data.copy() arguments_data = all_experiment_data.pop("arguments") for experiment_data in arguments_data, all_experiment_data: branches_data = [dict(b) for b in experiment_data.pop("branches")] self.assertEqual( experiment_data, { "application": experiment.application, "channel": experiment.channel, "bucketConfig": { "randomizationUnit": (experiment.bucket_range.isolation_group. randomization_unit), "namespace": experiment.bucket_range.isolation_group.namespace, "start": experiment.bucket_range.start, "count": experiment.bucket_range.count, "total": experiment.bucket_range.isolation_group.total, }, # DRF manually replaces the isoformat suffix so we have to do the same "endDate": experiment.end_date.isoformat().replace("+00:00", "Z"), "id": experiment.slug, "isEnrollmentPaused": False, "proposedDuration": experiment.proposed_duration, "proposedEnrollment": experiment.proposed_enrollment, "referenceBranch": experiment.reference_branch.slug, "schemaVersion": settings.NIMBUS_SCHEMA_VERSION, "slug": experiment.slug, # DRF manually replaces the isoformat suffix so we have to do the same "startDate": experiment.start_date.isoformat().replace("+00:00", "Z"), "targeting": ('browserSettings.update.channel == "nightly" ' "&& version|versionCompare('80.!') >= 0 " "&& localeLanguageCode == 'en' " "&& 'app.shield.optoutstudies.enabled'|preferenceValue"), "userFacingDescription": experiment.public_description, "userFacingName": experiment.name, "probeSets": [probe_set.slug], }, ) self.assertEqual(len(branches_data), 2) for branch in experiment.branches.all(): self.assertIn( { "slug": branch.slug, "ratio": branch.ratio, "feature": { "featureId": experiment.feature_config.slug, "enabled": branch.feature_enabled, "value": json.loads(branch.feature_value), }, }, branches_data, ) check_schema("experiments/NimbusExperiment", serializer.data)