Skip to content

Commit 42cfc46

Browse files
committed
feat: TT-401 validated request create time entry
1 parent 9311ce4 commit 42cfc46

File tree

24 files changed

+233
-260
lines changed

24 files changed

+233
-260
lines changed

V2/tests/api/api_fixtures.py

Lines changed: 0 additions & 80 deletions
This file was deleted.

V2/tests/api/azure/time_entry_azure_endpoints_test.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ def test__time_entry_azure_endpoint__creates_an_time_entry__when_time_entry_has_
1515
time_entries._create_time_entry._JSON_PATH = tmp_directory
1616

1717
time_entry_body = {
18-
"id" : None,
19-
"start_date" : Faker().date(),
20-
"owner_id" : Faker().random_int(),
18+
"id": None,
19+
"start_date": Faker().date(),
20+
"owner_id": Faker().random_int(),
2121
"description": Faker().sentence(),
22-
"activity_id" : Faker().random_int(),
22+
"activity_id": Faker().random_int(),
2323
"uri": "http://timetracker.com",
24-
"technologies" : ["jira","git"],
24+
"technologies": ["jira", "git"],
2525
"end_date": Faker().date(),
26-
"deleted": Faker().random_int(),
26+
"deleted": False,
2727
"timezone_offset": "300",
2828
"project_id": Faker().random_int(),
2929
}

V2/tests/conftest.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# flake8: noqa
2-
from tests.api.api_fixtures import create_temp_activities
3-
from tests.api.api_fixtures import create_temp_time_entries
2+
from fixtures import create_temp_activities
3+
from fixtures import create_temp_time_entries
4+
from fixtures import _time_entry_factory

V2/tests/fixtures.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import json
2+
import pytest
3+
import shutil
4+
from faker import Faker
5+
6+
from time_tracker.time_entries._domain import TimeEntry
7+
8+
9+
@pytest.fixture
10+
def create_temp_activities(tmpdir_factory):
11+
temporary_directory = tmpdir_factory.mktemp("tmp")
12+
json_file = temporary_directory.join("activities.json")
13+
activities = [
14+
{
15+
'id': 'c61a4a49-3364-49a3-a7f7-0c5f2d15072b',
16+
'name': 'Development',
17+
'description': 'Development',
18+
'deleted': 'b4327ba6-9f96-49ee-a9ac-3c1edf525172',
19+
'status': 'active',
20+
'tenant_id': 'cc925a5d-9644-4a4f-8d99-0bee49aadd05',
21+
},
22+
{
23+
'id': '94ec92e2-a500-4700-a9f6-e41eb7b5507c',
24+
'name': 'Management',
25+
'description': 'Description of management',
26+
'deleted': '7cf6efe5-a221-4fe4-b94f-8945127a489a',
27+
'status': 'active',
28+
'tenant_id': 'cc925a5d-9644-4a4f-8d99-0bee49aadd05',
29+
},
30+
{
31+
'id': 'd45c770a-b1a0-4bd8-a713-22c01a23e41b',
32+
'name': 'Operations',
33+
'description': 'Operation activities performed.',
34+
'deleted': '7cf6efe5-a221-4fe4-b94f-8945127a489a',
35+
'status': 'active',
36+
'tenant_id': 'cc925a5d-9644-4a4f-8d99-0bee49aadd05',
37+
},
38+
]
39+
40+
with open(json_file, 'w') as outfile:
41+
json.dump(activities, outfile)
42+
43+
yield activities, json_file
44+
shutil.rmtree(temporary_directory)
45+
46+
47+
@pytest.fixture
48+
def create_temp_time_entries(tmpdir_factory):
49+
temporary_directory = tmpdir_factory.mktemp("tmp")
50+
json_file = temporary_directory.join("time_entries.json")
51+
time_entries = [
52+
{
53+
"id": Faker().random_int(),
54+
"start_date": Faker().date(),
55+
"owner_id": Faker().random_int(),
56+
"description": Faker().sentence(),
57+
"activity_id": Faker().random_int(),
58+
"uri": "http://time-tracker.com",
59+
"technologies": ["jira", "git"],
60+
"end_date": Faker().date(),
61+
"deleted": Faker().random_int(),
62+
"timezone_offset": "300",
63+
"project_id": Faker().random_int(),
64+
},
65+
{
66+
"id": Faker().random_int(),
67+
"start_date": Faker().date(),
68+
"owner_id": Faker().random_int(),
69+
"description": Faker().sentence(),
70+
"activity_id": Faker().random_int(),
71+
"uri": "http://time-tracker.com",
72+
"technologies": ["jira", "git"],
73+
"end_date": Faker().date(),
74+
"deleted": Faker().random_int(),
75+
"timezone_offset": "300",
76+
"project_id": Faker().random_int(),
77+
},
78+
]
79+
80+
with open(json_file, 'w') as outfile:
81+
json.dump(time_entries, outfile)
82+
83+
yield time_entries, json_file
84+
shutil.rmtree(temporary_directory)
85+
86+
87+
@pytest.fixture(name='time_entry_factory')
88+
def _time_entry_factory() -> TimeEntry:
89+
def _make_time_entry(
90+
id=Faker().random_int(),
91+
start_date=Faker().date(),
92+
owner_id=Faker().random_int(),
93+
description=Faker().sentence(),
94+
activity_id=Faker().random_int(),
95+
uri="http://time-tracker.com",
96+
technologies=["jira", "git"],
97+
end_date=Faker().date(),
98+
deleted=Faker().random_int(),
99+
timezone_offset="300",
100+
project_id=Faker().random_int(),
101+
):
102+
time_entry = TimeEntry(
103+
id=id,
104+
start_date=start_date,
105+
owner_id=owner_id,
106+
description=description,
107+
activity_id=activity_id,
108+
uri=uri,
109+
technologies=technologies,
110+
end_date=end_date,
111+
deleted=deleted,
112+
timezone_offset=timezone_offset,
113+
project_id=project_id,
114+
)
115+
return time_entry
116+
return _make_time_entry

