From ad28bda52b97d05fa6fa31d8116ab6ccfae9bf0b Mon Sep 17 00:00:00 2001 From: Alissa Sobo Date: Sat, 7 Mar 2020 17:38:25 -0800 Subject: [PATCH] Add windows build number filter object --- docs/user/filters.rst | 1 + normandy/recipes/filters.py | 34 ++++++++++++++++++++++++++ normandy/recipes/tests/test_filters.py | 28 +++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/docs/user/filters.rst b/docs/user/filters.rst index 1d088352..20da5b23 100644 --- a/docs/user/filters.rst +++ b/docs/user/filters.rst @@ -29,6 +29,7 @@ Filter Objects .. autoclass:: PrefExistsFilter() .. autoclass:: PrefCompareFilter() .. autoclass:: PrefUserSetFilter() +.. autoclass:: WindowsBuildNumberFilter() Filter Expressions diff --git a/normandy/recipes/filters.py b/normandy/recipes/filters.py index bb74a614..a104023e 100644 --- a/normandy/recipes/filters.py +++ b/normandy/recipes/filters.py @@ -48,6 +48,22 @@ class BaseFilter(serializers.Serializer): """Render this filter to a JEXL expression""" raise NotImplementedError + def to_operator(self, comparison): + if comparison == "equal": + return "==" + elif comparison == "not_equal": + return "!=" + elif comparison == "greater_than": + return ">" + elif comparison == "greater_than_equal": + return ">=" + elif comparison == "less_than": + return "<" + elif comparison == "less_than_equal": + return "<=" + else: + raise serializers.ValidationError(f"Unrecognized comparison {comparison!r}") + class ChannelFilter(BaseFilter): """ @@ -547,6 +563,24 @@ class DateRangeFilter(BaseFilter): return {"jexl.transform.date"} +class WindowsBuildNumberFilter(BaseFilter): + type = "windows_build_number" + build_number = serializers.IntegerField() + comparison = serializers.CharField() + + def to_jexl(self): + comparison = self.initial_data["comparison"] + build_number = self.initial_data["build_number"] + + symbol = self.to_operator(comparison) + + return f"(normandy.os.isWindows && normandy.os.windowsBuildNumber {symbol} {build_number})" + + @property + def capabilities(self): + return set() + + class ProfileCreateDateFilter(BaseFilter): """ This filter is meant to distinguish between new and existing users. diff --git a/normandy/recipes/tests/test_filters.py b/normandy/recipes/tests/test_filters.py index 2273d9be..91de78dc 100644 --- a/normandy/recipes/tests/test_filters.py +++ b/normandy/recipes/tests/test_filters.py @@ -15,6 +15,7 @@ from normandy.recipes.filters import ( PrefCompareFilter, PrefExistsFilter, PrefUserSetFilter, + WindowsBuildNumberFilter, ) from normandy.recipes.tests import ChannelFactory, LocaleFactory, CountryFactory @@ -121,6 +122,33 @@ class TestDateRangeFilter(FilterTestsBase): } +class TestWindowsBuildNumberFiter(FilterTestsBase): + def create_basic_filter(self, build_number=12345, comparison="equal"): + return WindowsBuildNumberFilter.create(build_number=build_number, comparison=comparison) + + @pytest.mark.parametrize( + "comparison,symbol", + [ + ("equal", "=="), + ("greater_than", ">"), + ("greater_than_equal", ">="), + ("less_than", "<"), + ("less_than_equal", "<="), + ], + ) + def test_generates_jexl_number_ops(self, comparison, symbol): + filter = self.create_basic_filter(comparison=comparison) + assert ( + filter.to_jexl() + == f"(normandy.os.isWindows && normandy.os.windowsBuildNumber {symbol} 12345)" + ) + + def test_generates_jexl_error_on_bad_comparison(self): + filter = self.create_basic_filter(comparison="typo") + with pytest.raises(serializers.ValidationError): + filter.to_jexl() + + class TestChannelFilter(FilterTestsBase): def create_basic_filter(self, channels=None): if channels: