From 5c6f62390a00421d8b42b49de03ed66b687fb66c Mon Sep 17 00:00:00 2001 From: Peter Adam Korodi <52385411+kp-cat@users.noreply.github.com> Date: Fri, 19 Jan 2024 18:32:07 +0100 Subject: [PATCH] String List check (#60) * update config_v6 sdk keys in the sample apps * string list check * spec char test --- configcatclient/rolloutevaluator.py | 12 +++++++ configcatclienttests/test_evaluationlog.py | 32 +++++++++---------- .../test_integration_configcatclient.py | 2 +- .../test_lazyloadingcachepolicy.py | 1 - configcatclienttests/test_specialcharacter.py | 30 +++++++++++++++++ 5 files changed, 59 insertions(+), 18 deletions(-) create mode 100644 configcatclienttests/test_specialcharacter.py diff --git a/configcatclient/rolloutevaluator.py b/configcatclient/rolloutevaluator.py index f233f26..a1e9c34 100644 --- a/configcatclient/rolloutevaluator.py +++ b/configcatclient/rolloutevaluator.py @@ -188,9 +188,21 @@ def _get_user_attribute_value_as_string_list(self, attribute_value): attribute_value_list = json.loads(attribute_value) else: attribute_value_list = attribute_value + + # Check if the result is a list if not isinstance(attribute_value_list, list): raise ValueError() + # Check if all items in the list are strings + for item in attribute_value_list: + # Handle unicode strings on Python 2.7 + if sys.version_info[0] == 2: + if not isinstance(attribute_value, (str, unicode)): # noqa: F821 + return attribute_value + else: + if not isinstance(item, str): + raise ValueError() + return attribute_value_list def _handle_invalid_user_attribute(self, comparison_attribute, comparator, comparison_value, key, validation_error): diff --git a/configcatclienttests/test_evaluationlog.py b/configcatclienttests/test_evaluationlog.py index 2a9c652..e22786b 100644 --- a/configcatclienttests/test_evaluationlog.py +++ b/configcatclienttests/test_evaluationlog.py @@ -26,52 +26,52 @@ def remove_unicode_prefix(string): class EvaluationLogTests(unittest.TestCase): def test_simple_value(self): - self.assertTrue(self._evaluation_log('data/evaluation/simple_value.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/simple_value.json')) def test_1_targeting_rule(self): - self.assertTrue(self._evaluation_log('data/evaluation/1_targeting_rule.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/1_targeting_rule.json')) def test_2_targeting_rules(self): - self.assertTrue(self._evaluation_log('data/evaluation/2_targeting_rules.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/2_targeting_rules.json')) def test_options_based_on_user_id(self): - self.assertTrue(self._evaluation_log('data/evaluation/options_based_on_user_id.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/options_based_on_user_id.json')) def test_options_based_on_custom_attr(self): - self.assertTrue(self._evaluation_log('data/evaluation/options_based_on_custom_attr.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/options_based_on_custom_attr.json')) def test_options_after_targeting_rule(self): - self.assertTrue(self._evaluation_log('data/evaluation/options_after_targeting_rule.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/options_after_targeting_rule.json')) def test_options_within_targeting_rule(self): - self.assertTrue(self._evaluation_log('data/evaluation/options_within_targeting_rule.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/options_within_targeting_rule.json')) def test_and_rules(self): - self.assertTrue(self._evaluation_log('data/evaluation/and_rules.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/and_rules.json')) def test_segment(self): - self.assertTrue(self._evaluation_log('data/evaluation/segment.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/segment.json')) def test_prerequisite_flag(self): - self.assertTrue(self._evaluation_log('data/evaluation/prerequisite_flag.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/prerequisite_flag.json')) def test_semver_validation(self): - self.assertTrue(self._evaluation_log('data/evaluation/semver_validation.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/semver_validation.json')) def test_epoch_date_validation(self): - self.assertTrue(self._evaluation_log('data/evaluation/epoch_date_validation.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/epoch_date_validation.json')) def test_number_validation(self): - self.assertTrue(self._evaluation_log('data/evaluation/number_validation.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/number_validation.json')) def test_comparators_validation(self): self.maxDiff = None - self.assertTrue(self._evaluation_log('data/evaluation/comparators.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/comparators.json')) def test_list_truncation_validation(self): - self.assertTrue(self._evaluation_log('data/evaluation/list_truncation.json')) + self.assertTrue(self._test_evaluation_log('data/evaluation/list_truncation.json')) - def _evaluation_log(self, file_path, test_filter=None, generate_expected_log=False): + def _test_evaluation_log(self, file_path, test_filter=None, generate_expected_log=False): script_dir = os.path.dirname(__file__) file_path = os.path.join(script_dir, file_path) self.assertTrue(os.path.isfile(file_path)) diff --git a/configcatclienttests/test_integration_configcatclient.py b/configcatclienttests/test_integration_configcatclient.py index 5bfcb75..70037fc 100644 --- a/configcatclienttests/test_integration_configcatclient.py +++ b/configcatclienttests/test_integration_configcatclient.py @@ -20,7 +20,7 @@ except ImportError: from mock import Mock, ANY -_SDK_KEY = 'PKDVCLf-Hq-h-kCzMp-L7Q/PaDVCFk9EpmD6sLpGLltTA' +_SDK_KEY = 'configcat-sdk-1/PKDVCLf-Hq-h-kCzMp-L7Q/1cGEJXUwYUGZCBOL-E2sOw' class DefaultTests(unittest.TestCase): diff --git a/configcatclienttests/test_lazyloadingcachepolicy.py b/configcatclienttests/test_lazyloadingcachepolicy.py index e09f88c..f1c6b42 100644 --- a/configcatclienttests/test_lazyloadingcachepolicy.py +++ b/configcatclienttests/test_lazyloadingcachepolicy.py @@ -186,7 +186,6 @@ def test_cache_TTL_respects_external_cache(self): response_mock.json.return_value = json.loads(config_json_string_remote) response_mock.text = config_json_string_remote response_mock.status_code = 200 - # response_mock.headers = {'ETag': 'etag'} config_json_string_local = TEST_JSON_FORMAT.format(value_type=SettingType.STRING, value='{"s": "test-local"}') config_cache = SingleValueConfigCache(ConfigEntry( diff --git a/configcatclienttests/test_specialcharacter.py b/configcatclienttests/test_specialcharacter.py new file mode 100644 index 0000000..4fe5ebe --- /dev/null +++ b/configcatclienttests/test_specialcharacter.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +import logging +import unittest + +import configcatclient +from configcatclient.user import User + +logging.basicConfig(level=logging.INFO) + +_SDK_KEY = 'configcat-sdk-1/PKDVCLf-Hq-h-kCzMp-L7Q/u28_1qNyZ0Wz-ldYHIU7-g' + + +class SpecialCharacterTests(unittest.TestCase): + def setUp(self): + self.client = configcatclient.get(_SDK_KEY) + + def tearDown(self): + self.client.close() + + def test_special_characters_works_cleartext(self): + actual = self.client.get_value("specialCharacters", "NOT_CAT", User('äöüÄÖÜçéèñışğ⢙✓😀')) + self.assertEqual(actual, 'äöüÄÖÜçéèñışğ⢙✓😀') + + def test_special_characters_works_hashed(self): + actual = self.client.get_value("specialCharactersHashed", "NOT_CAT", User('äöüÄÖÜçéèñışğ⢙✓😀')) + self.assertEqual(actual, 'äöüÄÖÜçéèñışğ⢙✓😀') + + +if __name__ == '__main__': + unittest.main()