Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1065bde
feat: TT-353 Create V2 Activities DAO
Sep 24, 2021
3bb39b0
refactor: TT-353 Solving code smells from SonarCloud
Sep 24, 2021
b15c301
refactor: TT-353 Solving duplicated literal
Sep 24, 2021
7a2565c
refactor: TT-353 Add type of argument and return type to functions
Sep 27, 2021
8bdbdfe
refactor: TT-353 Solving comments from PR
Sep 29, 2021
bc998fe
refactor: TT-353 Solving Sonarcloud code smell
Sep 29, 2021
9d0e21e
refactor: TT-353 Changing variable names and tests
Sep 29, 2021
4c467c7
feat: TT-352 Create entry point and use case to get activities
JosueOb Sep 30, 2021
408c016
feat: TT-352 Create entry point and use case to get activity
JosueOb Sep 30, 2021
a936f0a
refactor: TT-352 use list comprehensions
JosueOb Sep 30, 2021
47bb34b
refactor: TT-352 standarization flask_api directory
JosueOb Sep 30, 2021
1f92569
refactor: TT-353 Solving requested changes on PR
Sep 30, 2021
2ce4987
refactor: TT-352 use_cases and entry_points improvements to read acti…
JosueOb Sep 30, 2021
361a864
Merge branch 'TT-353-Create-V2-Activities-DAO' into TT-352-Create-V2-…
JosueOb Sep 30, 2021
bb87c54
test: TT-352 Unit test of activity use cases
JosueOb Oct 4, 2021
1006410
test: TT-352 entry_points and use_cases for activities complete testing
JosueOb Oct 6, 2021
39f5221
refactor: TT-352 solving merge conflicts
JosueOb Oct 6, 2021
9539885
code-smell: TT-352 fixing code-smell
JosueOb Oct 6, 2021
9e090bc
build: TT-352 implementation of CSRF Protection using Flask-WTF
JosueOb Oct 6, 2021
b0cc467
refactor: TT-352 improving use_cases, endpoitns and test to get activ…
JosueOb Oct 6, 2021
13133d1
test: TT-352 improved testing of activity use cases
JosueOb Oct 7, 2021
7b582b7
refactor: TT-352 improvement of endpoint testing for obtaining activi…
JosueOb Oct 8, 2021
a2d912c
refactor: TT-352 refactoring of the use case and endpoint to obtain a…
JosueOb Oct 12, 2021
b4987e6
refactor: TT-352 refactoring of use cases and enpoint to obtain activ…
JosueOb Oct 12, 2021
4866913
test: TT-352 refactoring of use cases and enpoint to obtain activities
JosueOb Oct 12, 2021
fd84ea1
refactor: TT-352 refactoring of activity endpoints
JosueOb Oct 13, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
12 changes: 0 additions & 12 deletions V2/source/daos/activities_dao_interface.py

This file was deleted.

56 changes: 24 additions & 32 deletions V2/source/daos/activities_json_dao.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,35 @@
from V2.source.daos.activities_dao_interface import ActivitiesDaoInterface
from V2.source.dtos.activity import ActivityDto
from http import HTTPStatus
from V2.source.daos.activities_dao import ActivitiesDao
from V2.source.dtos.activity import Activity
import json
import typing


Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Siempre deben quedar dos líneas entre los imports y las clases o funciones de acuerdo a PEP 8. Creo que estaba bien

class ActivitiesJsonDao(ActivitiesDaoInterface):
class ActivitiesJsonDao(ActivitiesDao):
def __init__(self, json_data_file_path: str):
self.json_data_file_path = json_data_file_path
self.activity_keys = ActivityDto.__dataclass_fields__.keys()

def get_by_id(self, id: str) -> ActivityDto:
activities = self.__get_activities_from_file()

try:
activity = next(
(
activity
for activity in activities
if activity.get('id') == id
)
)
except Exception:
return HTTPStatus.NOT_FOUND

