Skip to content
66 changes: 66 additions & 0 deletions V2/source/activities_data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
[
{
"name": "Development",
"description": "Development",
"tenant_id": "cc925a5d-9644-4a4f-8d99-0bee49aadd05",
"id": "c61a4a49-3364-49a3-a7f7-0c5f2d15072b",
"_rid": "QUwFAPuumiRhAAAAAAAAAA==",
"_self": "dbs/QUwFAA==/colls/QUwFAPuumiQ=/docs/QUwFAPuumiRhAAAAAAAAAA==/",
"_etag": "\"4e006cc9-0000-0500-0000-607dcc0d0000\"",
"_attachments": "attachments/",
"_last_event_ctx": {
"user_id": "dd76e5d6-3949-46fd-b418-f15bf7c354fa",
"tenant_id": "cc925a5d-9644-4a4f-8d99-0bee49aadd05",
"action": "delete",
"description": null,
"container_id": "activity",
"session_id": null
},
"deleted": "b4327ba6-9f96-49ee-a9ac-3c1edf525172",
"status": null,
"_ts": 1618856973
},
{
"name": "Management",
"description": null,
"tenant_id": "cc925a5d-9644-4a4f-8d99-0bee49aadd05",
"id": "94ec92e2-a500-4700-a9f6-e41eb7b5507c",
"_last_event_ctx": {
"user_id": "dd76e5d6-3949-46fd-b418-f15bf7c354fa",
"tenant_id": "cc925a5d-9644-4a4f-8d99-0bee49aadd05",
"action": "delete",
"description": null,
"container_id": "activity",
"session_id": null
},
"_rid": "QUwFAPuumiRfAAAAAAAAAA==",
"_self": "dbs/QUwFAA==/colls/QUwFAPuumiQ=/docs/QUwFAPuumiRfAAAAAAAAAA==/",
"_etag": "\"4e0069c9-0000-0500-0000-607dcc0d0000\"",
"_attachments": "attachments/",
"deleted": "7cf6efe5-a221-4fe4-b94f-8945127a489a",
"status": null,
"_ts": 1618856973
},
{
"name": "Operations",
"description": "Operation activities performed.",
"tenant_id": "cc925a5d-9644-4a4f-8d99-0bee49aadd05",
"id": "d45c770a-b1a0-4bd8-a713-22c01a23e41b",
"_rid": "QUwFAPuumiRjAAAAAAAAAA==",
"_self": "dbs/QUwFAA==/colls/QUwFAPuumiQ=/docs/QUwFAPuumiRjAAAAAAAAAA==/",
"_etag": "\"09009a4d-0000-0500-0000-614b66fb0000\"",
"_attachments": "attachments/",
"_last_event_ctx": {
"user_id": "82ed0f65-051c-4898-890f-870805900e21",
"tenant_id": "cc925a5d-9644-4a4f-8d99-0bee49aadd05",
"action": "update",
"description": null,
"container_id": "activity",
"session_id": null
},
"deleted": "7cf6efe5-a221-4fe4-b94f-8945127a489a",
"status": "active",
"_ts": 1632331515
}
]

13 changes: 13 additions & 0 deletions V2/source/daos/activities_dao.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from V2.source.dtos.activity import Activity
import abc
import typing


class ActivitiesDao(abc.ABC):
@abc.abstractmethod
def get_by_id(self, id: str) -> Activity:
pass

@abc.abstractmethod
def get_all(self) -> typing.List[Activity]:
pass
42 changes: 42 additions & 0 deletions V2/source/daos/activities_json_dao.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from V2.source.daos.activities_dao import ActivitiesDao
from V2.source.dtos.activity import Activity
import dataclasses
import json
import typing


class ActivitiesJsonDao(ActivitiesDao):
def __init__(self, json_data_file_path: str):
self.json_data_file_path = json_data_file_path
self.activity_keys = [
field.name for field in dataclasses.fields(Activity)
]

def get_by_id(self, activity_id: str) -> Activity:
activity = {
activity.get('id'): activity
for activity in self.__get_activities_from_file()
}.get(activity_id)

return self.__create_activity_dto(activity) if activity else None

def get_all(self) -> typing.List[Activity]:
return [
self.__create_activity_dto(activity)
for activity in self.__get_activities_from_file()
]

