Skip to content

Commit

Permalink
refactor: use constants
Browse files Browse the repository at this point in the history
  • Loading branch information
mutantsan committed Nov 7, 2024
1 parent 9e78a39 commit afd896e
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 39 deletions.
4 changes: 2 additions & 2 deletions ckanext/event_audit/listeners/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import ckan.plugins.toolkit as tk
import ckan.types as ckan_types

from ckanext.event_audit import config, types, utils
from ckanext.event_audit import config, const, types, utils
from ckanext.event_audit.interfaces import IEventAudit


Expand All @@ -24,7 +24,7 @@ def action_succeeded_subscriber(

event = repo.build_event(
types.EventData(
category="api",
category=const.Category.API.value,
actor=(
tk.current_user.id
if tk.current_user and not tk.current_user.is_anonymous
Expand Down
4 changes: 2 additions & 2 deletions ckanext/event_audit/listeners/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import ckan.plugins as p
from ckan.model.base import Session

from ckanext.event_audit import config, types
from ckanext.event_audit import config, const, types
from ckanext.event_audit.interfaces import IEventAudit
from ckanext.event_audit.model import EventModel
from ckanext.event_audit.utils import get_active_repo
Expand Down Expand Up @@ -65,7 +65,7 @@ def after_commit(session: SQLAlchemySession):

event = repo.build_event(
types.EventData(
category="model",
category=const.Category.MODEL.value,
action=action,
action_object=instance.__class__.__name__,
action_object_id=inspect(instance).identity[0],
Expand Down
6 changes: 3 additions & 3 deletions ckanext/event_audit/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from ckan.tests.factories import User

from ckanext.event_audit import types, utils
from ckanext.event_audit import const, types, utils
from ckanext.event_audit.repositories.cloudwatch import CloudWatchRepository


Expand All @@ -21,7 +21,7 @@ def clean_db(reset_db: Any, migrate_db_for: Any):
@pytest.fixture()
def event() -> types.Event:
return types.Event(
category="model",
category=const.Category.MODEL.value,
action="created",
action_object="package",
actor=User()["id"],
Expand All @@ -31,7 +31,7 @@ def event() -> types.Event:
@pytest.fixture()
def event_factory():
def factory(**kwargs: types.EventData) -> types.Event:
kwargs.setdefault("category", "model") # type: ignore
kwargs.setdefault("category", const.Category.MODEL.value) # type: ignore
kwargs.setdefault("action", "created") # type: ignore

return types.Event(**kwargs) # type: ignore
Expand Down
9 changes: 6 additions & 3 deletions ckanext/event_audit/tests/listeners/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@

from ckan.tests.helpers import call_action

from ckanext.event_audit import config, repositories, types, utils
from ckanext.event_audit import config, const, repositories, types, utils
from ckanext.event_audit.repositories.cloudwatch import CloudWatchRepository


@pytest.mark.ckan_config(config.CONF_IGNORED_CATEGORIES, ["api", "views"])
@pytest.mark.ckan_config(
config.CONF_IGNORED_CATEGORIES,
[const.Category.API.value, const.Category.VIEW.value],
)
@pytest.mark.ckan_config(config.CONF_DATABASE_TRACK_ENABLED, True)
@pytest.mark.usefixtures("with_plugins")
class TestModelListener:
Expand Down Expand Up @@ -41,7 +44,7 @@ def test_cloudwatch(
"message": json.dumps(
{
"id": site_user["id"],
"category": "model",
"category": const.Category.MODEL.value,
"action": "created",
"actor": "",
"action_object": "User",
Expand Down
6 changes: 4 additions & 2 deletions ckanext/event_audit/tests/repositories/test_cloudwatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from botocore.stub import Stubber

from ckanext.event_audit import types
from ckanext.event_audit import const, types
from ckanext.event_audit.repositories.cloudwatch import CloudWatchRepository

put_log_events_response: dict[str, Any] = {
Expand Down Expand Up @@ -103,7 +103,9 @@ def test_filter_events(
)

with stubber:
events = repo.filter_events(types.Filters(category="model"))
events = repo.filter_events(
types.Filters(category=const.Category.MODEL.value)
)

assert len(events) == 1
assert events[0].model_dump() == event.model_dump()
Expand Down
10 changes: 6 additions & 4 deletions ckanext/event_audit/tests/repositories/test_postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import pytest

from ckanext.event_audit import config, types
from ckanext.event_audit import config, const, types
from ckanext.event_audit.repositories import PostgresRepository


Expand Down Expand Up @@ -35,7 +35,9 @@ def test_filter_by_category(self, event: types.Event):
postgres_repo = PostgresRepository()

postgres_repo.write_event(event)
events = postgres_repo.filter_events(types.Filters(category="model"))
events = postgres_repo.filter_events(
types.Filters(category=const.Category.MODEL.value)
)

assert len(events) == 1
assert events[0].model_dump() == event.model_dump()
Expand All @@ -54,7 +56,7 @@ def test_filter_by_action_and_action_object(self, event: types.Event):

postgres_repo.write_event(event)
events = postgres_repo.filter_events(
types.Filters(category="model", action_object="package")
types.Filters(category=const.Category.MODEL.value, action_object="package")
)

assert len(events) == 1
Expand Down Expand Up @@ -112,7 +114,7 @@ def test_filter_by_multiple(self, event_factory: Callable[..., types.Event]):

events = postgres_repo.filter_events(
types.Filters(
category="model",
category=const.Category.MODEL.value,
action="created",
)
)
Expand Down
6 changes: 3 additions & 3 deletions ckanext/event_audit/tests/repositories/test_redis.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import pytest

from ckanext.event_audit import config, types
from ckanext.event_audit import config, const, types
from ckanext.event_audit.repositories import RedisRepository


Expand All @@ -32,7 +32,7 @@ def test_filter_by_category(self, event: types.Event):
result = repo.write_event(event)
assert result.status is True

events = repo.filter_events(types.Filters(category="model"))
events = repo.filter_events(types.Filters(category=const.Category.MODEL.value))
assert len(events) == 1
assert events[0].model_dump() == event.model_dump()

Expand All @@ -53,7 +53,7 @@ def test_filter_by_action_and_action_object(self, event: types.Event):
assert result.status is True

events = repo.filter_events(
types.Filters(category="model", action_object="package")
types.Filters(category=const.Category.MODEL.value, action_object="package")
)
assert len(events) == 1
assert events[0].model_dump() == event.model_dump()
Expand Down
62 changes: 42 additions & 20 deletions ckanext/event_audit/tests/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
import pytest
from pydantic_core import ValidationError

from ckanext.event_audit import types
from ckanext.event_audit import const, types


class TestEvent:
def test_valid_event(self):
"""Test creation of a valid event with required fields."""
event = types.Event(category="model", action="created")
event = types.Event(category=const.Category.MODEL.value, action="created")

assert event.category == "model"
assert event.category == const.Category.MODEL.value
assert event.action == "created"

assert isinstance(event.id, str)
Expand All @@ -21,7 +21,7 @@ def test_event_with_optional_fields(self, user):
"""Test creating an event with all fields filled."""
timestamp = datetime.now(timezone.utc).isoformat()
event = types.Event(
category="model",
category=const.Category.MODEL.value,
action="created",
actor=user["id"],
action_object="package",
Expand Down Expand Up @@ -52,68 +52,90 @@ def test_empty_action(self):
with pytest.raises(
ValidationError, match="The `action` field must be a non-empty string."
):
types.Event(category="model", action="")
types.Event(category=const.Category.MODEL.value, action="")

def test_category_not_string(self):
"""Test that non-string category raises a ValidationError."""
with pytest.raises(ValidationError, match="Input should be a valid string."):
types.Event(category=1, action="created")
types.Event(category=1, action="created") # type: ignore

def test_action_not_string(self):
"""Test that non-string action raises a ValidationError."""
with pytest.raises(ValidationError, match="Input should be a valid string"):
types.Event(category="model", action=1)
types.Event(category=const.Category.MODEL.value, action=1) # type: ignore

def test_actor_not_string(self):
"""Test that a non-string actor raises a ValidationError."""
with pytest.raises(ValidationError):
types.Event(category="model", action="created", actor=123)
types.Event(
category=const.Category.MODEL.value, action="created", actor=123 # type: ignore
)

def test_invalid_timestamp_format(self):
"""Test that an invalid timestamp format raises a ValidationError."""
with pytest.raises(ValidationError, match="Date format incorrect"):
types.Event(category="model", action="created", timestamp="invalid-date")
types.Event(
category=const.Category.MODEL.value,
action="created",
timestamp="invalid-date",
)

def test_future_timestamp(self):
"""Test handling of future timestamps."""
future_timestamp = (datetime.now(timezone.utc) + timedelta(days=1)).isoformat()
event = types.Event(
category="model", action="created", timestamp=future_timestamp
category=const.Category.MODEL.value,
action="created",
timestamp=future_timestamp,
)
assert event.timestamp == future_timestamp

def test_default_timestamp(self):
"""Test that the default timestamp is set to the current time."""
event = types.Event(category="model", action="created")
event = types.Event(category=const.Category.MODEL.value, action="created")
timestamp = datetime.now(timezone.utc).isoformat()

# Allowing a small difference in time to handle execution delays
assert event.timestamp[:19] == timestamp[:19]
assert event.timestamp[:19] == timestamp[:19] # type: ignore

def test_empty_result_and_payload(self):
"""Test that result and payload default to empty dictionaries."""
event = types.Event(category="model", action="created")
event = types.Event(category=const.Category.MODEL.value, action="created")
assert event.result == {}
assert event.payload == {}

def test_user_doesnt_exist(self):
"""Test that invalid actor reference raises a ValidationError."""
with pytest.raises(ValidationError, match="Not found: User"):
types.Event(category="model", action="created", actor="non-existent-user")
types.Event(
category=const.Category.MODEL.value,
action="created",
actor="non-existent-user",
)

def test_custom_id_generation(self):
"""Test that a custom id can be provided."""
custom_id = "12345"
event = types.Event(category="model", action="created", id=custom_id)
event = types.Event(
category=const.Category.MODEL.value, action="created", id=custom_id
)
assert event.id == custom_id

def test_invalid_field_assignment(self):
"""Test that assigning invalid data types to fields raises an error."""
with pytest.raises(ValidationError):
types.Event(category="model", action="created", result="not-a-dict") # type: ignore
types.Event(
category=const.Category.MODEL.value,
action="created",
result="not-a-dict", # type: ignore
) # type: ignore

with pytest.raises(ValidationError):
types.Event(category="model", action="created", payload="not-a-dict") # type: ignore
types.Event(
category=const.Category.MODEL.value,
action="created",
payload="not-a-dict", # type: ignore
)


class TestFilters:
Expand All @@ -124,7 +146,7 @@ def test_empty_filters(self):
def test_valid_filters(self, user):
"""Test creating a valid Filters object."""
filters = types.Filters(
category="api",
category=const.Category.API.value,
action="created",
actor=user["id"],
action_object="package",
Expand All @@ -134,7 +156,7 @@ def test_valid_filters(self, user):
time_from=datetime.now(timezone.utc) - timedelta(days=1),
time_to=datetime.now(timezone.utc),
)
assert filters.category == "api"
assert filters.category == const.Category.API.value
assert filters.action == "created"
assert filters.actor == user["id"]

Expand All @@ -147,7 +169,7 @@ def test_empty_optional_strings(self):
def test_whitespace_trimming(self):
"""Test that leading and trailing spaces are removed from string fields."""
filters = types.Filters(category=" api ", action=" created ")
assert filters.category == "api"
assert filters.category == const.Category.API.value
assert filters.action == "created"

def test_time_range_validation(self):
Expand Down

0 comments on commit afd896e

Please sign in to comment.