From 74440dbf657280b0d5d0ff36d79c084ef9f4b605 Mon Sep 17 00:00:00 2001 From: Beth Rennie Date: Thu, 7 Nov 2024 15:34:23 -0500 Subject: [PATCH] feat(nimbus): Update to mozilla-nimbus-schemas 2024.11.5 Because: - we now have strict and lax schemas for Desktop Nimbus Experiments and a separate schema for SDK Nimbus Experiments in mozilla-nimbus-schemas v2024.11.4; and - the updated Desktop schema now has the correct feature placeholder feature ID This commit: - updates us to mozilla-nimbus-schemas v2024.11.5; and - updates our tests to use the appropriate schema validators in tests Fixes #11745 --- .../experimenter/experiments/constants.py | 4 +++ .../tests/api/v6/test_serializers.py | 32 ++++++++++++++----- .../tests/api/v8/test_serializers.py | 9 ------ experimenter/poetry.lock | 10 +++--- experimenter/pyproject.toml | 2 +- 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/experimenter/experimenter/experiments/constants.py b/experimenter/experimenter/experiments/constants.py index fd411531c5..20be391bcf 100644 --- a/experimenter/experimenter/experiments/constants.py +++ b/experimenter/experimenter/experiments/constants.py @@ -314,6 +314,10 @@ class Application(models.TextChoices): ) DEMO_APP = (APPLICATION_CONFIG_DEMO_APP.slug, APPLICATION_CONFIG_DEMO_APP.name) + @staticmethod + def is_sdk(application): + return application != Application.DESKTOP + @staticmethod def is_mobile(application): return application in ( diff --git a/experimenter/experimenter/experiments/tests/api/v6/test_serializers.py b/experimenter/experimenter/experiments/tests/api/v6/test_serializers.py index 576d55d787..2b2699269c 100644 --- a/experimenter/experimenter/experiments/tests/api/v6/test_serializers.py +++ b/experimenter/experimenter/experiments/tests/api/v6/test_serializers.py @@ -4,7 +4,10 @@ from django.conf import settings from django.test import TestCase -from mozilla_nimbus_schemas.experiments import NimbusExperiment as NimbusExperimentSchema +from mozilla_nimbus_schemas.experiments import ( + DesktopAllVersionsNimbusExperiment, + SdkNimbusExperiment, +) from parameterized import parameterized from experimenter.base.tests.factories import LocaleFactory @@ -21,6 +24,19 @@ class TestNimbusExperimentSerializer(TestCase): maxDiff = None + @classmethod + def _validate_experiment_schema( + cls, + application: NimbusExperiment.Application, + experiment_data: dict[str, Any], + ): + if NimbusExperiment.Application.is_sdk(application): + schema = SdkNimbusExperiment + else: + schema = DesktopAllVersionsNimbusExperiment + + schema.model_validate(experiment_data) + def test_expected_schema_with_desktop(self): locale_en_us = LocaleFactory.create(code="en-US") application = NimbusExperiment.Application.DESKTOP @@ -145,7 +161,7 @@ def test_expected_schema_with_desktop(self): branches_data, ) - NimbusExperimentSchema.model_validate(serializer.data) + DesktopAllVersionsNimbusExperiment.model_validate(serializer.data) def test_expected_schema_with_desktop_with_non_default_fxlabs_fields(self): locale_en_us = LocaleFactory.create(code="en-US") @@ -261,7 +277,7 @@ def test_serializers_with_missing_feature_value(self, application): experiment.save() serializer = NimbusExperimentSerializer(experiment) self.assertEqual(serializer.data["branches"][0]["features"], []) - NimbusExperimentSchema.model_validate(serializer.data) + self._validate_experiment_schema(application, serializer.data) def test_serializers_with_empty_feature_value(self): application = NimbusExperiment.Application.DESKTOP @@ -281,7 +297,7 @@ def test_serializers_with_empty_feature_value(self): ) serializer = NimbusExperimentSerializer(experiment) self.assertEqual(serializer.data["branches"][0]["features"][0]["value"], {}) - NimbusExperimentSchema.model_validate(serializer.data) + DesktopAllVersionsNimbusExperiment.model_validate(serializer.data) def test_serializer_with_branch_invalid_feature_value(self): application = NimbusExperiment.Application.DESKTOP @@ -328,7 +344,7 @@ def test_sets_app_id_name_channel_for_application( NimbusExperiment.APPLICATION_CONFIGS[application].app_name, ) self.assertEqual(serializer.data["appId"], channel_app_id) - NimbusExperimentSchema.model_validate(serializer.data) + self._validate_experiment_schema(application, serializer.data) def test_serializer_outputs_targeting(self): experiment = NimbusExperimentFactory.create_with_lifecycle( @@ -339,7 +355,7 @@ def test_serializer_outputs_targeting(self): ) serializer = NimbusExperimentSerializer(experiment) self.assertEqual(serializer.data["targeting"], experiment.targeting) - NimbusExperimentSchema.model_validate(serializer.data) + DesktopAllVersionsNimbusExperiment.model_validate(serializer.data) def test_serializer_outputs_empty_targeting(self): experiment = NimbusExperimentFactory.create_with_lifecycle( @@ -352,7 +368,7 @@ def test_serializer_outputs_empty_targeting(self): serializer = NimbusExperimentSerializer(experiment) self.assertEqual(serializer.data["targeting"], "true") - NimbusExperimentSchema.model_validate(serializer.data) + SdkNimbusExperiment.model_validate(serializer.data) def test_localized_desktop(self): locale_en_us = LocaleFactory.create(code="en-US") @@ -374,7 +390,7 @@ def test_localized_desktop(self): self.assertIn("localizations", serializer.data) self.assertEqual(serializer.data["localizations"], json.loads(TEST_LOCALIZATIONS)) - NimbusExperimentSchema.model_validate(serializer.data) + DesktopAllVersionsNimbusExperiment.model_validate(serializer.data) def test_multiple_locales(self): locale_en_us = LocaleFactory.create(code="en-US") diff --git a/experimenter/experimenter/experiments/tests/api/v8/test_serializers.py b/experimenter/experimenter/experiments/tests/api/v8/test_serializers.py index 7f23820a8d..7d007aad9f 100644 --- a/experimenter/experimenter/experiments/tests/api/v8/test_serializers.py +++ b/experimenter/experimenter/experiments/tests/api/v8/test_serializers.py @@ -4,7 +4,6 @@ from django.conf import settings from django.test import TestCase -from mozilla_nimbus_schemas.experiments import NimbusExperiment as NimbusExperimentSchema from parameterized import parameterized from experimenter.base.tests.factories import LocaleFactory @@ -97,8 +96,6 @@ def test_expected_schema_with_desktop(self): branches_data, ) - NimbusExperimentSchema.model_validate(serializer.data) - def test_expected_schema_with_desktop_with_non_default_fxlabs_fields(self): locale_en_us = LocaleFactory.create(code="en-US") application = NimbusExperiment.Application.DESKTOP @@ -214,7 +211,6 @@ def test_serializers_with_missing_feature_value(self, application): experiment.save() serializer = NimbusExperimentSerializer(experiment) self.assertEqual(serializer.data["branches"][0]["features"], []) - NimbusExperimentSchema.model_validate(serializer.data) def test_serializers_with_empty_feature_value(self): application = NimbusExperiment.Application.DESKTOP @@ -234,7 +230,6 @@ def test_serializers_with_empty_feature_value(self): ) serializer = NimbusExperimentSerializer(experiment) self.assertEqual(serializer.data["branches"][0]["features"][0]["value"], {}) - NimbusExperimentSchema.model_validate(serializer.data) def test_serializer_with_branch_invalid_feature_value(self): application = NimbusExperiment.Application.DESKTOP @@ -281,7 +276,6 @@ def test_sets_app_id_name_channel_for_application( NimbusExperiment.APPLICATION_CONFIGS[application].app_name, ) self.assertEqual(serializer.data["appId"], channel_app_id) - NimbusExperimentSchema.model_validate(serializer.data) def test_serializer_outputs_targeting(self): experiment = NimbusExperimentFactory.create_with_lifecycle( @@ -292,7 +286,6 @@ def test_serializer_outputs_targeting(self): ) serializer = NimbusExperimentSerializer(experiment) self.assertEqual(serializer.data["targeting"], experiment.targeting) - NimbusExperimentSchema.model_validate(serializer.data) def test_serializer_outputs_empty_targeting(self): experiment = NimbusExperimentFactory.create_with_lifecycle( @@ -305,7 +298,6 @@ def test_serializer_outputs_empty_targeting(self): serializer = NimbusExperimentSerializer(experiment) self.assertEqual(serializer.data["targeting"], "true") - NimbusExperimentSchema.model_validate(serializer.data) def test_localized_desktop(self): locale_en_us = LocaleFactory.create(code="en-US") @@ -328,7 +320,6 @@ def test_localized_desktop(self): self.assertIn("localizations", serializer.data) self.assertEqual(serializer.data["localizations"], json.loads(TEST_LOCALIZATIONS)) - NimbusExperimentSchema.model_validate(serializer.data) def test_multiple_locales(self): locale_en_us = LocaleFactory.create(code="en-US") diff --git a/experimenter/poetry.lock b/experimenter/poetry.lock index 079a965fa3..d2dd716635 100644 --- a/experimenter/poetry.lock +++ b/experimenter/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "amqp" @@ -1695,13 +1695,13 @@ testing = ["coverage", "isort", "jsonschema", "mypy", "pytest", "pytest-black", [[package]] name = "mozilla-nimbus-schemas" -version = "2024.11.2" +version = "2024.11.5" description = "Schemas used by Mozilla Nimbus and related projects." optional = false python-versions = "<4.0,>=3.10" files = [ - {file = "mozilla_nimbus_schemas-2024.11.2-py3-none-any.whl", hash = "sha256:451eab2a002c98ec1731708abcf60960ee5170a5a8ee27717f1326a994ea6853"}, - {file = "mozilla_nimbus_schemas-2024.11.2.tar.gz", hash = "sha256:9d8463f97d48c5153a4119aa573226db84fb518e7fa8a26d8923e537bc741d5b"}, + {file = "mozilla_nimbus_schemas-2024.11.5-py3-none-any.whl", hash = "sha256:4b4e6835b1e8e142f79a7543238a7f8b9a5c5abd7178cb86d9f266f9eee5deb5"}, + {file = "mozilla_nimbus_schemas-2024.11.5.tar.gz", hash = "sha256:83de58bea9d56be679ad0bb174c5769ba5f076ef25e566868b4582ddb3867b01"}, ] [package.dependencies] @@ -3282,4 +3282,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "9960b8299f3ba3c0d959b4421bed8df7a09f1170f791a58c9709048bd9f7b7e3" +content-hash = "f9d0c7851c4de4588e02329be2b7670f34a459bc2c2277de3da8dd84c2ce9231" diff --git a/experimenter/pyproject.toml b/experimenter/pyproject.toml index fed6c360d0..ab68fc07a9 100644 --- a/experimenter/pyproject.toml +++ b/experimenter/pyproject.toml @@ -64,7 +64,7 @@ djangorestframework-dataclasses = "^1.3.0" graphene-django = "^3.2.0" pyright = "^1.1.291" django-types = "^0.19.1" -mozilla-nimbus-schemas = "2024.11.2" +mozilla-nimbus-schemas = "2024.11.5" mozilla-metric-config-parser = "^2024.10.2" django-redis = "^5.4.0" fontawesomefree = "6.6.0"