From ca2e3cb5002325b04add55be6f21e3c18d17702d Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Fri, 16 May 2025 12:42:48 -0700 Subject: [PATCH] updated split api --- splitio/api/splits.py | 19 ++++++++-- tests/api/test_splits_api.py | 73 +++++++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/splitio/api/splits.py b/splitio/api/splits.py index dcbb46f7..619306a1 100644 --- a/splitio/api/splits.py +++ b/splitio/api/splits.py @@ -37,11 +37,20 @@ def __init__(self, client, sdk_key, sdk_metadata, telemetry_runtime_producer): self._spec_version = SPEC_VERSION self._last_proxy_check_timestamp = 0 self.clear_storage = False + self._old_spec_since = None - def _check_last_proxy_check_timestamp(self): + def _check_last_proxy_check_timestamp(self, since): if self._spec_version == _SPEC_1_1 and ((utctime_ms() - self._last_proxy_check_timestamp) >= _PROXY_CHECK_INTERVAL_MILLISECONDS_SS): _LOGGER.info("Switching to new Feature flag spec (%s) and fetching.", SPEC_VERSION); self._spec_version = SPEC_VERSION + self._old_spec_since = since + + def _check_old_spec_since(self, change_number): + if self._spec_version == _SPEC_1_1 and self._old_spec_since is not None: + since = self._old_spec_since + self._old_spec_since = None + return since + return change_number class SplitsAPI(SplitsAPIBase): # pylint: disable=too-few-public-methods @@ -77,7 +86,9 @@ def fetch_splits(self, change_number, rbs_change_number, fetch_options): :rtype: dict """ try: - self._check_last_proxy_check_timestamp() + self._check_last_proxy_check_timestamp(change_number) + change_number = self._check_old_spec_since(change_number) + query, extra_headers = build_fetch(change_number, fetch_options, self._metadata, rbs_change_number) response = self._client.get( 'sdk', @@ -145,7 +156,9 @@ async def fetch_splits(self, change_number, rbs_change_number, fetch_options): :rtype: dict """ try: - self._check_last_proxy_check_timestamp() + self._check_last_proxy_check_timestamp(change_number) + change_number = self._check_old_spec_since(change_number) + query, extra_headers = build_fetch(change_number, fetch_options, self._metadata, rbs_change_number) response = await self._client.get( 'sdk', diff --git a/tests/api/test_splits_api.py b/tests/api/test_splits_api.py index bfb45c16..c9aeee8b 100644 --- a/tests/api/test_splits_api.py +++ b/tests/api/test_splits_api.py @@ -122,6 +122,41 @@ def get(sdk, splitChanges, sdk_key, extra_headers, query): assert self.query[2] == {'s': '1.3', 'since': 123, 'rbSince': -1} assert response == {"ff": {"d": [], "s": 123, "t": 456}, "rbs": {"d": [], "s": 123, "t": -1}} assert split_api.clear_storage + + def test_using_old_spec_since(self, mocker): + """Test using old_spec_since variable.""" + httpclient = mocker.Mock(spec=client.HttpClient) + self.counter = 0 + self.query = [] + def get(sdk, splitChanges, sdk_key, extra_headers, query): + self.counter += 1 + self.query.append(query) + if self.counter == 1: + return client.HttpResponse(400, 'error', {}) + if self.counter == 2: + return client.HttpResponse(200, '{"splits": [], "since": 123, "till": 456}', {}) + if self.counter == 3: + return client.HttpResponse(400, 'error', {}) + if self.counter == 4: + return client.HttpResponse(200, '{"splits": [], "since": 456, "till": 456}', {}) + + httpclient.is_sdk_endpoint_overridden.return_value = True + httpclient.get = get + split_api = splits.SplitsAPI(httpclient, 'some_api_key', SdkMetadata('1.0', 'some', '1.2.3.4'), mocker.Mock()) + response = split_api.fetch_splits(123, -1, FetchOptions(False, None, None, None)) + assert response == {"ff": {"d": [], "s": 123, "t": 456}, "rbs": {"d": [], "s": -1, "t": -1}} + assert self.query == [{'s': '1.3', 'since': 123, 'rbSince': -1}, {'s': '1.1', 'since': 123}] + assert not split_api.clear_storage + + time.sleep(1) + splits._PROXY_CHECK_INTERVAL_MILLISECONDS_SS = 10 + + response = split_api.fetch_splits(456, -1, FetchOptions(False, None, None, None)) + time.sleep(1) + splits._PROXY_CHECK_INTERVAL_MILLISECONDS_SS = 1000000 + assert self.query[2] == {'s': '1.3', 'since': 456, 'rbSince': -1} + assert self.query[3] == {'s': '1.1', 'since': 456} + assert response == {"ff": {"d": [], "s": 456, "t": 456}, "rbs": {"d": [], "s": -1, "t": -1}} class SplitAPIAsyncTests(object): """Split async API test cases.""" @@ -253,9 +288,45 @@ async def get(sdk, splitChanges, sdk_key, extra_headers, query): assert self.query == [{'s': '1.3', 'since': 123, 'rbSince': -1}, {'s': '1.1', 'since': 123}] assert not split_api.clear_storage - time.sleep(1) + time.sleep(1) splits._PROXY_CHECK_INTERVAL_MILLISECONDS_SS = 10 response = await split_api.fetch_splits(123, -1, FetchOptions(False, None, None, None)) assert self.query[2] == {'s': '1.3', 'since': 123, 'rbSince': -1} assert response == {"ff": {"d": [], "s": 123, "t": 456}, "rbs": {"d": [], "s": 123, "t": -1}} assert split_api.clear_storage + + @pytest.mark.asyncio + async def test_using_old_spec_since(self, mocker): + """Test using old_spec_since variable.""" + httpclient = mocker.Mock(spec=client.HttpClient) + self.counter = 0 + self.query = [] + async def get(sdk, splitChanges, sdk_key, extra_headers, query): + self.counter += 1 + self.query.append(query) + if self.counter == 1: + return client.HttpResponse(400, 'error', {}) + if self.counter == 2: + return client.HttpResponse(200, '{"splits": [], "since": 123, "till": 456}', {}) + if self.counter == 3: + return client.HttpResponse(400, 'error', {}) + if self.counter == 4: + return client.HttpResponse(200, '{"splits": [], "since": 456, "till": 456}', {}) + + httpclient.is_sdk_endpoint_overridden.return_value = True + httpclient.get = get + split_api = splits.SplitsAPIAsync(httpclient, 'some_api_key', SdkMetadata('1.0', 'some', '1.2.3.4'), mocker.Mock()) + response = await split_api.fetch_splits(123, -1, FetchOptions(False, None, None, None)) + assert response == {"ff": {"d": [], "s": 123, "t": 456}, "rbs": {"d": [], "s": -1, "t": -1}} + assert self.query == [{'s': '1.3', 'since': 123, 'rbSince': -1}, {'s': '1.1', 'since': 123}] + assert not split_api.clear_storage + + time.sleep(1) + splits._PROXY_CHECK_INTERVAL_MILLISECONDS_SS = 10 + + response = await split_api.fetch_splits(456, -1, FetchOptions(False, None, None, None)) + time.sleep(1) + splits._PROXY_CHECK_INTERVAL_MILLISECONDS_SS = 1000000 + assert self.query[2] == {'s': '1.3', 'since': 456, 'rbSince': -1} + assert self.query[3] == {'s': '1.1', 'since': 456} + assert response == {"ff": {"d": [], "s": 456, "t": 456}, "rbs": {"d": [], "s": -1, "t": -1}}