def __get_activities_from_file(self) -> typing.List[dict]:
try:
file = open(self.json_data_file_path)
activities = json.load(file)
file.close()

return activities

except FileNotFoundError:
return []

def __create_activity_dto(self, activity: dict) -> Activity:
activity = {key: activity.get(key) for key in self.activity_keys}
return Activity(**activity)
11 changes: 11 additions & 0 deletions V2/source/dtos/activity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from dataclasses import dataclass


@dataclass(frozen=True)
class Activity:
id: str
name: str
description: str
deleted: str
status: str
tenant_id: str
14 changes: 14 additions & 0 deletions V2/source/services/activity_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from V2.source.daos.activities_dao import ActivitiesDao
from V2.source.dtos.activity import Activity
import typing


class ActivityService:
def __init__(self, activities_dao: ActivitiesDao):
self.activities_dao = activities_dao

def get_by_id(self, activity_id: str) -> Activity:
return self.activities_dao.get_by_id(activity_id)

def get_all(self) -> typing.List[Activity]:
return self.activities_dao.get_all()
85 changes: 85 additions & 0 deletions V2/tests/daos/activities_json_dao_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from V2.source.daos.activities_json_dao import ActivitiesJsonDao
from V2.source.dtos.activity import Activity
from faker import Faker
import json
import pytest
import typing


@pytest.fixture(name='create_fake_activities')
def _create_fake_activities(mocker) -> typing.List[Activity]:
def _creator(activities):
read_data = json.dumps(activities)
mocker.patch('builtins.open', mocker.mock_open(read_data=read_data))
return [Activity(**activity) for activity in activities]

return _creator


def test_get_by_id__returns_an_activity_dto__when_found_one_activity_that_matches_its_id(
create_fake_activities,
):
activities_json_dao = ActivitiesJsonDao(Faker().file_path())
activities = create_fake_activities(
[
{
"name": "test_name",
"description": "test_description",
"tenant_id": "test_tenant_id",
"id": "test_id",
"deleted": "test_deleted",
"status": "test_status",
}
]
)
activity_dto = activities.pop()

result = activities_json_dao.get_by_id(activity_dto.id)

assert result == activity_dto


def test__get_by_id__returns_none__when_no_activity_matches_its_id(
create_fake_activities,
):
activities_json_dao = ActivitiesJsonDao(Faker().file_path())
create_fake_activities([])

result = activities_json_dao.get_by_id(Faker().uuid4())

assert result == None


def test__get_all__returns_a_list_of_activity_dto_objects__when_one_or_more_activities_are_found(
create_fake_activities,
):
activities_json_dao = ActivitiesJsonDao(Faker().file_path())
number_of_activities = 3
activities = create_fake_activities(
[
{
"name": "test_name",
"description": "test_description",
"tenant_id": "test_tenant_id",
"id": "test_id",
"deleted": "test_deleted",
"status": "test_status",
}
]
* number_of_activities
)

result = activities_json_dao.get_all()

assert result == activities


def test_get_all__returns_an_empty_list__when_doesnt_found_any_activities(
create_fake_activities,
):
activities_json_dao = ActivitiesJsonDao(Faker().file_path())
activities = create_fake_activities([])

result = activities_json_dao.get_all()

assert result == activities
28 changes: 28 additions & 0 deletions V2/tests/services/activity_service_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from V2.source.services.activity_service import ActivityService
from faker import Faker


def test__get_all__uses_the_activity_dao__to_retrieve_activities(mocker):
expected_activities = mocker.Mock()
activity_dao = mocker.Mock(
get_all=mocker.Mock(return_value=expected_activities)
)
activity_service = ActivityService(activity_dao)

actual_activities = activity_service.get_all()

assert activity_dao.get_all.called
assert expected_activities == actual_activities


def test__get_by_id__uses_the_activity_dao__to_retrieve_one_activity(mocker):
expected_activity = mocker.Mock()
activity_dao = mocker.Mock(
get_by_id=mocker.Mock(return_value=expected_activity)
)
activity_service = ActivityService(activity_dao)

actual_activity = activity_service.get_by_id(Faker().uuid4())

assert activity_dao.get_by_id.called
assert expected_activity == actual_activity