diff --git a/experimenter/experimenter/features/manifests/nimbus_fml_loader.py b/experimenter/experimenter/features/manifests/nimbus_fml_loader.py index 044dfd1672..7149ce0f4a 100644 --- a/experimenter/experimenter/features/manifests/nimbus_fml_loader.py +++ b/experimenter/experimenter/features/manifests/nimbus_fml_loader.py @@ -4,7 +4,7 @@ from typing import Optional from django.conf import settings -from nimbus_megazord.fml import FmlClient +from nimbus_megazord.fml import FmlClient, FmlError from experimenter.experiments.constants import NimbusConstants from experimenter.experiments.models import NimbusFeatureVersion @@ -55,10 +55,16 @@ def fml_client(self, version: Optional[NimbusFeatureVersion] = None) -> FmlClien """ file_path = self.file_path(version) if file_path is not None: - return FmlClient( - str(file_path), - self.channel, - ) + try: + return FmlClient( + str(file_path), + self.channel, + ) + except FmlError: + logger.exception( + f"Nimbus FML Loader: FmlClient failed to parse manifest: {file_path}" + ) + return None else: logger.error("Nimbus FML Loader: Failed to get FmlClient.") return None diff --git a/experimenter/experimenter/features/tests/test_nimbus_fml_loader.py b/experimenter/experimenter/features/tests/test_nimbus_fml_loader.py index d5b262df5f..3ce7cff8b6 100644 --- a/experimenter/experimenter/features/tests/test_nimbus_fml_loader.py +++ b/experimenter/experimenter/features/tests/test_nimbus_fml_loader.py @@ -2,7 +2,7 @@ from unittest.mock import patch from django.test import TestCase -from nimbus_megazord.fml import FmlClient +from nimbus_megazord.fml import FmlClient, FmlError from experimenter.experiments.constants import NimbusConstants from experimenter.features.manifests.nimbus_fml_loader import NimbusFmlLoader @@ -210,3 +210,36 @@ def test_return_no_errors_for_invalid_application( self.assertEqual(loader.application, None) self.assertEqual(result, []) self.assertIn("Nimbus FML Loader: Invalid application", log.output[0]) + + @patch( + "nimbus_megazord.fml.FmlClient.__init__", + side_effect=FmlError("gecko-pref and default are mutually exclusive"), + ) + @mock_fml_features + def test_fml_client_returns_none_when_manifest_fails_to_parse(self, _mock_client): + loader = self.create_loader() + with self.assertLogs(level="ERROR") as log: + result = loader.fml_client() + self.assertIsNone(result) + self.assertIn( + "Nimbus FML Loader: FmlClient failed to parse manifest", + log.output[0], + ) + + @patch( + "nimbus_megazord.fml.FmlClient.__init__", + side_effect=FmlError("gecko-pref and default are mutually exclusive"), + ) + @mock_fml_features + def test_get_fml_errors_returns_empty_when_manifest_fails_to_parse( + self, _mock_client + ): + loader = self.create_loader() + test_blob = json.dumps({"enabled": True}) + with self.assertLogs(level="ERROR") as log: + result = loader.get_fml_errors(test_blob, "cookie-banners") + self.assertEqual(result, []) + self.assertIn( + "Nimbus FML Loader: FmlClient failed to parse manifest", + log.output[0], + )