From 2a3efbba852f32eba67cff13bbf6b49ed106cfee Mon Sep 17 00:00:00 2001 From: Hugo Rodger-Brown Date: Mon, 18 Sep 2023 10:43:22 +0100 Subject: [PATCH] Fix redaction tests --- tests/conftest.py | 29 ++++++++++++++++++++ tests/test_db.py | 23 ---------------- tests/test_models.py | 17 ++---------- tests/test_models_pg.py | 61 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 37 deletions(-) create mode 100644 tests/conftest.py delete mode 100644 tests/test_db.py create mode 100644 tests/test_models_pg.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..55feec2 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,29 @@ +import pytest +from django.conf import settings + +from tests.anon import UserAnonymiser +from tests.models import User + +IS_POSTGRES = ( + not settings.DATABASES["default"]["ENGINE"].endswith("postgresql"), + "PostgreSQL only", +) + + +@pytest.fixture +def user() -> User: + return User.objects.create_user( + username="testuser1", first_name="fred", last_name="flintstone" + ) + + +@pytest.fixture +def user2() -> User: + return User.objects.create_user( + username="testuser2", first_name="ginger", last_name="rogers" + ) + + +@pytest.fixture +def user_anonymiser() -> UserAnonymiser: + return UserAnonymiser() diff --git a/tests/test_db.py b/tests/test_db.py deleted file mode 100644 index 2294f28..0000000 --- a/tests/test_db.py +++ /dev/null @@ -1,23 +0,0 @@ -from unittest import mock, skipIf - -import pytest -from django.conf import settings -from django.db.backends.utils import CursorWrapper - -from anonymiser.db.expressions import GenerateUuid4 - -from .models import User - -# skip if we're using SQLite as it doesn't support UUIDs -is_sqlite = settings.DATABASES["default"]["ENGINE"] == "django.db.backends.sqlite3" - - -@skipIf(is_sqlite, "SQLite does not support native generation of UUIDs.") -@pytest.mark.django_db -@mock.patch.object(CursorWrapper, "execute") -def test_generate_uuid4(mock_execute: mock.MagicMock) -> None: - User.objects.update(uuid=GenerateUuid4()) - assert ( - mock_execute.call_args[0][0] - == 'UPDATE "tests_user" SET "uuid" = uuid_generate_v4()' - ) diff --git a/tests/test_models.py b/tests/test_models.py index 00d14a2..4993e9b 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -8,11 +8,6 @@ from .models import User -@pytest.fixture -def user_anonymiser() -> UserAnonymiser: - return UserAnonymiser() - - def test_model_fields_summary(user_anonymiser: UserAnonymiser) -> None: assert user_anonymiser.get_model_field_summary() == [ FieldSummaryData(User._meta.get_field("id"), False), @@ -43,12 +38,6 @@ def test_model_fields_data(user_anonymiser: UserAnonymiser) -> None: @pytest.mark.django_db class TestAnonymisableUserModel: - @pytest.fixture - def user(self) -> User: - return User.objects.create_user( - username="testuser", first_name="fred", last_name="flintstone" - ) - def test_anonymise_not_implemented( self, user: User, user_anonymiser: UserAnonymiser ) -> None: @@ -65,15 +54,15 @@ def test_anonymise_first_name_field( def test_anonymise(self, user: User, user_anonymiser: UserAnonymiser) -> None: assert user.first_name == "fred" assert user.last_name == "flintstone" - assert user.username == "testuser" + assert user.username == "testuser1" user_anonymiser.anonymise_object(user) assert user.first_name == "Anonymous" assert user.last_name == "flintstone" - assert user.username == "testuser" + assert user.username == "testuser1" user.refresh_from_db() assert user.first_name == "fred" assert user.last_name == "flintstone" - assert user.username == "testuser" + assert user.username == "testuser1" @mock.patch.object(UserAnonymiser, "post_anonymise_object") def test_post_anonymise_object( diff --git a/tests/test_models_pg.py b/tests/test_models_pg.py new file mode 100644 index 0000000..11e9619 --- /dev/null +++ b/tests/test_models_pg.py @@ -0,0 +1,61 @@ +from unittest import SkipTest, mock + +import pytest +from django.conf import settings +from django.db import connection +from django.db.backends.utils import CursorWrapper + +from anonymiser.db.expressions import GenerateUuid4 + +from .anon import UserAnonymiser +from .models import User + +# skip if we're using SQLite as it doesn't support UUIDs +if settings.DATABASES["default"]["ENGINE"] == "django.db.backends.sqlite3": + # this will skip all tests in this file + raise SkipTest("Skipping Postgres tets as SQLite is being used.") + + +@pytest.mark.django_db +@mock.patch.object(CursorWrapper, "execute") +def test_generate_uuid4(mock_execute: mock.MagicMock) -> None: + User.objects.update(uuid=GenerateUuid4()) + assert ( + mock_execute.call_args[0][0] + == 'UPDATE "tests_user" SET "uuid" = uuid_generate_v4()' + ) + + +@pytest.mark.django_db +class TestPostgresRedaction: + @pytest.fixture(autouse=True) + def activate_postgresql_uuid(self) -> None: + """Activate the uuid-ossp extension in the test database.""" + with connection.cursor() as cursor: + cursor.execute('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";') + + def test_redact_queryset_none( + self, user: User, user_anonymiser: UserAnonymiser + ) -> None: + assert user_anonymiser.redact_queryset(User.objects.none()) == 0 + + def test_redact_queryset_one( + self, user: User, user_anonymiser: UserAnonymiser + ) -> None: + uuid = user.uuid + assert user_anonymiser.redact_queryset(User.objects.all()) == 1 + user.refresh_from_db() + assert user.first_name == user_anonymiser.field_redactions["first_name"] + assert user.uuid != uuid + + def test_redact_queryset_two( + self, + user: User, + user2: User, + user_anonymiser: UserAnonymiser, + ) -> None: + assert user_anonymiser.redact_queryset(User.objects.all()) == 2 + user.refresh_from_db() + user2.refresh_from_db() + # confirm that we haven't reused the same uuid for all objects + assert user.uuid != user2.uuid