Skip to content

Commit

Permalink
fix: searching edge identities (dashboard_alias prefix and identifier…
Browse files Browse the repository at this point in the history
… casing) (#4700)
  • Loading branch information
matthewelwell authored Oct 8, 2024
1 parent b689a62 commit 8e6b241
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 54 deletions.
7 changes: 5 additions & 2 deletions api/edge_api/identities/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,14 @@ class GetEdgeIdentityOverridesQuerySerializer(serializers.Serializer):
class EdgeIdentitySearchField(serializers.CharField):
def to_internal_value(self, data: str) -> EdgeIdentitySearchData:
kwargs = {}
search_term = data.lower()
search_term = data

if search_term.startswith(DASHBOARD_ALIAS_SEARCH_PREFIX):
kwargs["search_attribute"] = DASHBOARD_ALIAS_ATTRIBUTE
search_term = search_term.lstrip(DASHBOARD_ALIAS_SEARCH_PREFIX)
# dashboard aliases are always stored in lower case
search_term = search_term.removeprefix(
DASHBOARD_ALIAS_SEARCH_PREFIX
).lower()
else:
kwargs["search_attribute"] = IDENTIFIER_ATTRIBUTE

Expand Down
9 changes: 6 additions & 3 deletions api/tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,9 @@ def identity_document(
mv_feature_name,
mv_feature,
):
_identifier = "User1-Test" # use a mixture of cases and symbols to make sure we're testing all cases
_dashboard_alias = "dashboard-alias"

_environment_feature_state_1_document = {
"featurestate_uuid": "ad71c644-71df-4e83-9cb5-cd2cd0160200",
"multivariate_feature_state_values": [],
Expand Down Expand Up @@ -431,15 +434,15 @@ def identity_document(
"feature_segment": None,
}
return {
"composite_key": f"{environment_api_key}_user_1_test",
"dashboard_alias": "dashboard-alias",
"composite_key": f"{environment_api_key}_{_identifier}",
"dashboard_alias": _dashboard_alias,
"identity_traits": identity_traits,
"identity_features": [
_environment_feature_state_1_document,
_environment_feature_state_2_document,
_mv_feature_state_document,
],
"identifier": "user_1_test",
"identifier": _identifier,
"created_date": "2021-09-21T10:12:42.230257+00:00",
"environment_api_key": environment_api_key,
"identity_uuid": "59efa2a7-6a45-46d6-b953-a7073a90eacf",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@
from rest_framework.exceptions import NotFound
from rest_framework.test import APIClient

from edge_api.identities.search import (
DASHBOARD_ALIAS_SEARCH_PREFIX,
IDENTIFIER_ATTRIBUTE,
EdgeIdentitySearchData,
EdgeIdentitySearchType,
)
from edge_api.identities.search import DASHBOARD_ALIAS_SEARCH_PREFIX
from environments.dynamodb.wrappers.environment_wrapper import (
DynamoEnvironmentV2Wrapper,
)
Expand Down Expand Up @@ -259,54 +254,43 @@ def test_get_identities_list(


def test_search_identities_without_exact_match(
admin_client,
dynamo_enabled_environment,
environment_api_key,
identity_document,
edge_identity_dynamo_wrapper_mock,
admin_client: APIClient,
dynamo_enabled_environment: Environment,
environment_api_key: str,
identity_document: dict[str, Any],
flagsmith_identities_table: Table,
):
# Given
identifier = identity_document["identifier"]

flagsmith_identities_table.put_item(Item=identity_document)

base_url = reverse(
"api-v1:environments:environment-edge-identities-list",
args=[environment_api_key],
)

url = "%s?q=%s" % (base_url, identifier)
edge_identity_dynamo_wrapper_mock.search_items.return_value = {
"Items": [identity_document],
"Count": 1,
}
url = "%s?q=%s" % (base_url, identifier[:6])

# When
response = admin_client.get(url)

# Then
assert response.status_code == status.HTTP_200_OK
assert response.json()["results"][0]["identifier"] == identifier
assert len(response.json()["results"]) == 1

edge_identity_dynamo_wrapper_mock.search_items.assert_called_with(
environment_api_key=environment_api_key,
search_data=EdgeIdentitySearchData(
search_term=identifier,
search_type=EdgeIdentitySearchType.BEGINS_WITH,
search_attribute=IDENTIFIER_ATTRIBUTE,
),
limit=100,
start_key=None,
)
assert response.json()["results"][0]["identifier"] == identifier


def test_search_for_identities_with_exact_match(
admin_client,
dynamo_enabled_environment,
environment_api_key,
identity_document,
edge_identity_dynamo_wrapper_mock,
admin_client: APIClient,
dynamo_enabled_environment: Environment,
environment_api_key: str,
identity_document: dict[str, Any],
flagsmith_identities_table: Table,
):
# Given
identifier = identity_document["identifier"]
flagsmith_identities_table.put_item(Item=identity_document)

base_url = reverse(
"api-v1:environments:environment-edge-identities-list",
Expand All @@ -316,31 +300,56 @@ def test_search_for_identities_with_exact_match(
base_url,
urllib.parse.urlencode({"q": f'"{identifier}"'}),
)
edge_identity_dynamo_wrapper_mock.search_items.return_value = {
"Items": [identity_document],
"Count": 1,
}

# When
response = admin_client.get(url)

# Then
assert response.status_code == status.HTTP_200_OK
assert response.json()["results"][0]["identifier"] == identifier
assert len(response.json()["results"]) == 1
assert response.json()["results"][0]["identifier"] == identifier


def test_search_for_identities_by_dashboard_alias_prefix(
admin_client: APIClient,
dynamo_enabled_environment: Environment,
environment_api_key: str,
identity_document: dict[str, Any],
flagsmith_identities_table: Table,
) -> None:
# Given
identifier = identity_document["identifier"]

# This test verifies a previous bug which meant that if any of the
# leading characters to the search string were contained in the
# `string `"dashboard_alias:"` then they would also be removed
# and the search would fail.
identity_document["dashboard_alias"] = "[email protected]"
search_string = "hans"

edge_identity_dynamo_wrapper_mock.search_items.assert_called_with(
environment_api_key=environment_api_key,
search_data=EdgeIdentitySearchData(
search_term=identifier,
search_type=EdgeIdentitySearchType.EQUAL,
search_attribute=IDENTIFIER_ATTRIBUTE,
flagsmith_identities_table.put_item(Item=identity_document)

base_url = reverse(
"api-v1:environments:environment-edge-identities-list",
args=[environment_api_key],
)
url = "%s?%s" % (
base_url,
urllib.parse.urlencode(
{"q": f"{DASHBOARD_ALIAS_SEARCH_PREFIX}{search_string}"}
),
limit=100,
start_key=None,
)

# When
response = admin_client.get(url)

def test_search_for_identities_by_dashboard_alias(
# Then
assert response.status_code == status.HTTP_200_OK
assert len(response.json()["results"]) == 1
assert response.json()["results"][0]["identifier"] == identifier


def test_search_for_identities_by_dashboard_alias_exact(
admin_client: APIClient,
dynamo_enabled_environment: Environment,
environment_api_key: str,
Expand Down Expand Up @@ -369,8 +378,8 @@ def test_search_for_identities_by_dashboard_alias(

# Then
assert response.status_code == status.HTTP_200_OK
assert response.json()["results"][0]["identifier"] == identifier
assert len(response.json()["results"]) == 1
assert response.json()["results"][0]["identifier"] == identifier


def test_search_for_identities_by_dashboard_alias_casts_search_to_lower(
Expand Down Expand Up @@ -402,8 +411,8 @@ def test_search_for_identities_by_dashboard_alias_casts_search_to_lower(

# Then
assert response.status_code == status.HTTP_200_OK
assert response.json()["results"][0]["identifier"] == identifier
assert len(response.json()["results"]) == 1
assert response.json()["results"][0]["identifier"] == identifier


def test_update_edge_identity(
Expand Down

0 comments on commit 8e6b241

Please sign in to comment.