From dea481cd07bca72488cbbdacd1ca171d88917a67 Mon Sep 17 00:00:00 2001 From: Matjaz Pirnovar Date: Fri, 19 Aug 2022 13:44:22 -0700 Subject: [PATCH 1/8] feat: add odp_segment_manager --- optimizely/helpers/enums.py | 6 +++ optimizely/odp/odp_config.py | 96 ++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 optimizely/odp/odp_config.py diff --git a/optimizely/helpers/enums.py b/optimizely/helpers/enums.py index ab63d1e3..5ea32dfc 100644 --- a/optimizely/helpers/enums.py +++ b/optimizely/helpers/enums.py @@ -205,3 +205,9 @@ class OdpRestApiConfig: class OdpGraphQLApiConfig: """ODP GraphQL API configs.""" REQUEST_TIMEOUT: Final = 10 + + +class OptimizelySegmentOption: + """Options for the OdpSegmentManager.""" + IGNORE_CACHE = None + RESET_CACHE = None diff --git a/optimizely/odp/odp_config.py b/optimizely/odp/odp_config.py new file mode 100644 index 00000000..aec19916 --- /dev/null +++ b/optimizely/odp/odp_config.py @@ -0,0 +1,96 @@ +# Copyright 2022, Optimizely +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from typing import Optional +from threading import Lock + + +class OdpConfig: + """ + Contains configuration used for ODP integration. + + Args: + api_host: The host URL for the ODP audience segments API (optional). + api_key: The public API key for the ODP account from which the audience segments will be fetched (optional). + segments_to_check: A list of all ODP segments used in the current datafile + (associated with api_host/api_key). + """ + def __init__( + self, + api_key: Optional[str] = None, + api_host: Optional[str] = None, + segments_to_check: Optional[list[str]] = None + ) -> None: + self.api_key = api_key + self.api_host = api_host + self.segments_to_check = segments_to_check or [] + self.lock = Lock() + + def update(self, api_key: Optional[str], api_host: Optional[str], segments_to_check: list[str]) -> bool: + """ + Override the ODP configuration. + + Args: + api_host: The host URL for the ODP audience segments API (optional). + api_key: The public API key for the ODP account from which the audience segments will be fetched (optional). + segments_to_check: A list of all ODP segments used in the current datafile + (associated with api_host/api_key). + + Returns: + True if the provided values were different than the existing values. + """ + updated = False + with self.lock: + if self.api_key != api_key or self.api_host != api_host or self.segments_to_check != segments_to_check: + self.api_key = api_key + self.api_host = api_host + self.segments_to_check = segments_to_check + updated = True + + return updated + + def get_api_host(self) -> Optional[str]: + with self.lock: + return self.api_host + + def set_api_host(self, api_host: Optional[str]) -> None: + with self.lock: + self.api_host = api_host + + def get_api_key(self) -> Optional[str]: + with self.lock: + return self.api_key + + def set_api_key(self, api_key: Optional[str]) -> None: + with self.lock: + self.api_key = api_key + + def get_segments_to_check(self) -> Optional[list[str]]: + with self.lock: + return self.segments_to_check.copy() + + def set_segments_to_check(self, segments_to_check: list[str]) -> None: + """ + Replace qualified segments with provided list of segments. + Args: + segments_to_check: A list of segment names. + """ + with self.lock: + self.segments_to_check = segments_to_check.copy() + + def odp_integrated(self) -> bool: + """Returns True if ODP is integrated.""" + with self.lock: + return self.api_key is not None and self.api_host is not None From 80659967e69f6980bc958013d1f137cefff28075 Mon Sep 17 00:00:00 2001 From: Matjaz Pirnovar Date: Tue, 23 Aug 2022 00:46:02 -0700 Subject: [PATCH 2/8] feat: add segment manager --- optimizely/helpers/enums.py | 4 +- optimizely/odp/odp_config.py | 41 ++--- optimizely/odp/odp_event.py | 12 +- optimizely/odp/odp_segment_manager.py | 82 ++++++++++ tests/test_odp_config.py | 41 +++++ tests/test_odp_segment_manager.py | 210 ++++++++++++++++++++++++++ 6 files changed, 353 insertions(+), 37 deletions(-) create mode 100644 optimizely/odp/odp_segment_manager.py create mode 100644 tests/test_odp_config.py create mode 100644 tests/test_odp_segment_manager.py diff --git a/optimizely/helpers/enums.py b/optimizely/helpers/enums.py index 5ea32dfc..abe1d530 100644 --- a/optimizely/helpers/enums.py +++ b/optimizely/helpers/enums.py @@ -209,5 +209,5 @@ class OdpGraphQLApiConfig: class OptimizelySegmentOption: """Options for the OdpSegmentManager.""" - IGNORE_CACHE = None - RESET_CACHE = None + IGNORE_CACHE = 'IGNORE_CACHE' + RESET_CACHE = 'RESET_CACHE' diff --git a/optimizely/odp/odp_config.py b/optimizely/odp/odp_config.py index aec19916..4af29a53 100644 --- a/optimizely/odp/odp_config.py +++ b/optimizely/odp/odp_config.py @@ -33,9 +33,9 @@ def __init__( api_host: Optional[str] = None, segments_to_check: Optional[list[str]] = None ) -> None: - self.api_key = api_key - self.api_host = api_host - self.segments_to_check = segments_to_check or [] + self._api_key = api_key + self._api_host = api_host + self._segments_to_check = segments_to_check or [] self.lock = Lock() def update(self, api_key: Optional[str], api_host: Optional[str], segments_to_check: list[str]) -> bool: @@ -53,44 +53,27 @@ def update(self, api_key: Optional[str], api_host: Optional[str], segments_to_ch """ updated = False with self.lock: - if self.api_key != api_key or self.api_host != api_host or self.segments_to_check != segments_to_check: - self.api_key = api_key - self.api_host = api_host - self.segments_to_check = segments_to_check + if self._api_key != api_key or self._api_host != api_host or self._segments_to_check != segments_to_check: + self._api_key = api_key + self._api_host = api_host + self._segments_to_check = segments_to_check updated = True return updated def get_api_host(self) -> Optional[str]: with self.lock: - return self.api_host - - def set_api_host(self, api_host: Optional[str]) -> None: - with self.lock: - self.api_host = api_host + return self._api_host def get_api_key(self) -> Optional[str]: with self.lock: - return self.api_key + return self._api_key - def set_api_key(self, api_key: Optional[str]) -> None: - with self.lock: - self.api_key = api_key - - def get_segments_to_check(self) -> Optional[list[str]]: - with self.lock: - return self.segments_to_check.copy() - - def set_segments_to_check(self, segments_to_check: list[str]) -> None: - """ - Replace qualified segments with provided list of segments. - Args: - segments_to_check: A list of segment names. - """ + def get_segments_to_check(self) -> list[str]: with self.lock: - self.segments_to_check = segments_to_check.copy() + return self._segments_to_check.copy() def odp_integrated(self) -> bool: """Returns True if ODP is integrated.""" with self.lock: - return self.api_key is not None and self.api_host is not None + return self._api_key is not None and self._api_host is not None \ No newline at end of file diff --git a/optimizely/odp/odp_event.py b/optimizely/odp/odp_event.py index 23015db5..9a38bc03 100644 --- a/optimizely/odp/odp_event.py +++ b/optimizely/odp/odp_event.py @@ -13,15 +13,15 @@ from __future__ import annotations -from typing import Any, Dict +from typing import Any class OdpEvent: """ Representation of an odp event which can be sent to the Optimizely odp platform. """ def __init__(self, type: str, action: str, - identifiers: Dict[str, str], data: Dict[str, Any]) -> None: - self.type = type, - self.action = action, - self.identifiers = identifiers, - self.data = data + identifiers: dict[str, str], data: dict[str, Any]) -> None: + self.type = type + self.action = action + self.identifiers = identifiers + self.data = data \ No newline at end of file diff --git a/optimizely/odp/odp_segment_manager.py b/optimizely/odp/odp_segment_manager.py new file mode 100644 index 00000000..a6e46d70 --- /dev/null +++ b/optimizely/odp/odp_segment_manager.py @@ -0,0 +1,82 @@ +# Copyright 2022, Optimizely +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from typing import List, Optional + +from optimizely import logger as optimizely_logger +from optimizely.helpers.enums import Errors +from optimizely.helpers.enums import OptimizelySegmentOption +from optimizely.odp.lru_cache import LRUCache +from optimizely.odp.odp_config import OdpConfig +from optimizely.odp.zaius_graphql_api_manager import ZaiusGraphQLApiManager + + +class OdpSegmentManager: + """Schedules connections to ODP for audience segmentation and caches the results.""" + + IGNORE_CACHE = OptimizelySegmentOption.IGNORE_CACHE + RESET_CACHE = OptimizelySegmentOption.RESET_CACHE + + def __init__(self, odp_config: Optional[OdpConfig], segments_cache: Optional[LRUCache[str, List[str]](1000, 1000)], + zaius_manager: Optional[ZaiusGraphQLApiManager], + logger: Optional[optimizely_logger.Logger] = None) -> None: + + self.odp_config = odp_config + self.segments_cache = segments_cache + self.zaius_manager = zaius_manager + self.logger = logger or optimizely_logger.NoOpLogger() + + def fetch_qualified_segments(self, user_key: str, user_value: str, options: list[OptimizelySegmentOption]): + if not self.odp_config.odp_integrated(): + self.logger.error(Errors.FETCH_SEGMENTS_FAILED.format('apiKey/apiHost not defined')) + return None + + odp_api_key: Optional[str] = self.odp_config.get_api_key() + odp_api_host: Optional[str] = self.odp_config.get_api_host() + odp_segments_to_check: Optional[list[str]] = self.odp_config.get_segments_to_check() + + if not odp_segments_to_check and not len(odp_segments_to_check): + self.logger.debug('No segments are used in the project. Returning empty list.') + return [] + + cache_key = self.make_cache_key(user_key, user_value) + + ignore_cache = self.IGNORE_CACHE if self.IGNORE_CACHE in options else None + reset_cache = self.RESET_CACHE if self.RESET_CACHE in options else None + + if reset_cache: + self._reset() + + if not ignore_cache and not reset_cache: + segments = self.segments_cache.lookup(cache_key) + if segments: + self.logger.debug('ODP cache hit. Returning segments from cache.') + return segments + + self.logger.debug('ODP cache miss. Making a call to ODP server.') + + segments = self.zaius_manager.fetch_segments(odp_api_key, odp_api_host, user_key, user_value, + odp_segments_to_check) + + if segments and not ignore_cache: + self.segments_cache.save(cache_key, segments) + + return segments + + def _reset(self): + self.segments_cache.reset() + + def make_cache_key(self, user_key: str, user_value: str) -> str: + return user_key + '-$-' + user_value diff --git a/tests/test_odp_config.py b/tests/test_odp_config.py new file mode 100644 index 00000000..af11f3ff --- /dev/null +++ b/tests/test_odp_config.py @@ -0,0 +1,41 @@ +# Copyright 2022, Optimizely +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +from tests import base +from optimizely.odp.odp_config import OdpConfig + + +class OdpConfigTest(base.BaseTest): + api_host = 'test-host' + api_key = 'test-key' + segments_to_check = ['test-segment'] + + def test_init_config(self): + config = OdpConfig(self.api_key, self.api_host, self.segments_to_check) + + self.assertEqual(config.get_api_key(), self.api_key) + self.assertEqual(config.get_api_host(), self.api_host) + self.assertEqual(config.get_segments_to_check(), self.segments_to_check) + + def test_update_config(self): + config = OdpConfig() + updated = config.update(self.api_key, self.api_host, self.segments_to_check) + + self.assertStrictTrue(updated) + self.assertEqual(config.get_api_key(), self.api_key) + self.assertEqual(config.get_api_host(), self.api_host) + self.assertEqual(config.get_segments_to_check(), self.segments_to_check) + + updated = config.update(self.api_key, self.api_host, self.segments_to_check) + self.assertStrictFalse(updated) \ No newline at end of file diff --git a/tests/test_odp_segment_manager.py b/tests/test_odp_segment_manager.py new file mode 100644 index 00000000..68db8b40 --- /dev/null +++ b/tests/test_odp_segment_manager.py @@ -0,0 +1,210 @@ +# Copyright 2022, Optimizely +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from unittest import mock + +from requests import exceptions as request_exception + +from optimizely.helpers.enums import OptimizelySegmentOption +from optimizely.odp.lru_cache import LRUCache +from optimizely.odp.odp_config import OdpConfig +from optimizely.odp.odp_segment_manager import OdpSegmentManager +from optimizely.odp.zaius_graphql_api_manager import ZaiusGraphQLApiManager +from tests import base + + +class OdpSegmentManagerTest(base.BaseTest): + api_host = 'host' + api_key = 'valid' + user_key = 'fs_user_id' + user_value = 'test-user-value' + + def test_empty_array_with_no_segments_to_check(self): + with mock.patch('requests.post') as mock_request_post, \ + mock.patch('optimizely.logger') as mock_logger: + mock_request_post.return_value = self.fake_server_response(status_code=200, + content=self.good_response_data) + + odp_config = OdpConfig(self.api_key, self.api_host, []) + segments_cache = LRUCache(1000, 1000) + api = ZaiusGraphQLApiManager() + + segment_manager = OdpSegmentManager(odp_config, segments_cache, api, mock_logger) + segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, []) + + self.assertEqual(segments, []) + mock_logger.debug.assert_called_once_with('No segments are used in the project. Returning empty list.') + mock_logger.error.assert_not_called() + + def test_fetch_segments_success_cache_miss(self): + """ + we are fetching user key/value 'fs_user_id'/'test-user-value' + which is different from what we have passed to cache (fs_user_id-$-123/['d']) + ---> hence we trigger a cache miss + """ + with mock.patch('requests.post') as mock_request_post, \ + mock.patch('optimizely.logger') as mock_logger: + mock_request_post.return_value = self.fake_server_response(status_code=200, + content=self.good_response_data) + + odp_config = OdpConfig(self.api_key, self.api_host, ["a", "b", "c"]) + segments_cache = LRUCache(1000, 1000) + api = ZaiusGraphQLApiManager() + + segment_manager = OdpSegmentManager(odp_config, segments_cache, api, mock_logger) + + cache_key = segment_manager.make_cache_key(self.user_key, '123') + segment_manager.segments_cache.save(cache_key, ["d"]) + + segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, []) + + self.assertEqual(segments, ["a", "b"]) + actual_cache_key = segment_manager.make_cache_key(self.user_key, self.user_value) + self.assertEqual(segment_manager.segments_cache.lookup(actual_cache_key), ["a", "b"]) + mock_logger.debug.assert_called_once_with('ODP cache miss. Making a call to ODP server.') + mock_logger.error.assert_not_called() + + def test_fetch_segments_success_cache_hit(self): + with mock.patch('optimizely.logger') as mock_logger: + odp_config = OdpConfig() + odp_config.update(self.api_key, self.api_host, ['c']) + segments_cache = LRUCache(1000, 1000) + segment_manager = OdpSegmentManager(odp_config, segments_cache, None, mock_logger) + + cache_key = segment_manager.make_cache_key(self.user_key, self.user_value) + segment_manager.segments_cache.save(cache_key, ['c']) + + segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, []) + + self.assertEqual(segments, ['c']) + mock_logger.debug.assert_called_once_with('ODP cache hit. Returning segments from cache.') + mock_logger.error.assert_not_called() + + def test_fetch_segments_missing_api_host_api_key(self): + with mock.patch('optimizely.logger') as mock_logger: + segment_manager = OdpSegmentManager(OdpConfig(), LRUCache(1000, 1000), None, mock_logger) + segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, []) + + self.assertEqual(segments, None) + mock_logger.error.assert_called_once_with('Audience segments fetch failed (apiKey/apiHost not defined).') + + def test_fetch_segments_network_error(self): + """ + Trigger connection error with mock side_effect. Note that Python's requests don't + have a status code for connection error, that's why we need to trigger the exception + instead of returning a fake server response with status code 500. + The error log should come form the GraphQL API manager, not from ODP Segment Manager. + The active mock logger should be placed as parameter in ZaiusGraphQLApiManager object. + """ + with mock.patch('requests.post', + side_effect=request_exception.ConnectionError('Connection error')), \ + mock.patch('optimizely.logger') as mock_logger: + odp_config = OdpConfig(self.api_key, self.api_host, ["a", "b", "c"]) + segments_cache = LRUCache(1000, 1000) + api = ZaiusGraphQLApiManager(mock_logger) + + segment_manager = OdpSegmentManager(odp_config, segments_cache, api, None) + segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, []) + + self.assertEqual(segments, None) + mock_logger.error.assert_called_once_with('Audience segments fetch failed (network error).') + + def test_options_ignore_cache(self): + with mock.patch('requests.post') as mock_request_post, \ + mock.patch('optimizely.logger') as mock_logger: + mock_request_post.return_value = self.fake_server_response(status_code=200, + content=self.good_response_data) + + odp_config = OdpConfig(self.api_key, self.api_host, ["a", "b", "c"]) + segments_cache = LRUCache(1000, 1000) + api = ZaiusGraphQLApiManager() + + segment_manager = OdpSegmentManager(odp_config, segments_cache, api, mock_logger) + + cache_key = segment_manager.make_cache_key(self.user_key, self.user_value) + segment_manager.segments_cache.save(cache_key, ['d']) + + segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, + [OptimizelySegmentOption.IGNORE_CACHE]) + + self.assertEqual(segments, ["a", "b"]) + self.assertEqual(segment_manager.segments_cache.lookup(cache_key), ['d']) + mock_logger.debug.assert_called_once_with('ODP cache miss. Making a call to ODP server.') + mock_logger.error.assert_not_called() + + def test_options_reset_cache(self): + with mock.patch('requests.post') as mock_request_post, \ + mock.patch('optimizely.logger') as mock_logger: + mock_request_post.return_value = self.fake_server_response(status_code=200, + content=self.good_response_data) + + odp_config = OdpConfig(self.api_key, self.api_host, ["a", "b", "c"]) + segments_cache = LRUCache(1000, 1000) + api = ZaiusGraphQLApiManager() + + segment_manager = OdpSegmentManager(odp_config, segments_cache, api, mock_logger) + + cache_key = segment_manager.make_cache_key(self.user_key, self.user_value) + segment_manager.segments_cache.save(cache_key, ['d']) + segment_manager.segments_cache.save('123', ['c', 'd']) + + segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, + [OptimizelySegmentOption.RESET_CACHE]) + + self.assertEqual(segments, ["a", "b"]) + self.assertEqual(segment_manager.segments_cache.lookup(cache_key), ['a', 'b']) + self.assertTrue(len(segment_manager.segments_cache.map) == 1) + mock_logger.debug.assert_called_once_with('ODP cache miss. Making a call to ODP server.') + mock_logger.error.assert_not_called() + + def test_make_correct_cache_key(self): + segment_manager = OdpSegmentManager(None, None, None, None) + cache_key = segment_manager.make_cache_key(self.user_key, self.user_value) + self.assertEqual(cache_key, 'fs_user_id-$-test-user-value') + + # test json response + good_response_data = """ + { + "data": { + "customer": { + "audiences": { + "edges": [ + { + "node": { + "name": "a", + "state": "qualified", + "description": "qualifed sample 1" + } + }, + { + "node": { + "name": "b", + "state": "qualified", + "description": "qualifed sample 2" + } + }, + { + "node": { + "name": "c", + "state": "not_qualified", + "description": "not-qualified sample" + } + } + ] + } + } + } + } + """ From 72057fbb4a86250a02e1715720c6651e6655df9e Mon Sep 17 00:00:00 2001 From: Matjaz Pirnovar Date: Tue, 23 Aug 2022 18:22:49 -0700 Subject: [PATCH 3/8] fix pr comments --- optimizely/helpers/enums.py | 5 ---- optimizely/odp/odp_config.py | 2 +- optimizely/odp/odp_options.py | 25 ++++++++++++++++ optimizely/odp/odp_segment_manager.py | 43 ++++++++++++++++----------- tests/test_odp_segment_manager.py | 2 +- 5 files changed, 52 insertions(+), 25 deletions(-) create mode 100644 optimizely/odp/odp_options.py diff --git a/optimizely/helpers/enums.py b/optimizely/helpers/enums.py index abe1d530..e3d66c34 100644 --- a/optimizely/helpers/enums.py +++ b/optimizely/helpers/enums.py @@ -206,8 +206,3 @@ class OdpGraphQLApiConfig: """ODP GraphQL API configs.""" REQUEST_TIMEOUT: Final = 10 - -class OptimizelySegmentOption: - """Options for the OdpSegmentManager.""" - IGNORE_CACHE = 'IGNORE_CACHE' - RESET_CACHE = 'RESET_CACHE' diff --git a/optimizely/odp/odp_config.py b/optimizely/odp/odp_config.py index 4af29a53..64809626 100644 --- a/optimizely/odp/odp_config.py +++ b/optimizely/odp/odp_config.py @@ -76,4 +76,4 @@ def get_segments_to_check(self) -> list[str]: def odp_integrated(self) -> bool: """Returns True if ODP is integrated.""" with self.lock: - return self._api_key is not None and self._api_host is not None \ No newline at end of file + return self._api_key is not None and self._api_host is not None diff --git a/optimizely/odp/odp_options.py b/optimizely/odp/odp_options.py new file mode 100644 index 00000000..cdfe634d --- /dev/null +++ b/optimizely/odp/odp_options.py @@ -0,0 +1,25 @@ +# Copyright 2022, Optimizely +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from sys import version_info + +if version_info < (3, 8): + from typing_extensions import Final +else: + from typing import Final # type: ignore + + +class OptimizelySegmentOption: + """Options for the OdpSegmentManager.""" + IGNORE_CACHE: Final = 'IGNORE_CACHE' + RESET_CACHE: Final = 'RESET_CACHE' diff --git a/optimizely/odp/odp_segment_manager.py b/optimizely/odp/odp_segment_manager.py index a6e46d70..3c8abe31 100644 --- a/optimizely/odp/odp_segment_manager.py +++ b/optimizely/odp/odp_segment_manager.py @@ -13,12 +13,12 @@ from __future__ import annotations -from typing import List, Optional +from typing import Optional from optimizely import logger as optimizely_logger from optimizely.helpers.enums import Errors -from optimizely.helpers.enums import OptimizelySegmentOption -from optimizely.odp.lru_cache import LRUCache +from optimizely.odp.odp_options import OptimizelySegmentOption +from optimizely.odp.lru_cache import OptimizelySegmentsCache from optimizely.odp.odp_config import OdpConfig from optimizely.odp.zaius_graphql_api_manager import ZaiusGraphQLApiManager @@ -26,11 +26,8 @@ class OdpSegmentManager: """Schedules connections to ODP for audience segmentation and caches the results.""" - IGNORE_CACHE = OptimizelySegmentOption.IGNORE_CACHE - RESET_CACHE = OptimizelySegmentOption.RESET_CACHE - - def __init__(self, odp_config: Optional[OdpConfig], segments_cache: Optional[LRUCache[str, List[str]](1000, 1000)], - zaius_manager: Optional[ZaiusGraphQLApiManager], + def __init__(self, odp_config: OdpConfig, segments_cache: OptimizelySegmentsCache, + zaius_manager: ZaiusGraphQLApiManager, logger: Optional[optimizely_logger.Logger] = None) -> None: self.odp_config = odp_config @@ -38,23 +35,33 @@ def __init__(self, odp_config: Optional[OdpConfig], segments_cache: Optional[LRU self.zaius_manager = zaius_manager self.logger = logger or optimizely_logger.NoOpLogger() - def fetch_qualified_segments(self, user_key: str, user_value: str, options: list[OptimizelySegmentOption]): - if not self.odp_config.odp_integrated(): + def fetch_qualified_segments(self, user_key: str, user_value: str, options: list[str]) -> \ + Optional[list[str]]: + """ + Args: + user_key: The key for identifying the id type. + user_value: The id itself. + options: An array of OptimizelySegmentOptions used to ignore and/or reset the cache. + + Returns: + Qualified segments for the user from the cache or the ODP server if not in the cache. + """ + odp_api_key = self.odp_config.get_api_key() + odp_api_host = self.odp_config.get_api_host() + odp_segments_to_check = self.odp_config.get_segments_to_check() + + if not (odp_api_key and odp_api_host): self.logger.error(Errors.FETCH_SEGMENTS_FAILED.format('apiKey/apiHost not defined')) return None - odp_api_key: Optional[str] = self.odp_config.get_api_key() - odp_api_host: Optional[str] = self.odp_config.get_api_host() - odp_segments_to_check: Optional[list[str]] = self.odp_config.get_segments_to_check() - - if not odp_segments_to_check and not len(odp_segments_to_check): + if not odp_segments_to_check: self.logger.debug('No segments are used in the project. Returning empty list.') return [] cache_key = self.make_cache_key(user_key, user_value) - ignore_cache = self.IGNORE_CACHE if self.IGNORE_CACHE in options else None - reset_cache = self.RESET_CACHE if self.RESET_CACHE in options else None + ignore_cache = OptimizelySegmentOption.IGNORE_CACHE in options + reset_cache = OptimizelySegmentOption.RESET_CACHE in options if reset_cache: self._reset() @@ -75,7 +82,7 @@ def fetch_qualified_segments(self, user_key: str, user_value: str, options: list return segments - def _reset(self): + def _reset(self) -> None: self.segments_cache.reset() def make_cache_key(self, user_key: str, user_value: str) -> str: diff --git a/tests/test_odp_segment_manager.py b/tests/test_odp_segment_manager.py index 68db8b40..cb325de4 100644 --- a/tests/test_odp_segment_manager.py +++ b/tests/test_odp_segment_manager.py @@ -17,7 +17,7 @@ from requests import exceptions as request_exception -from optimizely.helpers.enums import OptimizelySegmentOption +from optimizely.odp.odp_options import OptimizelySegmentOption from optimizely.odp.lru_cache import LRUCache from optimizely.odp.odp_config import OdpConfig from optimizely.odp.odp_segment_manager import OdpSegmentManager From 1b155819ceaaf6fbb70e7392a7a3922edf763c1a Mon Sep 17 00:00:00 2001 From: Matjaz Pirnovar Date: Tue, 23 Aug 2022 23:29:15 -0700 Subject: [PATCH 4/8] fix tests --- optimizely/helpers/enums.py | 1 - tests/test_odp_segment_manager.py | 13 +++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/optimizely/helpers/enums.py b/optimizely/helpers/enums.py index e3d66c34..ab63d1e3 100644 --- a/optimizely/helpers/enums.py +++ b/optimizely/helpers/enums.py @@ -205,4 +205,3 @@ class OdpRestApiConfig: class OdpGraphQLApiConfig: """ODP GraphQL API configs.""" REQUEST_TIMEOUT: Final = 10 - diff --git a/tests/test_odp_segment_manager.py b/tests/test_odp_segment_manager.py index cb325de4..370d6523 100644 --- a/tests/test_odp_segment_manager.py +++ b/tests/test_odp_segment_manager.py @@ -17,9 +17,9 @@ from requests import exceptions as request_exception -from optimizely.odp.odp_options import OptimizelySegmentOption from optimizely.odp.lru_cache import LRUCache from optimizely.odp.odp_config import OdpConfig +from optimizely.odp.odp_options import OptimizelySegmentOption from optimizely.odp.odp_segment_manager import OdpSegmentManager from optimizely.odp.zaius_graphql_api_manager import ZaiusGraphQLApiManager from tests import base @@ -31,9 +31,10 @@ class OdpSegmentManagerTest(base.BaseTest): user_key = 'fs_user_id' user_value = 'test-user-value' - def test_empty_array_with_no_segments_to_check(self): + def test_empty_list_with_no_segments_to_check(self): with mock.patch('requests.post') as mock_request_post, \ - mock.patch('optimizely.logger') as mock_logger: + mock.patch('optimizely.logger') as mock_logger, mock.patch( + 'optimizely.odp.odp_segment_manager.ZaiusGraphQLApiManager.fetch_segments') as mock_fetch_segments: mock_request_post.return_value = self.fake_server_response(status_code=200, content=self.good_response_data) @@ -47,6 +48,7 @@ def test_empty_array_with_no_segments_to_check(self): self.assertEqual(segments, []) mock_logger.debug.assert_called_once_with('No segments are used in the project. Returning empty list.') mock_logger.error.assert_not_called() + mock_fetch_segments.assert_not_called() def test_fetch_segments_success_cache_miss(self): """ @@ -77,10 +79,12 @@ def test_fetch_segments_success_cache_miss(self): mock_logger.error.assert_not_called() def test_fetch_segments_success_cache_hit(self): - with mock.patch('optimizely.logger') as mock_logger: + with mock.patch('optimizely.logger') as mock_logger, mock.patch( + 'optimizely.odp.odp_segment_manager.ZaiusGraphQLApiManager.fetch_segments') as mock_fetch_segments: odp_config = OdpConfig() odp_config.update(self.api_key, self.api_host, ['c']) segments_cache = LRUCache(1000, 1000) + segment_manager = OdpSegmentManager(odp_config, segments_cache, None, mock_logger) cache_key = segment_manager.make_cache_key(self.user_key, self.user_value) @@ -91,6 +95,7 @@ def test_fetch_segments_success_cache_hit(self): self.assertEqual(segments, ['c']) mock_logger.debug.assert_called_once_with('ODP cache hit. Returning segments from cache.') mock_logger.error.assert_not_called() + mock_fetch_segments.assert_not_called() def test_fetch_segments_missing_api_host_api_key(self): with mock.patch('optimizely.logger') as mock_logger: From 61802237f5b43201331379656f6f814770140269 Mon Sep 17 00:00:00 2001 From: Matjaz Pirnovar Date: Wed, 24 Aug 2022 23:28:54 -0700 Subject: [PATCH 5/8] refacored tests --- optimizely/odp/odp_segment_manager.py | 2 +- tests/test_odp_segment_manager.py | 113 ++++++++++++-------------- 2 files changed, 54 insertions(+), 61 deletions(-) diff --git a/optimizely/odp/odp_segment_manager.py b/optimizely/odp/odp_segment_manager.py index 3c8abe31..f7b506fc 100644 --- a/optimizely/odp/odp_segment_manager.py +++ b/optimizely/odp/odp_segment_manager.py @@ -86,4 +86,4 @@ def _reset(self) -> None: self.segments_cache.reset() def make_cache_key(self, user_key: str, user_value: str) -> str: - return user_key + '-$-' + user_value + return f'{user_key}-$-{user_value}' diff --git a/tests/test_odp_segment_manager.py b/tests/test_odp_segment_manager.py index 370d6523..bb98a758 100644 --- a/tests/test_odp_segment_manager.py +++ b/tests/test_odp_segment_manager.py @@ -32,17 +32,13 @@ class OdpSegmentManagerTest(base.BaseTest): user_value = 'test-user-value' def test_empty_list_with_no_segments_to_check(self): - with mock.patch('requests.post') as mock_request_post, \ - mock.patch('optimizely.logger') as mock_logger, mock.patch( - 'optimizely.odp.odp_segment_manager.ZaiusGraphQLApiManager.fetch_segments') as mock_fetch_segments: - mock_request_post.return_value = self.fake_server_response(status_code=200, - content=self.good_response_data) - - odp_config = OdpConfig(self.api_key, self.api_host, []) - segments_cache = LRUCache(1000, 1000) - api = ZaiusGraphQLApiManager() + odp_config = OdpConfig(self.api_key, self.api_host, []) + mock_logger = mock.MagicMock() + segments_cache = LRUCache(1000, 1000) + api = ZaiusGraphQLApiManager() + segment_manager = OdpSegmentManager(odp_config, segments_cache, api, mock_logger) - segment_manager = OdpSegmentManager(odp_config, segments_cache, api, mock_logger) + with mock.patch.object(api, 'fetch_segments') as mock_fetch_segments: segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, []) self.assertEqual(segments, []) @@ -56,19 +52,18 @@ def test_fetch_segments_success_cache_miss(self): which is different from what we have passed to cache (fs_user_id-$-123/['d']) ---> hence we trigger a cache miss """ - with mock.patch('requests.post') as mock_request_post, \ - mock.patch('optimizely.logger') as mock_logger: - mock_request_post.return_value = self.fake_server_response(status_code=200, - content=self.good_response_data) - - odp_config = OdpConfig(self.api_key, self.api_host, ["a", "b", "c"]) - segments_cache = LRUCache(1000, 1000) - api = ZaiusGraphQLApiManager() + odp_config = OdpConfig(self.api_key, self.api_host, ["a", "b", "c"]) + mock_logger = mock.MagicMock() + segments_cache = LRUCache(1000, 1000) + api = ZaiusGraphQLApiManager() - segment_manager = OdpSegmentManager(odp_config, segments_cache, api, mock_logger) + segment_manager = OdpSegmentManager(odp_config, segments_cache, api, mock_logger) + cache_key = segment_manager.make_cache_key(self.user_key, '123') + segment_manager.segments_cache.save(cache_key, ["d"]) - cache_key = segment_manager.make_cache_key(self.user_key, '123') - segment_manager.segments_cache.save(cache_key, ["d"]) + with mock.patch('requests.post') as mock_request_post: + mock_request_post.return_value = self.fake_server_response(status_code=200, + content=self.good_response_data) segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, []) @@ -79,17 +74,17 @@ def test_fetch_segments_success_cache_miss(self): mock_logger.error.assert_not_called() def test_fetch_segments_success_cache_hit(self): - with mock.patch('optimizely.logger') as mock_logger, mock.patch( - 'optimizely.odp.odp_segment_manager.ZaiusGraphQLApiManager.fetch_segments') as mock_fetch_segments: - odp_config = OdpConfig() - odp_config.update(self.api_key, self.api_host, ['c']) - segments_cache = LRUCache(1000, 1000) - - segment_manager = OdpSegmentManager(odp_config, segments_cache, None, mock_logger) + odp_config = OdpConfig() + odp_config.update(self.api_key, self.api_host, ['c']) + mock_logger = mock.MagicMock() + api = ZaiusGraphQLApiManager() + segments_cache = LRUCache(1000, 1000) - cache_key = segment_manager.make_cache_key(self.user_key, self.user_value) - segment_manager.segments_cache.save(cache_key, ['c']) + segment_manager = OdpSegmentManager(odp_config, segments_cache, None, mock_logger) + cache_key = segment_manager.make_cache_key(self.user_key, self.user_value) + segment_manager.segments_cache.save(cache_key, ['c']) + with mock.patch.object(api, 'fetch_segments') as mock_fetch_segments: segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, []) self.assertEqual(segments, ['c']) @@ -113,33 +108,32 @@ def test_fetch_segments_network_error(self): The error log should come form the GraphQL API manager, not from ODP Segment Manager. The active mock logger should be placed as parameter in ZaiusGraphQLApiManager object. """ - with mock.patch('requests.post', - side_effect=request_exception.ConnectionError('Connection error')), \ - mock.patch('optimizely.logger') as mock_logger: - odp_config = OdpConfig(self.api_key, self.api_host, ["a", "b", "c"]) - segments_cache = LRUCache(1000, 1000) - api = ZaiusGraphQLApiManager(mock_logger) + odp_config = OdpConfig(self.api_key, self.api_host, ["a", "b", "c"]) + mock_logger = mock.MagicMock() + segments_cache = LRUCache(1000, 1000) + api = ZaiusGraphQLApiManager(mock_logger) + segment_manager = OdpSegmentManager(odp_config, segments_cache, api, None) - segment_manager = OdpSegmentManager(odp_config, segments_cache, api, None) + with mock.patch('requests.post', + side_effect=request_exception.ConnectionError('Connection error')): segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, []) self.assertEqual(segments, None) mock_logger.error.assert_called_once_with('Audience segments fetch failed (network error).') def test_options_ignore_cache(self): - with mock.patch('requests.post') as mock_request_post, \ - mock.patch('optimizely.logger') as mock_logger: - mock_request_post.return_value = self.fake_server_response(status_code=200, - content=self.good_response_data) - - odp_config = OdpConfig(self.api_key, self.api_host, ["a", "b", "c"]) - segments_cache = LRUCache(1000, 1000) - api = ZaiusGraphQLApiManager() + odp_config = OdpConfig(self.api_key, self.api_host, ["a", "b", "c"]) + mock_logger = mock.MagicMock() + segments_cache = LRUCache(1000, 1000) + api = ZaiusGraphQLApiManager() - segment_manager = OdpSegmentManager(odp_config, segments_cache, api, mock_logger) + segment_manager = OdpSegmentManager(odp_config, segments_cache, api, mock_logger) + cache_key = segment_manager.make_cache_key(self.user_key, self.user_value) + segment_manager.segments_cache.save(cache_key, ['d']) - cache_key = segment_manager.make_cache_key(self.user_key, self.user_value) - segment_manager.segments_cache.save(cache_key, ['d']) + with mock.patch('requests.post') as mock_request_post: + mock_request_post.return_value = self.fake_server_response(status_code=200, + content=self.good_response_data) segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, [OptimizelySegmentOption.IGNORE_CACHE]) @@ -150,20 +144,19 @@ def test_options_ignore_cache(self): mock_logger.error.assert_not_called() def test_options_reset_cache(self): - with mock.patch('requests.post') as mock_request_post, \ - mock.patch('optimizely.logger') as mock_logger: - mock_request_post.return_value = self.fake_server_response(status_code=200, - content=self.good_response_data) - - odp_config = OdpConfig(self.api_key, self.api_host, ["a", "b", "c"]) - segments_cache = LRUCache(1000, 1000) - api = ZaiusGraphQLApiManager() + odp_config = OdpConfig(self.api_key, self.api_host, ["a", "b", "c"]) + mock_logger = mock.MagicMock() + segments_cache = LRUCache(1000, 1000) + api = ZaiusGraphQLApiManager() - segment_manager = OdpSegmentManager(odp_config, segments_cache, api, mock_logger) + segment_manager = OdpSegmentManager(odp_config, segments_cache, api, mock_logger) + cache_key = segment_manager.make_cache_key(self.user_key, self.user_value) + segment_manager.segments_cache.save(cache_key, ['d']) + segment_manager.segments_cache.save('123', ['c', 'd']) - cache_key = segment_manager.make_cache_key(self.user_key, self.user_value) - segment_manager.segments_cache.save(cache_key, ['d']) - segment_manager.segments_cache.save('123', ['c', 'd']) + with mock.patch('requests.post') as mock_request_post: + mock_request_post.return_value = self.fake_server_response(status_code=200, + content=self.good_response_data) segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, [OptimizelySegmentOption.RESET_CACHE]) From 92f8792b81c1246c21c81a130b5e359c612b721d Mon Sep 17 00:00:00 2001 From: Matjaz Pirnovar Date: Thu, 25 Aug 2022 18:22:04 -0700 Subject: [PATCH 6/8] fix PR comments --- optimizely/odp/odp_segment_manager.py | 4 ++-- .../{odp_options.py => optimizely_odp_option.py} | 0 tests/test_odp_segment_manager.py | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) rename optimizely/odp/{odp_options.py => optimizely_odp_option.py} (100%) diff --git a/optimizely/odp/odp_segment_manager.py b/optimizely/odp/odp_segment_manager.py index f7b506fc..99e32668 100644 --- a/optimizely/odp/odp_segment_manager.py +++ b/optimizely/odp/odp_segment_manager.py @@ -17,7 +17,7 @@ from optimizely import logger as optimizely_logger from optimizely.helpers.enums import Errors -from optimizely.odp.odp_options import OptimizelySegmentOption +from optimizely.odp.optimizely_odp_option import OptimizelySegmentOption from optimizely.odp.lru_cache import OptimizelySegmentsCache from optimizely.odp.odp_config import OdpConfig from optimizely.odp.zaius_graphql_api_manager import ZaiusGraphQLApiManager @@ -51,7 +51,7 @@ def fetch_qualified_segments(self, user_key: str, user_value: str, options: list odp_segments_to_check = self.odp_config.get_segments_to_check() if not (odp_api_key and odp_api_host): - self.logger.error(Errors.FETCH_SEGMENTS_FAILED.format('apiKey/apiHost not defined')) + self.logger.error(Errors.FETCH_SEGMENTS_FAILED.format('api_key/api_host not defined')) return None if not odp_segments_to_check: diff --git a/optimizely/odp/odp_options.py b/optimizely/odp/optimizely_odp_option.py similarity index 100% rename from optimizely/odp/odp_options.py rename to optimizely/odp/optimizely_odp_option.py diff --git a/tests/test_odp_segment_manager.py b/tests/test_odp_segment_manager.py index bb98a758..07b19d23 100644 --- a/tests/test_odp_segment_manager.py +++ b/tests/test_odp_segment_manager.py @@ -19,7 +19,7 @@ from optimizely.odp.lru_cache import LRUCache from optimizely.odp.odp_config import OdpConfig -from optimizely.odp.odp_options import OptimizelySegmentOption +from optimizely.odp.optimizely_odp_option import OptimizelySegmentOption from optimizely.odp.odp_segment_manager import OdpSegmentManager from optimizely.odp.zaius_graphql_api_manager import ZaiusGraphQLApiManager from tests import base @@ -41,10 +41,10 @@ def test_empty_list_with_no_segments_to_check(self): with mock.patch.object(api, 'fetch_segments') as mock_fetch_segments: segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, []) - self.assertEqual(segments, []) - mock_logger.debug.assert_called_once_with('No segments are used in the project. Returning empty list.') - mock_logger.error.assert_not_called() - mock_fetch_segments.assert_not_called() + self.assertEqual(segments, []) + mock_logger.debug.assert_called_once_with('No segments are used in the project. Returning empty list.') + mock_logger.error.assert_not_called() + mock_fetch_segments.assert_not_called() def test_fetch_segments_success_cache_miss(self): """ @@ -98,7 +98,7 @@ def test_fetch_segments_missing_api_host_api_key(self): segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, []) self.assertEqual(segments, None) - mock_logger.error.assert_called_once_with('Audience segments fetch failed (apiKey/apiHost not defined).') + mock_logger.error.assert_called_once_with('Audience segments fetch failed (api_key/api_host not defined).') def test_fetch_segments_network_error(self): """ @@ -118,8 +118,8 @@ def test_fetch_segments_network_error(self): side_effect=request_exception.ConnectionError('Connection error')): segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, []) - self.assertEqual(segments, None) - mock_logger.error.assert_called_once_with('Audience segments fetch failed (network error).') + self.assertEqual(segments, None) + mock_logger.error.assert_called_once_with('Audience segments fetch failed (network error).') def test_options_ignore_cache(self): odp_config = OdpConfig(self.api_key, self.api_host, ["a", "b", "c"]) From 8cd49a021b9d3d5975ebe1ae168308c93d6a79ea Mon Sep 17 00:00:00 2001 From: Matjaz Pirnovar Date: Fri, 26 Aug 2022 12:03:47 -0700 Subject: [PATCH 7/8] refactor logs in tests for cache miss/ignore --- optimizely/odp/odp_segment_manager.py | 3 ++- tests/test_odp_segment_manager.py | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/optimizely/odp/odp_segment_manager.py b/optimizely/odp/odp_segment_manager.py index 99e32668..aedf3332 100644 --- a/optimizely/odp/odp_segment_manager.py +++ b/optimizely/odp/odp_segment_manager.py @@ -71,8 +71,9 @@ def fetch_qualified_segments(self, user_key: str, user_value: str, options: list if segments: self.logger.debug('ODP cache hit. Returning segments from cache.') return segments + self.logger.debug('ODP cache miss.') - self.logger.debug('ODP cache miss. Making a call to ODP server.') + self.logger.debug('Making a call to ODP server.') segments = self.zaius_manager.fetch_segments(odp_api_key, odp_api_host, user_key, user_value, odp_segments_to_check) diff --git a/tests/test_odp_segment_manager.py b/tests/test_odp_segment_manager.py index 07b19d23..98e9f827 100644 --- a/tests/test_odp_segment_manager.py +++ b/tests/test_odp_segment_manager.py @@ -14,6 +14,7 @@ from __future__ import annotations from unittest import mock +from unittest.mock import call from requests import exceptions as request_exception @@ -70,7 +71,9 @@ def test_fetch_segments_success_cache_miss(self): self.assertEqual(segments, ["a", "b"]) actual_cache_key = segment_manager.make_cache_key(self.user_key, self.user_value) self.assertEqual(segment_manager.segments_cache.lookup(actual_cache_key), ["a", "b"]) - mock_logger.debug.assert_called_once_with('ODP cache miss. Making a call to ODP server.') + + self.assertEqual(mock_logger.debug.call_count, 2) + mock_logger.debug.assert_has_calls([call('ODP cache miss.'), call('Making a call to ODP server.')]) mock_logger.error.assert_not_called() def test_fetch_segments_success_cache_hit(self): @@ -140,7 +143,7 @@ def test_options_ignore_cache(self): self.assertEqual(segments, ["a", "b"]) self.assertEqual(segment_manager.segments_cache.lookup(cache_key), ['d']) - mock_logger.debug.assert_called_once_with('ODP cache miss. Making a call to ODP server.') + mock_logger.debug.assert_called_once_with('Making a call to ODP server.') mock_logger.error.assert_not_called() def test_options_reset_cache(self): @@ -164,7 +167,7 @@ def test_options_reset_cache(self): self.assertEqual(segments, ["a", "b"]) self.assertEqual(segment_manager.segments_cache.lookup(cache_key), ['a', 'b']) self.assertTrue(len(segment_manager.segments_cache.map) == 1) - mock_logger.debug.assert_called_once_with('ODP cache miss. Making a call to ODP server.') + mock_logger.debug.assert_called_once_with('Making a call to ODP server.') mock_logger.error.assert_not_called() def test_make_correct_cache_key(self): From f312b777b25326be0814d6c59cde8e578fda9ffd Mon Sep 17 00:00:00 2001 From: Matjaz Pirnovar Date: Fri, 26 Aug 2022 12:20:13 -0700 Subject: [PATCH 8/8] cleanup --- optimizely/odp/odp_segment_manager.py | 6 +++--- optimizely/odp/optimizely_odp_option.py | 2 +- tests/test_odp_segment_manager.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/optimizely/odp/odp_segment_manager.py b/optimizely/odp/odp_segment_manager.py index aedf3332..33c829a1 100644 --- a/optimizely/odp/odp_segment_manager.py +++ b/optimizely/odp/odp_segment_manager.py @@ -17,7 +17,7 @@ from optimizely import logger as optimizely_logger from optimizely.helpers.enums import Errors -from optimizely.odp.optimizely_odp_option import OptimizelySegmentOption +from optimizely.odp.optimizely_odp_option import OptimizelyOdpOption from optimizely.odp.lru_cache import OptimizelySegmentsCache from optimizely.odp.odp_config import OdpConfig from optimizely.odp.zaius_graphql_api_manager import ZaiusGraphQLApiManager @@ -60,8 +60,8 @@ def fetch_qualified_segments(self, user_key: str, user_value: str, options: list cache_key = self.make_cache_key(user_key, user_value) - ignore_cache = OptimizelySegmentOption.IGNORE_CACHE in options - reset_cache = OptimizelySegmentOption.RESET_CACHE in options + ignore_cache = OptimizelyOdpOption.IGNORE_CACHE in options + reset_cache = OptimizelyOdpOption.RESET_CACHE in options if reset_cache: self._reset() diff --git a/optimizely/odp/optimizely_odp_option.py b/optimizely/odp/optimizely_odp_option.py index cdfe634d..ce6eaf00 100644 --- a/optimizely/odp/optimizely_odp_option.py +++ b/optimizely/odp/optimizely_odp_option.py @@ -19,7 +19,7 @@ from typing import Final # type: ignore -class OptimizelySegmentOption: +class OptimizelyOdpOption: """Options for the OdpSegmentManager.""" IGNORE_CACHE: Final = 'IGNORE_CACHE' RESET_CACHE: Final = 'RESET_CACHE' diff --git a/tests/test_odp_segment_manager.py b/tests/test_odp_segment_manager.py index 98e9f827..1dad6fdd 100644 --- a/tests/test_odp_segment_manager.py +++ b/tests/test_odp_segment_manager.py @@ -20,7 +20,7 @@ from optimizely.odp.lru_cache import LRUCache from optimizely.odp.odp_config import OdpConfig -from optimizely.odp.optimizely_odp_option import OptimizelySegmentOption +from optimizely.odp.optimizely_odp_option import OptimizelyOdpOption from optimizely.odp.odp_segment_manager import OdpSegmentManager from optimizely.odp.zaius_graphql_api_manager import ZaiusGraphQLApiManager from tests import base @@ -139,7 +139,7 @@ def test_options_ignore_cache(self): content=self.good_response_data) segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, - [OptimizelySegmentOption.IGNORE_CACHE]) + [OptimizelyOdpOption.IGNORE_CACHE]) self.assertEqual(segments, ["a", "b"]) self.assertEqual(segment_manager.segments_cache.lookup(cache_key), ['d']) @@ -162,7 +162,7 @@ def test_options_reset_cache(self): content=self.good_response_data) segments = segment_manager.fetch_qualified_segments(self.user_key, self.user_value, - [OptimizelySegmentOption.RESET_CACHE]) + [OptimizelyOdpOption.RESET_CACHE]) self.assertEqual(segments, ["a", "b"]) self.assertEqual(segment_manager.segments_cache.lookup(cache_key), ['a', 'b'])