Skip to content

Commit

Permalink
feat(environment_api_key): propagate delete to dynamo
Browse files Browse the repository at this point in the history
  • Loading branch information
gagantrivedi committed Dec 26, 2023
1 parent a14eb23 commit ec511af
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 9 deletions.
3 changes: 3 additions & 0 deletions api/environments/dynamodb/dynamodb_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,3 +291,6 @@ def write_api_keys(self, api_keys: Iterable["EnvironmentAPIKey"]):
api_key
)
)

def delete_api_key(self, key: str):
self.table.delete_item(Key={"key": key})
16 changes: 12 additions & 4 deletions api/environments/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from django.utils.translation import ugettext_lazy as _
from django_lifecycle import (
AFTER_CREATE,
AFTER_DELETE,
AFTER_SAVE,
AFTER_UPDATE,
BEFORE_UPDATE,
Expand Down Expand Up @@ -449,10 +450,17 @@ def natural_key(self):
def is_valid(self) -> bool:
return self.active and (not self.expires_at or self.expires_at > timezone.now())

@hook(AFTER_SAVE)
@hook(AFTER_SAVE, when="_should_update_dynamo", is_now=True)
def send_to_dynamo(self):
if (
environment_api_key_wrapper.write_api_key(self)

@hook(AFTER_DELETE, when="_should_update_dynamo", is_now=True)
def delete_from_dynamo(self):
environment_api_key_wrapper.delete_api_key(self.key)

@property
def _should_update_dynamo(self) -> bool:
return (
self.environment.project.enable_dynamo_db
and environment_api_key_wrapper.is_enabled
):
environment_api_key_wrapper.write_api_key(self)
)
20 changes: 20 additions & 0 deletions api/tests/unit/conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import typing

import pytest

from environments.models import Environment
Expand All @@ -7,6 +9,12 @@
from projects.tags.models import Tag
from users.models import FFAdminUser

if typing.TYPE_CHECKING:
from mypy_boto3_dynamodb.service_resource import (
DynamoDBServiceResource,
Table,
)


@pytest.fixture()
def organisation_one(db):
Expand Down Expand Up @@ -189,3 +197,15 @@ def project_two_feature(project_two: Project) -> Feature:
return Feature.objects.create(
name="project_two_feature", project=project_two, initial_value="initial_value"
)


@pytest.fixture()
def flagsmith_environment_api_key_table(dynamodb: "DynamoDBServiceResource") -> "Table":
return dynamodb.create_table(
TableName="flagsmith_environment_api_key",
KeySchema=[{"AttributeName": "key", "KeyType": "HASH"}],
AttributeDefinitions=[
{"AttributeName": "key", "AttributeType": "S"},
],
BillingMode="PAY_PER_REQUEST",
)
38 changes: 33 additions & 5 deletions api/tests/unit/environments/test_unit_environments_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from django.test import TestCase, override_settings
from django.utils import timezone
from pytest_django.asserts import assertQuerysetEqual as assert_queryset_equal
from pytest_mock import MockerFixture

from audit.models import AuditLog
from audit.related_object_type import RelatedObjectType
Expand All @@ -31,6 +32,7 @@

if typing.TYPE_CHECKING:
from django.db.models import Model
from mypy_boto3_dynamodb.service_resource import Table

from features.workflows.core.models import ChangeRequest

Expand Down Expand Up @@ -802,20 +804,46 @@ def test_get_hide_disabled_flags(
assert environment.get_hide_disabled_flags() is expected_result


def test_saving_environment_api_key_calls_put_item_with_correct_arguments_if_enabled(
dynamo_enabled_project_environment_one, mocker
def test_saving_environment_api_key_creates_dynamo_document_if_enabled(
dynamo_enabled_project_environment_one: Environment,
mocker: MockerFixture,
flagsmith_environment_api_key_table: "Table",
):
# Given
mocked_environment_api_key_wrapper = mocker.patch(
"environments.models.environment_api_key_wrapper", autospec=True
mocker.patch(
"environments.models.environment_api_key_wrapper.get_table",
return_value=flagsmith_environment_api_key_table,
)
# When
api_key = EnvironmentAPIKey.objects.create(
name="Some key", environment=dynamo_enabled_project_environment_one
)

# Then
mocked_environment_api_key_wrapper.write_api_key.assert_called_with(api_key)
response = flagsmith_environment_api_key_table.get_item(Key={"key": api_key.key})
assert response["Item"]["key"] == api_key.key


def test_deleting_environment_api_key_deletes_dynamo_document_if_enabled(
dynamo_enabled_project_environment_one: Environment,
mocker: MockerFixture,
flagsmith_environment_api_key_table: "Table",
):
# Given
mocker.patch(
"environments.models.environment_api_key_wrapper.get_table",
return_value=flagsmith_environment_api_key_table,
)
api_key = EnvironmentAPIKey.objects.create(
name="Some key", environment=dynamo_enabled_project_environment_one
)

# When
api_key.delete()

# Then
response = flagsmith_environment_api_key_table.get_item(Key={"key": api_key.key})
assert "Item" not in response


def test_put_item_not_called_when_saving_environment_api_key_for_non_edge_project(
Expand Down

0 comments on commit ec511af

Please sign in to comment.