activity_dto = self.__create_activity_dto(activity)
self.activity_keys = Activity.__dataclass_fields__.keys()

def get_by_id(self, activity_id: str) -> Activity:
activities_grouped_by_id = {
activity.get('id'): activity
for activity in self.__get_activities_from_file()
}
activity = activities_grouped_by_id.get(activity_id)
activity_dto = (
self.__create_activity_dto(activity) if activity else None
)

return activity_dto

def get_all(self) -> list:
activities = self.__get_activities_from_file()
list_activities = []

for activity in activities:
activity = self.__create_activity_dto(activity)
list_activities.append(activity)
def get_all(self) -> typing.List[Activity]:
all_activities = self.__get_activities_from_file()
activity_dtos = [
self.__create_activity_dto(activity) for activity in all_activities
]

return list_activities
return activity_dtos

def __get_activities_from_file(self) -> list:
def __get_activities_from_file(self) -> typing.List[dict]:
try:
file = open(self.json_data_file_path)
activities = json.load(file)
Expand All @@ -48,7 +40,7 @@ def __get_activities_from_file(self) -> list:
except FileNotFoundError:
return []

def __create_activity_dto(self, activity: dict) -> ActivityDto:
def __create_activity_dto(self, activity: dict) -> Activity:
activity = {key: activity.get(key) for key in self.activity_keys}
activity_dto = ActivityDto(**activity)
activity_dto = Activity(**activity)
return activity_dto
2 changes: 1 addition & 1 deletion V2/source/dtos/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


@dataclass(frozen=True)
class ActivityDto:
class Activity:
id: str
name: str
description: str
Expand Down
17 changes: 8 additions & 9 deletions V2/source/services/activity_service.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
from V2.source.daos.activities_dao_interface import ActivitiesDaoInterface
from V2.source.dtos.activity import ActivityDto
from V2.source.daos.activities_dao import ActivitiesDao
from V2.source.dtos.activity import Activity
import typing


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

def get_by_id(self, id: str) -> ActivityDto:
activity_dto = self.activities_dao.get_by_id(id)
return activity_dto
def get_by_id(self, activity_id: str) -> Activity:
return self.activities_dao.get_by_id(activity_id)

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