V2/tests/integration/daos/time_entries_dao.test.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,17 @@ def test_create_time_entry__returns_an_time_entry_dto__when_create_an_time_entry
2525

2626
time_entries_json_dao = TimeEntriesJsonDao(Faker().file_path())
2727
time_entry_data = {
28-
"id" : None,
29-
"start_date" : Faker().date(),
30-
"owner_id" : Faker().random_int(),
28+
"id": None,
29+
"start_date": Faker().date(),
30+
"owner_id": Faker().random_int(),
3131
"description": Faker().sentence(),
32-
"activity_id" : Faker().random_int(),
33-
"uri": "http://hola.com",
34-
"technologies" : ["jira","git"],
32+
"activity_id": Faker().random_int(),
33+
"uri": "http://timetracker.com",
34+
"technologies": ["jira", "git"],
3535
"end_date": Faker().date(),
36-
"deleted": Faker().random_int(),
37-
"timezone_offset": "UTC-5",
36+
"deleted": False,
37+
"timezone_offset": "300",
3838
"project_id": Faker().random_int(),
3939
}
4040
result = time_entries_json_dao.create(time_entry_data)
4141
assert result == TimeEntry(**time_entry_data)
42-
43-
44-
45-

V2/tests/unit/services/time_entry_service_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from time_tracker.time_entries._domain import TimeEntryService
44

