|
|
|
@@ -6,7 +6,7 @@ from dateutil import parser, tz
|
|
|
|
|
from freezegun import freeze_time
|
|
|
|
|
|
|
|
|
|
from posthog.client import Client
|
|
|
|
|
from posthog.feature_flags import InconclusiveMatchError, match_property
|
|
|
|
|
from posthog.feature_flags import InconclusiveMatchError, match_property, relative_date_parse_for_feature_flag_matching
|
|
|
|
|
from posthog.request import APIError
|
|
|
|
|
from posthog.test.test_utils import FAKE_TEST_API_KEY
|
|
|
|
|
|
|
|
|
@@ -1775,7 +1775,8 @@ class TestMatchProperties(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
self.assertFalse(match_property(property_a, {"key": 0}))
|
|
|
|
|
self.assertFalse(match_property(property_a, {"key": -1}))
|
|
|
|
|
self.assertFalse(match_property(property_a, {"key": "23"}))
|
|
|
|
|
# now we handle type mismatches so this should be true
|
|
|
|
|
self.assertTrue(match_property(property_a, {"key": "23"}))
|
|
|
|
|
|
|
|
|
|
property_b = self.property(key="key", value=1, operator="lt")
|
|
|
|
|
self.assertTrue(match_property(property_b, {"key": 0}))
|
|
|
|
@@ -1792,7 +1793,8 @@ class TestMatchProperties(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
self.assertFalse(match_property(property_c, {"key": 0}))
|
|
|
|
|
self.assertFalse(match_property(property_c, {"key": -1}))
|
|
|
|
|
self.assertFalse(match_property(property_c, {"key": "3"}))
|
|
|
|
|
# now we handle type mismatches so this should be true
|
|
|
|
|
self.assertTrue(match_property(property_c, {"key": "3"}))
|
|
|
|
|
|
|
|
|
|
property_d = self.property(key="key", value="43", operator="lte")
|
|
|
|
|
self.assertTrue(match_property(property_d, {"key": "41"}))
|
|
|
|
@@ -1801,6 +1803,21 @@ class TestMatchProperties(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
self.assertFalse(match_property(property_d, {"key": "44"}))
|
|
|
|
|
self.assertFalse(match_property(property_d, {"key": 44}))
|
|
|
|
|
self.assertTrue(match_property(property_d, {"key": 42}))
|
|
|
|
|
|
|
|
|
|
property_e = self.property(key="key", value="30", operator="lt")
|
|
|
|
|
self.assertTrue(match_property(property_e, {"key": "29"}))
|
|
|
|
|
|
|
|
|
|
# depending on the type of override, we adjust type comparison
|
|
|
|
|
self.assertTrue(match_property(property_e, {"key": "100"}))
|
|
|
|
|
self.assertFalse(match_property(property_e, {"key": 100}))
|
|
|
|
|
|
|
|
|
|
property_f = self.property(key="key", value="123aloha", operator="gt")
|
|
|
|
|
self.assertFalse(match_property(property_f, {"key": "123"}))
|
|
|
|
|
self.assertFalse(match_property(property_f, {"key": 122}))
|
|
|
|
|
|
|
|
|
|
# this turns into a string comparison
|
|
|
|
|
self.assertTrue(match_property(property_f, {"key": 129}))
|
|
|
|
|
|
|
|
|
|
def test_match_property_date_operators(self):
|
|
|
|
|
property_a = self.property(key="key", value="2022-05-01", operator="is_date_before")
|
|
|
|
@@ -1854,6 +1871,305 @@ class TestMatchProperties(unittest.TestCase):
|
|
|
|
|
self.assertTrue(match_property(property_d, {"key": "2022-04-05 11:34:11 +00:00"}))
|
|
|
|
|
self.assertFalse(match_property(property_d, {"key": "2022-04-05 11:34:13 +00:00"}))
|
|
|
|
|
|
|
|
|
|
@freeze_time("2022-05-01")
|
|
|
|
|
def test_match_property_relative_date_operators(self):
|
|
|
|
|
property_a = self.property(key="key", value="6h", operator="is_relative_date_before")
|
|
|
|
|
self.assertTrue(match_property(property_a, {"key": "2022-03-01"}))
|
|
|
|
|
self.assertTrue(match_property(property_a, {"key": "2022-04-30"}))
|
|
|
|
|
self.assertTrue(match_property(property_a, {"key": datetime.datetime(2022, 4, 30, 1, 2, 3)}))
|
|
|
|
|
# false because date comparison, instead of datetime, so reduces to same date
|
|
|
|
|
self.assertFalse(match_property(property_a, {"key": datetime.date(2022, 4, 30)}))
|
|
|
|
|
|
|
|
|
|
self.assertFalse(match_property(property_a, {"key": datetime.datetime(2022, 4, 30, 19, 2, 3)}))
|
|
|
|
|
self.assertTrue(
|
|
|
|
|
match_property(
|
|
|
|
|
property_a,
|
|
|
|
|
{"key": datetime.datetime(2022, 4, 30, 1, 2, 3, tzinfo=tz.gettz("Europe/Madrid"))},
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
self.assertTrue(match_property(property_a, {"key": parser.parse("2022-04-30")}))
|
|
|
|
|
self.assertFalse(match_property(property_a, {"key": "2022-05-30"}))
|
|
|
|
|
|
|
|
|
|
# Can't be a number
|
|
|
|
|
with self.assertRaises(InconclusiveMatchError):
|
|
|
|
|
match_property(property_a, {"key": 1})
|
|
|
|
|
|
|
|
|
|
# can't be invalid string
|
|
|
|
|
with self.assertRaises(InconclusiveMatchError):
|
|
|
|
|
match_property(property_a, {"key": "abcdef"})
|
|
|
|
|
|
|
|
|
|
property_b = self.property(key="key", value="1h", operator="is_relative_date_after")
|
|
|
|
|
self.assertTrue(match_property(property_b, {"key": "2022-05-02"}))
|
|
|
|
|
self.assertTrue(match_property(property_b, {"key": "2022-05-30"}))
|
|
|
|
|
self.assertTrue(match_property(property_b, {"key": datetime.datetime(2022, 5, 30)}))
|
|
|
|
|
self.assertTrue(match_property(property_b, {"key": parser.parse("2022-05-30")}))
|
|
|
|
|
self.assertFalse(match_property(property_b, {"key": "2022-04-30"}))
|
|
|
|
|
|
|
|
|
|
# can't be invalid string
|
|
|
|
|
with self.assertRaises(InconclusiveMatchError):
|
|
|
|
|
self.assertFalse(match_property(property_b, {"key": "abcdef"}))
|
|
|
|
|
|
|
|
|
|
# Invalid flag property
|
|
|
|
|
property_c = self.property(key="key", value=1234, operator="is_relative_date_after")
|
|
|
|
|
|
|
|
|
|
with self.assertRaises(InconclusiveMatchError):
|
|
|
|
|
self.assertFalse(match_property(property_c, {"key": 1}))
|
|
|
|
|
|
|
|
|
|
with self.assertRaises(InconclusiveMatchError):
|
|
|
|
|
self.assertFalse(match_property(property_c, {"key": "2022-05-30"}))
|
|
|
|
|
|
|
|
|
|
# # Timezone aware property
|
|
|
|
|
property_d = self.property(key="key", value="12d", operator="is_relative_date_before")
|
|
|
|
|
self.assertFalse(match_property(property_d, {"key": "2022-05-30"}))
|
|
|
|
|
|
|
|
|
|
self.assertTrue(match_property(property_d, {"key": "2022-03-30"}))
|
|
|
|
|
self.assertTrue(match_property(property_d, {"key": "2022-04-05 12:34:11+01:00"}))
|
|
|
|
|
self.assertTrue(match_property(property_d, {"key": "2022-04-19 01:34:11+02:00"}))
|
|
|
|
|
|
|
|
|
|
self.assertFalse(match_property(property_d, {"key": "2022-04-19 02:00:01+02:00"}))
|
|
|
|
|
|
|
|
|
|
# Try all possible relative dates
|
|
|
|
|
property_e = self.property(key="key", value="1h", operator="is_relative_date_before")
|
|
|
|
|
self.assertFalse(match_property(property_e, {"key": "2022-05-01 00:00:00"}))
|
|
|
|
|
self.assertTrue(match_property(property_e, {"key": "2022-04-30 22:00:00"}))
|
|
|
|
|
|
|
|
|
|
property_f = self.property(key="key", value="1d", operator="is_relative_date_before")
|
|
|
|
|
self.assertTrue(match_property(property_f, {"key": "2022-04-29 23:59:00"}))
|
|
|
|
|
self.assertFalse(match_property(property_f, {"key": "2022-04-30 00:00:01"}))
|
|
|
|
|
|
|
|
|
|
property_g = self.property(key="key", value="1w", operator="is_relative_date_before")
|
|
|
|
|
self.assertTrue(match_property(property_g, {"key": "2022-04-23 00:00:00"}))
|
|
|
|
|
self.assertFalse(match_property(property_g, {"key": "2022-04-24 00:00:00"}))
|
|
|
|
|
self.assertFalse(match_property(property_g, {"key": "2022-04-24 00:00:01"}))
|
|
|
|
|
|
|
|
|
|
property_h = self.property(key="key", value="1m", operator="is_relative_date_before")
|
|
|
|
|
self.assertTrue(match_property(property_h, {"key": "2022-03-01 00:00:00"}))
|
|
|
|
|
self.assertFalse(match_property(property_h, {"key": "2022-04-05 00:00:00"}))
|
|
|
|
|
|
|
|
|
|
property_i = self.property(key="key", value="1y", operator="is_relative_date_before")
|
|
|
|
|
self.assertTrue(match_property(property_i, {"key": "2021-04-28 00:00:00"}))
|
|
|
|
|
self.assertFalse(match_property(property_i, {"key": "2021-05-01 00:00:01"}))
|
|
|
|
|
|
|
|
|
|
property_j = self.property(key="key", value="122h", operator="is_relative_date_after")
|
|
|
|
|
self.assertTrue(match_property(property_j, {"key": "2022-05-01 00:00:00"}))
|
|
|
|
|
self.assertFalse(match_property(property_j, {"key": "2022-04-23 01:00:00"}))
|
|
|
|
|
|
|
|
|
|
property_k = self.property(key="key", value="2d", operator="is_relative_date_after")
|
|
|
|
|
self.assertTrue(match_property(property_k, {"key": "2022-05-01 00:00:00"}))
|
|
|
|
|
self.assertTrue(match_property(property_k, {"key": "2022-04-29 00:00:01"}))
|
|
|
|
|
self.assertFalse(match_property(property_k, {"key": "2022-04-29 00:00:00"}))
|
|
|
|
|
|
|
|
|
|
property_l = self.property(key="key", value="02w", operator="is_relative_date_after")
|
|
|
|
|
self.assertTrue(match_property(property_l, {"key": "2022-05-01 00:00:00"}))
|
|
|
|
|
self.assertFalse(match_property(property_l, {"key": "2022-04-16 00:00:00"}))
|
|
|
|
|
|
|
|
|
|
property_m = self.property(key="key", value="1m", operator="is_relative_date_after")
|
|
|
|
|
self.assertTrue(match_property(property_m, {"key": "2022-04-01 00:00:01"}))
|
|
|
|
|
self.assertFalse(match_property(property_m, {"key": "2022-04-01 00:00:00"}))
|
|
|
|
|
|
|
|
|
|
property_n = self.property(key="key", value="1y", operator="is_relative_date_after")
|
|
|
|
|
self.assertTrue(match_property(property_n, {"key": "2022-05-01 00:00:00"}))
|
|
|
|
|
self.assertTrue(match_property(property_n, {"key": "2021-05-01 00:00:01"}))
|
|
|
|
|
self.assertFalse(match_property(property_n, {"key": "2021-05-01 00:00:00"}))
|
|
|
|
|
self.assertFalse(match_property(property_n, {"key": "2021-04-30 00:00:00"}))
|
|
|
|
|
self.assertFalse(match_property(property_n, {"key": "2021-03-01 12:13:00"}))
|
|
|
|
|
|
|
|
|
|
def test_none_property_value_with_all_operators(self):
|
|
|
|
|
property_a = self.property(key="key", value="none", operator="is_not")
|
|
|
|
|
self.assertFalse(match_property(property_a, {"key": None}))
|
|
|
|
|
self.assertTrue(match_property(property_a, {"key": "non"}))
|
|
|
|
|
|
|
|
|
|
property_b = self.property(key="key", value=None, operator="is_set")
|
|
|
|
|
self.assertTrue(match_property(property_b, {"key": None}))
|
|
|
|
|
|
|
|
|
|
property_c = self.property(key="key", value="no", operator="icontains")
|
|
|
|
|
self.assertTrue(match_property(property_c, {"key": None}))
|
|
|
|
|
self.assertFalse(match_property(property_c, {"key": "smh"}))
|
|
|
|
|
|
|
|
|
|
property_d = self.property(key="key", value="No", operator="regex")
|
|
|
|
|
self.assertTrue(match_property(property_d, {"key": None}))
|
|
|
|
|
|
|
|
|
|
property_d_lower_case = self.property(key="key", value="no", operator="regex")
|
|
|
|
|
self.assertFalse(match_property(property_d_lower_case, {"key": None}))
|
|
|
|
|
|
|
|
|
|
property_e = self.property(key="key", value=1, operator="gt")
|
|
|
|
|
self.assertTrue(match_property(property_e, {"key": None}))
|
|
|
|
|
|
|
|
|
|
property_f = self.property(key="key", value=1, operator="lt")
|
|
|
|
|
self.assertFalse(match_property(property_f, {"key": None}))
|
|
|
|
|
|
|
|
|
|
property_g = self.property(key="key", value="xyz", operator="gte")
|
|
|
|
|
self.assertFalse(match_property(property_g, {"key": None}))
|
|
|
|
|
|
|
|
|
|
property_h = self.property(key="key", value="Oo", operator="lte")
|
|
|
|
|
self.assertTrue(match_property(property_h, {"key": None}))
|
|
|
|
|
|
|
|
|
|
property_i = self.property(key="key", value="2022-05-01", operator="is_date_before")
|
|
|
|
|
with self.assertRaises(InconclusiveMatchError):
|
|
|
|
|
self.assertFalse(match_property(property_i, {"key": None}))
|
|
|
|
|
|
|
|
|
|
property_j = self.property(key="key", value="2022-05-01", operator="is_date_after")
|
|
|
|
|
with self.assertRaises(InconclusiveMatchError):
|
|
|
|
|
self.assertFalse(match_property(property_j, {"key": None}))
|
|
|
|
|
|
|
|
|
|
property_k = self.property(key="key", value="2022-05-01", operator="is_date_before")
|
|
|
|
|
with self.assertRaises(InconclusiveMatchError):
|
|
|
|
|
self.assertFalse(match_property(property_k, {"key": "random"}))
|
|
|
|
|
|
|
|
|
|
def test_unknown_operator(self):
|
|
|
|
|
property_a = self.property(key="key", value="2022-05-01", operator="is_unknown")
|
|
|
|
|
with self.assertRaises(InconclusiveMatchError) as exception_context:
|
|
|
|
|
match_property(property_a, {"key": "random"})
|
|
|
|
|
self.assertEqual(str(exception_context.exception), "Unknown operator is_unknown")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestRelativeDateParsing(unittest.TestCase):
|
|
|
|
|
def test_invalid_input(self):
|
|
|
|
|
with freeze_time("2020-01-01T12:01:20.1340Z"):
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1") is None
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1x") is None
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1.2y") is None
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1z") is None
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1s") is None
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("123344000.134m") is None
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("bazinga") is None
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("000bello") is None
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("000hello") is None
|
|
|
|
|
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("000h") is not None
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1000h") is not None
|
|
|
|
|
|
|
|
|
|
def test_overflow(self):
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1000000h") is None
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("100000000000000000y") is None
|
|
|
|
|
|
|
|
|
|
def test_hour_parsing(self):
|
|
|
|
|
with freeze_time("2020-01-01T12:01:20.1340Z"):
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1h") == datetime.datetime(
|
|
|
|
|
2020, 1, 1, 11, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("2h") == datetime.datetime(
|
|
|
|
|
2020, 1, 1, 10, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("24h") == datetime.datetime(
|
|
|
|
|
2019, 12, 31, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("30h") == datetime.datetime(
|
|
|
|
|
2019, 12, 31, 6, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("48h") == datetime.datetime(
|
|
|
|
|
2019, 12, 30, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching(
|
|
|
|
|
"24h"
|
|
|
|
|
) == relative_date_parse_for_feature_flag_matching("1d")
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching(
|
|
|
|
|
"48h"
|
|
|
|
|
) == relative_date_parse_for_feature_flag_matching("2d")
|
|
|
|
|
|
|
|
|
|
def test_day_parsing(self):
|
|
|
|
|
with freeze_time("2020-01-01T12:01:20.1340Z"):
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1d") == datetime.datetime(
|
|
|
|
|
2019, 12, 31, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("2d") == datetime.datetime(
|
|
|
|
|
2019, 12, 30, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("7d") == datetime.datetime(
|
|
|
|
|
2019, 12, 25, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("14d") == datetime.datetime(
|
|
|
|
|
2019, 12, 18, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("30d") == datetime.datetime(
|
|
|
|
|
2019, 12, 2, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("7d") == relative_date_parse_for_feature_flag_matching(
|
|
|
|
|
"1w"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def test_week_parsing(self):
|
|
|
|
|
with freeze_time("2020-01-01T12:01:20.1340Z"):
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1w") == datetime.datetime(
|
|
|
|
|
2019, 12, 25, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("2w") == datetime.datetime(
|
|
|
|
|
2019, 12, 18, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("4w") == datetime.datetime(
|
|
|
|
|
2019, 12, 4, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("8w") == datetime.datetime(
|
|
|
|
|
2019, 11, 6, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1m") == datetime.datetime(
|
|
|
|
|
2019, 12, 1, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("4w") != relative_date_parse_for_feature_flag_matching(
|
|
|
|
|
"1m"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def test_month_parsing(self):
|
|
|
|
|
with freeze_time("2020-01-01T12:01:20.1340Z"):
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1m") == datetime.datetime(
|
|
|
|
|
2019, 12, 1, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("2m") == datetime.datetime(
|
|
|
|
|
2019, 11, 1, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("4m") == datetime.datetime(
|
|
|
|
|
2019, 9, 1, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("8m") == datetime.datetime(
|
|
|
|
|
2019, 5, 1, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1y") == datetime.datetime(
|
|
|
|
|
2019, 1, 1, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching(
|
|
|
|
|
"12m"
|
|
|
|
|
) == relative_date_parse_for_feature_flag_matching("1y")
|
|
|
|
|
|
|
|
|
|
with freeze_time("2020-04-03T00:00:00"):
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1m") == datetime.datetime(
|
|
|
|
|
2020, 3, 3, 0, 0, 0, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("2m") == datetime.datetime(
|
|
|
|
|
2020, 2, 3, 0, 0, 0, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("4m") == datetime.datetime(
|
|
|
|
|
2019, 12, 3, 0, 0, 0, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("8m") == datetime.datetime(
|
|
|
|
|
2019, 8, 3, 0, 0, 0, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1y") == datetime.datetime(
|
|
|
|
|
2019, 4, 3, 0, 0, 0, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching(
|
|
|
|
|
"12m"
|
|
|
|
|
) == relative_date_parse_for_feature_flag_matching("1y")
|
|
|
|
|
|
|
|
|
|
def test_year_parsing(self):
|
|
|
|
|
with freeze_time("2020-01-01T12:01:20.1340Z"):
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("1y") == datetime.datetime(
|
|
|
|
|
2019, 1, 1, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("2y") == datetime.datetime(
|
|
|
|
|
2018, 1, 1, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("4y") == datetime.datetime(
|
|
|
|
|
2016, 1, 1, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
assert relative_date_parse_for_feature_flag_matching("8y") == datetime.datetime(
|
|
|
|
|
2012, 1, 1, 12, 1, 20, 134000, tzinfo=tz.gettz("UTC")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestCaptureCalls(unittest.TestCase):
|
|
|
|
|
@mock.patch.object(Client, "capture")
|
|
|
|
|