OPEN_FILE = 'builtins.open'
@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__return_activity_dto__when_find_activity_that_matches_its_id(
mocker,

def test_get_by_id__returns_an_activity_dto__when_found_one_activity_that_matches_its_id(
create_fake_activities,
):
activities_json_dao = ActivitiesJsonDao('non-important-path')
activities = [
{
"name": "test_name",
"description": "test_description",
"tenant_id": "test_tenant_id",
"id": "test_id",
"deleted": "test_deleted",
"status": "test_status",
}
]
read_data = json.dumps(activities)
activity_dto = ActivityDto(**activities.pop())

mocker.patch(OPEN_FILE, mocker.mock_open(read_data=read_data))
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__return_httpstatus_not_found__when_no_activity_matches_its_id(
mocker,
def test__get_by_id__returns_none__when_no_activity_matches_its_id(
create_fake_activities,
):
activities_json_dao = ActivitiesJsonDao('non-important-path')
activities = []
read_data = json.dumps(activities)
activities_json_dao = ActivitiesJsonDao(Faker().file_path())
create_fake_activities([])

mocker.patch(OPEN_FILE, mocker.mock_open(read_data=read_data))
result = activities_json_dao.get_by_id('non-important-id')
result = activities_json_dao.get_by_id(Faker().uuid4())

assert result == HTTPStatus.NOT_FOUND
assert result == None


def test_get_all__return_list_of_activity_dto__when_find_one_or_more_activities(
mocker,
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('non-important-path')
activity = {
"name": "test_name",
"description": "test_description",
"tenant_id": "test_tenant_id",
"id": "test_id",
"deleted": "test_deleted",
"status": "test_status",
}
activities_json_dao = ActivitiesJsonDao(Faker().file_path())
number_of_activities = 3
activity_dto = ActivityDto(**activity)
list_activities_dto = [activity_dto] * number_of_activities
activities = [activity] * number_of_activities
read_data = json.dumps(activities)
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
)

mocker.patch(OPEN_FILE, mocker.mock_open(read_data=read_data))
result = activities_json_dao.get_all()

assert result == list_activities_dto
assert result == activities


def test_get_all__return_empty_list__when_doesnt_found_any_activities(mocker):
activities_json_dao = ActivitiesJsonDao('non-important-path')
activities = []
read_data = json.dumps(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([])

mocker.patch(OPEN_FILE, mocker.mock_open(read_data=read_data))
result = activities_json_dao.get_all()

assert result == activities
88 changes: 17 additions & 71 deletions V2/tests/services/activity_service_test.py
Original file line number Diff line number Diff line change
@@ -1,82 +1,28 @@
from V2.source.services.activity_service import ActivityService
from V2.source.daos.activities_dao_interface import ActivitiesDaoInterface
from V2.source.dtos.activity import ActivityDto
from http import HTTPStatus
from faker import Faker


def test__get_by_id__return_activity_dto__when_find_activity_that_matches_its_id(
mocker,
):
activity_service = ActivityService(ActivitiesDaoInterface)
activity = {
"name": "test_name",
"description": "test_description",
"tenant_id": "test_tenant_id",
"id": "test_id",
"deleted": "test_deleted",
"status": "test_status",
}
activity_dto = ActivityDto(**activity)

activities_dao_mock = mocker.patch.object(
ActivitiesDaoInterface, 'get_by_id'
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)
)
activities_dao_mock.return_value = activity_dto
result = activity_service.get_by_id(activity.get('id'))
activity_service = ActivityService(activity_dao)

assert result == activity_dto
actual_activities = activity_service.get_all()

assert activity_dao.get_all.called
assert expected_activities == actual_activities

def test__get_by_id__return_httpstatus_not_found__when_no_activity_matches_its_id(
mocker,
):
activity_service = ActivityService(ActivitiesDaoInterface)

activities_dao_mock = mocker.patch.object(
ActivitiesDaoInterface, 'get_by_id'
def test__get_by_id__uses_the_activity_dao__to_retrieve_one_ativity(mocker):
expected_activity = mocker.Mock()
activity_dao = mocker.Mock(
get_by_id=mocker.Mock(return_value=expected_activity)
)
activities_dao_mock.return_value = HTTPStatus.NOT_FOUND

result = activity_service.get_by_id('non-important-id')

assert result == HTTPStatus.NOT_FOUND
activity_service = ActivityService(activity_dao)

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

def test__get_all__return_list_of_activity_dto__when_find_one_or_more_activities(
mocker,
):
activity_service = ActivityService(ActivitiesDaoInterface)
activity = {
"name": "test_name",
"description": "test_description",
"tenant_id": "test_tenant_id",
"id": "test_id",
"deleted": "test_deleted",
"status": "test_status",
}
number_of_activities = 3
activity_dto = ActivityDto(**activity)
list_activities_dto = [activity_dto] * number_of_activities

activities_dao_mock = mocker.patch.object(
ActivitiesDaoInterface, 'get_all'
)
activities_dao_mock.return_value = list_activities_dto
result = activity_service.get_all()

assert result == list_activities_dto


def test__get_all__return_empty_list__when_doesnt_found_any_activities(
mocker,
):
activity_service = ActivityService(ActivitiesDaoInterface)
activities = []

activities_dao_mock = mocker.patch.object(
ActivitiesDaoInterface, 'get_all'
)
activities_dao_mock.return_value = activities
result = activity_service.get_all()

assert result == activities
assert activity_dao.get_by_id.called
assert expected_activity == actual_activity