5+
56
def test__create_time_entries__uses_the_time_entry_dao__to_create_an_time_entry(mocker):
67
expected_time_entry = mocker.Mock()
78
time_entry_dao = mocker.Mock(
@@ -12,4 +13,4 @@ def test__create_time_entries__uses_the_time_entry_dao__to_create_an_time_entry(
1213
actual_time_entry = time_entry_service.create(Faker().pydict())
1314

1415
assert time_entry_dao.create.called
15-
assert expected_time_entry == actual_time_entry
16+
assert expected_time_entry == actual_time_entry
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
1-
from faker import Faker
2-
31
from pytest_mock import MockFixture
42

53
from time_tracker.time_entries._domain import _use_cases
64

5+
76
def test__create_time_entry_function__uses_the_time_entries_service__to_create_time_entry(
8-
mocker: MockFixture,
7+
mocker: MockFixture, time_entry_factory
98
):
109
expected_time_entry = mocker.Mock()
1110
time_entry_service = mocker.Mock(
1211
create=mocker.Mock(return_value=expected_time_entry)
1312
)
1413

1514
time_entry_use_case = _use_cases.CreateTimeEntryUseCase(time_entry_service)
16-
actual_time_entry = time_entry_use_case.create_time_entry(Faker().pydict())
15+
actual_time_entry = time_entry_use_case.create_time_entry(time_entry_factory())
1716

1817
assert time_entry_service.create.called
1918
assert expected_time_entry == actual_time_entry
20-
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
# flake8: noqa
12
from ._time_entries import create_time_entry
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
# flake8: noqa
12
from ._create_time_entry import create_time_entry

V2/time_tracker/time_entries/_application/_time_entries/_create_time_entry.py

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,42 +8,59 @@
88
from ... import _infrastructure
99

1010
_JSON_PATH = (
11-
'time_entries/_infrastructure/_data_persistence/time_entries_data.json'
11+
'time_tracker/time_entries/_infrastructure/_data_persistence/time_entries_data.json'
1212
)
1313

14+
1415
def create_time_entry(req: func.HttpRequest) -> func.HttpResponse:
1516

16-
time_entry_dao = _infrastructure.TimeEntriesJsonDao(_JSON_PATH)
17-
time_entry_service = _domain.TimeEntryService(time_entry_dao)
18-
use_case = _domain._use_cases.CreateTimeEntryUseCase(time_entry_service)
19-
20-
time_entry_data = req.get_json()
21-
22-
time_entry_to_create = _domain.TimeEntry(
23-
id=None,
24-
start_date=time_entry_data["start_date"],
25-
owner_id=time_entry_data["owner_id"],
26-
description=time_entry_data["description"],
27-
activity_id=time_entry_data["activity_id"],
28-
uri=time_entry_data["uri"],
29-
technologies=time_entry_data["technologies"],
30-
end_date=time_entry_data["end_date"],
31-
deleted=time_entry_data["deleted"],
32-
timezone_offset=time_entry_data["timezone_offset"],
33-
project_id=time_entry_data["project_id"]
34-
)
35-
36-
created_time_entry = use_case.create_time_entry(time_entry_to_create.__dict__)
37-
38-
if not created_time_entry:
17+
time_entry_dao = _infrastructure.TimeEntriesJsonDao(_JSON_PATH)
18+
time_entry_service = _domain.TimeEntryService(time_entry_dao)
19+
use_case = _domain._use_cases.CreateTimeEntryUseCase(time_entry_service)
20+
21+
time_entry_data = req.get_json()
22+
23+
validation_errors = _validate_time_entry(time_entry_data)
24+
if validation_errors:
25+
return func.HttpResponse(
26+
body=json.dumps(validation_errors), status_code=400, mimetype="application/json"
27+
)
28+
29+
time_entry_to_create = _domain.TimeEntry(
30+
id=None,
31+
start_date=time_entry_data["start_date"],
32+
owner_id=time_entry_data["owner_id"],
33+
description=time_entry_data["description"],
34+
activity_id=time_entry_data["activity_id"],
35+
uri=time_entry_data["uri"],
36+
technologies=time_entry_data["technologies"],
37+
end_date=time_entry_data["end_date"],
38+
deleted=False,
39+
timezone_offset=time_entry_data["timezone_offset"],
40+
project_id=time_entry_data["project_id"]
41+
)
42+
43+
created_time_entry = use_case.create_time_entry(time_entry_to_create)
44+
45+
if not created_time_entry:
46+
return func.HttpResponse(
47+
body=json.dumps({'error': 'time_entry could not be created'}),
48+
status_code=500,
49+
mimetype="application/json"
50+
)
51+
3952
return func.HttpResponse(
40-
body=json.dumps({'error': 'time_entry could not be created'}),
41-
status_code=500,
53+
body=json.dumps(created_time_entry.__dict__),
54+
status_code=201,
4255
mimetype="application/json"
4356
)
4457

45-
return func.HttpResponse(
46-
body=json.dumps(created_time_entry.__dict__),
47-
status_code=201,
48-
mimetype="application/json"
49-
)
58+
59+
def _validate_time_entry(time_entry_data: dict) -> typing.List[str]:
60+
time_entry_fields = [field.name for field in dataclasses.fields(_domain.TimeEntry)]
61+
time_entry_fields.pop(8)
62+
missing_keys = [field for field in time_entry_fields if field not in time_entry_data]
63+
return [
64+
f'The {missing_key} key is missing in the input data'
65+
for missing_key in missing_keys
66+
]

0 commit comments

Comments
 (0)