From 789ac8b41ff24a0bfeaae15b8797e338428b4665 Mon Sep 17 00:00:00 2001 From: Gagan Trivedi Date: Wed, 11 Aug 2021 13:27:13 +0530 Subject: [PATCH] wip: Add test cases --- .isort.cfg | 2 +- api/features/views.py | 2 +- api/requirements-dev.txt | 1 + api/tests/integration/conftest.py | 32 +---- .../features/test_feature_state.py | 116 ++++++++++++++++++ api/tests/integration/helpers.py | 11 ++ 6 files changed, 131 insertions(+), 33 deletions(-) create mode 100644 api/tests/integration/features/test_feature_state.py diff --git a/.isort.cfg b/.isort.cfg index 744a883562f4..c53f3cef45d3 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -4,4 +4,4 @@ multi_line_output=3 include_trailing_comma=true line_length=79 known_first_party=analytics,app,custom_auth,environments,integrations,organisations,projects,segments,users,webhooks,api,audit,e2etests,features,permissions,util -known_third_party=apiclient,app_analytics,axes,chargebee,core,coreapi,corsheaders,dateutil,dj_database_url,django,django_lifecycle,djoser,drf_writable_nested,drf_yasg2,environs,google,influxdb_client,ordered_model,pyotp,pytest,pytz,requests,responses,rest_framework,rest_framework_nested,rest_framework_recursive,sentry_sdk,shortuuid,simple_history,six,telemetry,tests,trench,whitenoise +known_third_party=apiclient,app_analytics,axes,chargebee,core,coreapi,corsheaders,dateutil,dj_database_url,django,django_lifecycle,djoser,drf_writable_nested,drf_yasg2,environs,freezegun,google,influxdb_client,ordered_model,pyotp,pytest,pytz,requests,responses,rest_framework,rest_framework_nested,rest_framework_recursive,sentry_sdk,shortuuid,simple_history,six,telemetry,tests,trench,whitenoise diff --git a/api/features/views.py b/api/features/views.py index e009e518bd05..506e12e73a11 100644 --- a/api/features/views.py +++ b/api/features/views.py @@ -162,7 +162,7 @@ def get_queryset(self): def get_serializer_context(self): context = super().get_serializer_context() queryset = self.get_base_qs() - # Add emptry order by to force group by to happen on featur__id + # Add emptry order by to force group by to happen on feature__id feature_updated_at_cache = list( queryset.values("feature__id") .annotate(updated_at=Max("updated_at")) diff --git a/api/requirements-dev.txt b/api/requirements-dev.txt index 3fa009c0c72a..db62d3532e7a 100644 --- a/api/requirements-dev.txt +++ b/api/requirements-dev.txt @@ -9,3 +9,4 @@ black pip-tools responses pre-commit +freezegun diff --git a/api/tests/integration/conftest.py b/api/tests/integration/conftest.py index b5c53deead0d..d15ecb1284b7 100644 --- a/api/tests/integration/conftest.py +++ b/api/tests/integration/conftest.py @@ -1,5 +1,6 @@ import json import uuid +from typing import Callable, Mapping import pytest from django.test import Client as DjangoClient @@ -60,22 +61,6 @@ def environment(admin_client, project, environment_api_key) -> int: return response.json()["id"] -@pytest.fixture() -def segment(admin_client, project) -> int: - url = reverse("api-v1:projects:project-segments-list", args=[project]) - segment_data = { - "name": "Test Segment", - "project": project, - "rules": [{"type": "ALL", "rules": [], "conditions": []}], - } - - response = admin_client.post( - url, data=json.dumps(segment_data), content_type="application/json" - ) - print(response.content) - return response.json()["id"] - - @pytest.fixture() def identity_identifier(): return uuid.uuid4() @@ -91,21 +76,6 @@ def identity(admin_client, identity_identifier, environment, environment_api_key return response.json()["id"] -@pytest.fixture() -def feature(admin_client, project, environment): - default_value = "This is a value" - data = { - "name": "test feature", - "initial_value": default_value, - "project": project, - } - url = reverse("api-v1:projects:project-features-list", args=[project]) - - # When - response = admin_client.post(url, data=data) - return response.json()["id"] - - @pytest.fixture() def sdk_client(environment_api_key): client = APIClient() diff --git a/api/tests/integration/features/test_feature_state.py b/api/tests/integration/features/test_feature_state.py new file mode 100644 index 000000000000..913dcdba27ec --- /dev/null +++ b/api/tests/integration/features/test_feature_state.py @@ -0,0 +1,116 @@ +import json +from datetime import datetime, timedelta + +import pytest +from django.urls import reverse +from django.utils import timezone +from freezegun import freeze_time +from rest_framework import status +from tests.integration.helpers import ( + get_env_feature_states_list_with_api, + update_feature_state_with_api, +) + + +@pytest.fixture() +def frozen_time(): + with freeze_time(timezone.now() - timedelta(days=2)) as f: + yield f + + +def test_updates_days_since_feature_last_updated_is_part_of_respone( + frozen_time, admin_client, environment_api_key, environment, feature +): + # Given + url = reverse( + "api-v1:environments:environment-featurestates-list", + args=[environment_api_key], + ) + + # When + response = admin_client.get(url) + # Then + assert response.json()["results"][0]["days_since_feature_last_updated"] == 2 + + +def test_updating_feature_state_updates_days_since_feature_last_updated( + frozen_time, admin_client, environment, environment_api_key, project, feature +): + # Given + url = reverse( + "api-v1:environments:environment-featurestates-list", + args=[environment_api_key], + ) + # Get the feature state to update + feature_state = get_env_feature_states_list_with_api( + admin_client, {"environment": environment} + )["results"][0]["id"] + + # When + + # Firstly, let's reset the time so that feature state update happen at t + # instead of t-2 + frozen_time.move_to(datetime.now() + timedelta(days=2)) + + # Update the feature state + update_feature_state_with_api( + admin_client, + { + "id": feature_state, + "feature_state_value": {"type": "unicode", "string_value": "new_value"}, + "enabled": False, + "feature": feature, + "environment": environment, + "identity": None, + "feature_segment": None, + }, + ) + response = admin_client.get(url) + + # Then + assert response.json()["results"][0]["days_since_feature_last_updated"] == 0 + + +def test_adding_feature_segment_udpates_days_since_feature_last_updated( + frozen_time, + admin_client, + environment, + environment_api_key, + project, + feature, + segment, + feature_segment, +): + # Given + frozen_time.move_to(datetime.now() + timedelta(days=2)) + + # Let's create a feature segment override + create_url = reverse("api-v1:features:featurestates-list") + data = { + "feature_state_value": { + "type": "unicode", + "boolean_value": None, + "integer_value": None, + "string_value": "dumb", + }, + "multivariate_feature_state_values": [], + "enabled": False, + "feature": feature, + "environment": environment, + "identity": None, + "feature_segment": feature_segment, + } + seg_override_response = admin_client.post( + create_url, data=json.dumps(data), content_type="application/json" + ) + # Make sure that override was a success + assert seg_override_response.status_code == status.HTTP_201_CREATED + + url = reverse( + "api-v1:environments:environment-featurestates-list", + args=[environment_api_key], + ) + response = admin_client.get(url) + + # Then + assert response.json()["results"][0]["days_since_feature_last_updated"] == 0 diff --git a/api/tests/integration/helpers.py b/api/tests/integration/helpers.py index 57b0aa71d9a1..2ac0636352f0 100644 --- a/api/tests/integration/helpers.py +++ b/api/tests/integration/helpers.py @@ -81,3 +81,14 @@ def get_json_response(client: APIClient, url: str, query_params: dict) -> dict: if query_params: url = f"{url}?{urlencode(query_params)}" return client.get(url).json() + + +def update_feature_state_with_api(client: APIClient, data: dict): + feature_state = data["id"] + fs_update_url = reverse( + "api-v1:features:featurestates-detail", args=[feature_state] + ) + response = client.put( + fs_update_url, data=json.dumps(data), content_type="application/json" + ) + return response.json()