From f1ae8b9ffd99a750c6b6ad7b903c99f3aca18cef Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Mon, 16 Oct 2023 10:36:44 -0700 Subject: [PATCH 1/3] added warning when not ready --- splitio/client/client.py | 2 ++ tests/client/test_client.py | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/splitio/client/client.py b/splitio/client/client.py index 8a638a0b..45c16677 100644 --- a/splitio/client/client.py +++ b/splitio/client/client.py @@ -61,6 +61,7 @@ def destroyed(self): def _evaluate_if_ready(self, matching_key, bucketing_key, feature, attributes=None): if not self.ready: + _LOGGER.warning("The SDK is not ready, results may be incorrect for feature flag %s. Make sure to wait for SDK readiness before using this method", feature) self._telemetry_init_producer.record_not_ready_usage() return { 'treatment': CONTROL, @@ -214,6 +215,7 @@ def _make_evaluations(self, key, feature_flags, attributes, method_name, metric_ def _evaluate_features_if_ready(self, matching_key, bucketing_key, feature_flags, attributes=None): if not self.ready: + _LOGGER.warning("The SDK is not ready, results may be incorrect for feature flags %s. Make sure to wait for SDK readiness before using this method", ', '.join([feature for feature in feature_flags])) self._telemetry_init_producer.record_not_ready_usage() return { feature_flag: { diff --git a/tests/client/test_client.py b/tests/client/test_client.py index fcddbf79..8287cc2a 100644 --- a/tests/client/test_client.py +++ b/tests/client/test_client.py @@ -83,6 +83,7 @@ def test_get_treatment(self, mocker): assert mocker.call( [(Impression('some_key', 'some_feature', 'control', Label.NOT_READY, mocker.ANY, mocker.ANY, mocker.ANY), {'some_attribute': 1})] ) in impmanager.process_impressions.mock_calls + assert _logger.call(["The SDK is not ready, results may be incorrect for feature flag %s. Make sure to wait for SDK readiness before using this method", 'some_feature']) # Test with exception: ready_property.return_value = True @@ -159,6 +160,7 @@ def test_get_treatment_with_config(self, mocker): [(Impression('some_key', 'some_feature', 'control', Label.NOT_READY, mocker.ANY, mocker.ANY, mocker.ANY), {'some_attribute': 1})] ) in impmanager.process_impressions.mock_calls + assert _logger.call(["The SDK is not ready, results may be incorrect for feature flag %s. Make sure to wait for SDK readiness before using this method", 'some_feature']) # Test with exception: ready_property.return_value = True @@ -236,6 +238,7 @@ def test_get_treatments(self, mocker): assert mocker.call( [(Impression('some_key', 'some_feature', 'control', Label.NOT_READY, mocker.ANY, mocker.ANY, mocker.ANY), {'some_attribute': 1})] ) in impmanager.process_impressions.mock_calls + assert _logger.call(["The SDK is not ready, results may be incorrect for feature flags %s. Make sure to wait for SDK readiness before using this method", 'some_feature']) # Test with exception: ready_property.return_value = True @@ -310,6 +313,7 @@ def test_get_treatments_with_config(self, mocker): assert mocker.call( [(Impression('some_key', 'some_feature', 'control', Label.NOT_READY, mocker.ANY, mocker.ANY, mocker.ANY), {'some_attribute': 1})] ) in impmanager.process_impressions.mock_calls + assert _logger.call(["The SDK is not ready, results may be incorrect for feature flags %s. Make sure to wait for SDK readiness before using this method", 'some_feature']) # Test with exception: ready_property.return_value = True @@ -400,6 +404,7 @@ def evaluate_features(feature_flag_names, matching_key, bucketing_key, attribute assert mocker.call( [(Impression('some_key', 'some_feature', 'control', Label.NOT_READY, mocker.ANY, mocker.ANY, mocker.ANY), {'some_attribute': 1})] ) in impmanager.process_impressions.mock_calls + assert _logger.call(["The SDK is not ready, results may be incorrect for feature flags %s. Make sure to wait for SDK readiness before using this method", 'some_feature']) # Test with exception: ready_property.return_value = True @@ -465,7 +470,6 @@ def evaluate_features(feature_flag_names, matching_key, bucketing_key, attribute client._evaluator.evaluate_features = evaluate_features _logger = mocker.Mock() client._send_impression_to_listener = mocker.Mock() -# pytest.set_trace() assert client.get_treatments_by_flag_sets('key', ['set1', 'set2']) == {'f1': 'on', 'f2': 'on'} impressions_called = impmanager.process_impressions.mock_calls[0][1][0] @@ -488,6 +492,7 @@ def evaluate_features(feature_flag_names, matching_key, bucketing_key, attribute assert mocker.call( [(Impression('some_key', 'some_feature', 'control', Label.NOT_READY, mocker.ANY, mocker.ANY, mocker.ANY), {'some_attribute': 1})] ) in impmanager.process_impressions.mock_calls + assert _logger.call(["The SDK is not ready, results may be incorrect for feature flags %s. Make sure to wait for SDK readiness before using this method", 'some_feature']) # Test with exception: ready_property.return_value = True @@ -581,6 +586,7 @@ def evaluate_features(feature_flag_names, matching_key, bucketing_key, attribute assert mocker.call( [(Impression('some_key', 'some_feature', 'control', Label.NOT_READY, mocker.ANY, mocker.ANY, mocker.ANY), {'some_attribute': 1})] ) in impmanager.process_impressions.mock_calls + assert _logger.call(["The SDK is not ready, results may be incorrect for feature flags %s. Make sure to wait for SDK readiness before using this method", 'some_feature']) # Test with exception: ready_property.return_value = True @@ -677,6 +683,7 @@ def evaluate_features(feature_flag_names, matching_key, bucketing_key, attribute assert mocker.call( [(Impression('some_key', 'some_feature', 'control', Label.NOT_READY, mocker.ANY, mocker.ANY, mocker.ANY), {'some_attribute': 1})] ) in impmanager.process_impressions.mock_calls + assert _logger.call(["The SDK is not ready, results may be incorrect for feature flags %s. Make sure to wait for SDK readiness before using this method", 'some_feature']) # Test with exception: ready_property.return_value = True @@ -748,6 +755,7 @@ def test_track(self, mocker): telemetry_producer.get_telemetry_init_producer(), mocker.Mock() ) + _logger = mocker.Mock() destroyed_mock = mocker.PropertyMock() destroyed_mock.return_value = False @@ -762,6 +770,7 @@ def test_track(self, mocker): size=1024 ) ]) in event_storage.put.mock_calls + assert _logger.call("track: the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method") def test_evaluations_before_running_post_fork(self, mocker): destroyed_property = mocker.PropertyMock() From 6636c840b43161154978cec5f60f9f9890902335 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Mon, 16 Oct 2023 10:47:18 -0700 Subject: [PATCH 2/3] added default_treatment to split view --- splitio/models/splits.py | 3 ++- tests/models/test_splits.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/splitio/models/splits.py b/splitio/models/splits.py index 5ab32953..0a10dd87 100644 --- a/splitio/models/splits.py +++ b/splitio/models/splits.py @@ -7,7 +7,7 @@ SplitView = namedtuple( 'SplitView', - ['name', 'traffic_type', 'killed', 'treatments', 'change_number', 'configs', 'sets'] + ['name', 'traffic_type', 'killed', 'treatments', 'change_number', 'configs', 'default_treatment', 'sets'] ) @@ -200,6 +200,7 @@ def to_split_view(self): list(set(part.treatment for cond in self.conditions for part in cond.partitions)), self.change_number, self._configurations if self._configurations is not None else {}, + self._default_treatment, list(self._sets) if self._sets is not None else [] ) diff --git a/tests/models/test_splits.py b/tests/models/test_splits.py index d56e6f77..23688d9e 100644 --- a/tests/models/test_splits.py +++ b/tests/models/test_splits.py @@ -117,4 +117,5 @@ def test_to_split_view(self): assert as_split_view.killed == self.raw['killed'] assert as_split_view.traffic_type == self.raw['trafficTypeName'] assert set(as_split_view.treatments) == set(['on', 'off']) + assert as_split_view.default_treatment == self.raw['defaultTreatment'] assert sorted(as_split_view.sets) == sorted(list(self.raw['sets'])) From c6c0f11239b13c520556300b89398a1eddad5c86 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Tue, 17 Oct 2023 09:11:47 -0700 Subject: [PATCH 3/3] polishing --- splitio/client/client.py | 12 ++++++------ tests/client/test_client.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/splitio/client/client.py b/splitio/client/client.py index 45c16677..35030595 100644 --- a/splitio/client/client.py +++ b/splitio/client/client.py @@ -59,9 +59,9 @@ def destroyed(self): """Return whether the factory holding this client has been destroyed.""" return self._factory.destroyed - def _evaluate_if_ready(self, matching_key, bucketing_key, feature, attributes=None): + def _evaluate_if_ready(self, matching_key, bucketing_key, feature, method, attributes=None): if not self.ready: - _LOGGER.warning("The SDK is not ready, results may be incorrect for feature flag %s. Make sure to wait for SDK readiness before using this method", feature) + _LOGGER.warning("%s: The SDK is not ready, results may be incorrect for feature flag %s. Make sure to wait for SDK readiness before using this method", method, feature) self._telemetry_init_producer.record_not_ready_usage() return { 'treatment': CONTROL, @@ -103,7 +103,7 @@ def _make_evaluation(self, key, feature_flag, attributes, method_name, metric_na or not input_validator.validate_attributes(attributes, method_name): return CONTROL, None - result = self._evaluate_if_ready(matching_key, bucketing_key, feature_flag, attributes) + result = self._evaluate_if_ready(matching_key, bucketing_key, feature_flag, method_name, attributes) impression = self._build_impression( matching_key, @@ -168,7 +168,7 @@ def _make_evaluations(self, key, feature_flags, attributes, method_name, metric_ try: evaluations = self._evaluate_features_if_ready(matching_key, bucketing_key, - list(feature_flags), attributes) + list(feature_flags), method_name, attributes) for feature_flag in feature_flags: try: @@ -213,9 +213,9 @@ def _make_evaluations(self, key, feature_flags, attributes, method_name, metric_ _LOGGER.debug('Error: ', exc_info=True) return input_validator.generate_control_treatments(list(feature_flags), method_name) - def _evaluate_features_if_ready(self, matching_key, bucketing_key, feature_flags, attributes=None): + def _evaluate_features_if_ready(self, matching_key, bucketing_key, feature_flags, method, attributes=None): if not self.ready: - _LOGGER.warning("The SDK is not ready, results may be incorrect for feature flags %s. Make sure to wait for SDK readiness before using this method", ', '.join([feature for feature in feature_flags])) + _LOGGER.warning("%s: The SDK is not ready, results may be incorrect for feature flags %s. Make sure to wait for SDK readiness before using this method", method, ', '.join([feature for feature in feature_flags])) self._telemetry_init_producer.record_not_ready_usage() return { feature_flag: { diff --git a/tests/client/test_client.py b/tests/client/test_client.py index 8287cc2a..6341142c 100644 --- a/tests/client/test_client.py +++ b/tests/client/test_client.py @@ -846,7 +846,7 @@ def test_telemetry_not_ready(self, mocker): ) client = Client(factory, mocker.Mock()) client.ready = False - client._evaluate_if_ready('matching_key','matching_key', 'feature') + client._evaluate_if_ready('matching_key','matching_key', 'method', 'feature') assert(telemetry_storage._tel_config._not_ready == 1) client.track('key', 'tt', 'ev') assert(telemetry_storage._tel_config._not_ready == 2)