Skip to content

Commit 822b925

Browse files
committed
feat: TT-404 get time entries
1 parent 5f107f3 commit 822b925

File tree

23 files changed

+378
-21
lines changed

23 files changed

+378
-21
lines changed

V2/serverless.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,13 @@ functions:
8686
- POST
8787
route: time-entries/
8888
authLevel: anonymous
89+
90+
get_time_entries:
91+
handler: time_tracker/time_entries/interface.get_time_entries
92+
events:
93+
- http: true
94+
x-azure-settings:
95+
methods:
96+
- GET
97+
route: time_entries/{id:?}
98+
authLevel: anonymous

V2/tests/api/azure/time_entry_azure_endpoints_test.py

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
import json
2+
import pytest
23

34
import azure.functions as func
45

56
import time_tracker.time_entries._application._time_entries as azure_time_entries
7+
import time_tracker.time_entries._infrastructure as infrastructure
8+
from time_tracker._infrastructure import DB
9+
from time_tracker.time_entries import _domain
610

7-
TIME_ENTRY_URL = "/api/time-entries/"
11+
TIME_ENTRY_URL = "/api/time_entries/"
812

913

14+
@pytest.fixture(name='insert_time_entry')
15+
def _insert_time_entry() -> _domain.TimeEntry:
16+
def _new_time_entry(time_entry: _domain.TimeEntry, database: DB):
17+
dao = infrastructure.TimeEntriesSQLDao(database)
18+
new_time_entry = dao.create(time_entry)
19+
return new_time_entry.__dict__
20+
return _new_time_entry
21+
1022
def test__time_entry_azure_endpoint__creates_an_time_entry__when_time_entry_has_all_attributes(
1123
test_db, time_entry_factory, activity_factory, insert_activity
1224
):
@@ -26,3 +38,66 @@ def test__time_entry_azure_endpoint__creates_an_time_entry__when_time_entry_has_
2638

2739
assert response.status_code == 201
2840
assert time_entry_json_data == time_entry_body
41+
42+
def test__time_entry_azure_endpoint__returns_all_time_entries(
43+
create_fake_database, time_entry_factory, insert_time_entry, activity_factory, insert_activity
44+
):
45+
fake_database = create_fake_database
46+
inserted_activity = insert_activity(activity_factory(), fake_database)
47+
existent_time_entries = time_entry_factory(activity_id=inserted_activity.id, technologies="[jira,sql]")
48+
inserted_time_entries = [insert_time_entry(existent_time_entries, fake_database)]
49+
50+
azure_time_entries._get_time_entries.DATABASE = fake_database
51+
req = func.HttpRequest(method="GET", body=None, url=TIME_ENTRY_URL)
52+
53+
response = azure_time_entries.get_time_entries(req)
54+
time_entries_json_data = response.get_body().decode("utf-8")
55+
56+
assert response.status_code == 200
57+
assert time_entries_json_data == json.dumps(inserted_time_entries)
58+
59+
60+
def test__time_entry_azure_endpoint__returns_an_time_entry__when_time_entry_matches_its_id(
61+
create_fake_database, time_entry_factory, insert_time_entry, activity_factory, insert_activity
62+
):
63+
fake_database = create_fake_database
64+
inserted_activity = insert_activity(activity_factory(), fake_database)
65+
existent_time_entries = time_entry_factory(activity_id=inserted_activity.id, technologies="[jira,sql]")
66+
inserted_time_entries = insert_time_entry(existent_time_entries, fake_database)
67+
68+
azure_time_entries._get_time_entries.DATABASE = fake_database
69+
70+
req = func.HttpRequest(
71+
method="GET",
72+
body=None,
73+
url=TIME_ENTRY_URL,
74+
route_params={"id": inserted_time_entries["id"]},
75+
)
76+
77+
response = azure_time_entries.get_time_entries(req)
78+
time_entry_json_data = response.get_body().decode("utf-8")
79+
80+
assert response.status_code == 200
81+
assert time_entry_json_data == json.dumps(inserted_time_entries)
82+
83+
84+
def test__get_time_entries_azure_endpoint__returns_a_status_code_400__when_time_entry_recive_invalid_id(
85+
create_fake_database, time_entry_factory, insert_time_entry, activity_factory, insert_activity
86+
):
87+
fake_database = create_fake_database
88+
inserted_activity = insert_activity(activity_factory(), fake_database)
89+
existent_time_entries = time_entry_factory(activity_id=inserted_activity.id, technologies="[jira,sql]")
90+
insert_time_entry(existent_time_entries, fake_database)
91+
92+
azure_time_entries._get_time_entries.DATABASE = fake_database
93+
req = func.HttpRequest(
94+
method="GET",
95+
body=None,
96+
url=TIME_ENTRY_URL,
97+
route_params={"id": "invalid id"},
98+
)
99+
100+
response = azure_time_entries.get_time_entries(req)
101+
102+
assert response.status_code == 400
103+
assert response.get_body() == b'Invalid Format ID'

V2/tests/conftest.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
# flake8: noqa
2-
from fixtures import _activity_factory, _test_db, _insert_activity
3-
from fixtures import _time_entry_factory
2+
from fixtures import _activity_factory, _test_db, _create_fake_database, _create_fake_dao, _time_entry_factory,_insert_activity

V2/tests/fixtures.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import pytest
22
from faker import Faker
33

4-
import time_tracker.activities._domain as activities_domain
5-
import time_tracker.activities._infrastructure as activities_infrastructure
6-
import time_tracker.time_entries._domain as time_entries_domain
4+
import time_tracker.activities._domain as domain_activities
5+
import time_tracker.activities._infrastructure as infrastructure_activities
6+
import time_tracker.time_entries._domain as domain_time_entries
77
from time_tracker._infrastructure import DB
88

99

1010
@pytest.fixture(name='activity_factory')
11-
def _activity_factory() -> activities_domain.Activity:
11+
def _activity_factory() -> domain_activities.Activity:
1212
def _make_activity(
1313
name: str = Faker().name(), description: str = Faker().sentence(), deleted: bool = False, status: int = 1
1414
):
15-
activity = activities_domain.Activity(
15+
activity = domain_activities.Activity(
1616
id=None,
1717
name=name,
1818
description=description,
@@ -29,9 +29,21 @@ def _test_db() -> DB:
2929
db_fake.get_session().execute("pragma foreign_keys=ON")
3030
return db_fake
3131

32+
@pytest.fixture(name='create_fake_dao')
33+
def _create_fake_dao() -> domain_activities.ActivitiesDao:
34+
db_fake = DB('sqlite:///:memory:')
35+
dao = infrastructure_activities.ActivitiesSQLDao(db_fake)
36+
return dao
37+
38+
39+
@pytest.fixture(name='create_fake_database')
40+
def _create_fake_database() -> DB:
41+
db_fake = DB('sqlite:///:memory:')
42+
return db_fake
43+
3244

3345
@pytest.fixture(name='time_entry_factory')
34-
def _time_entry_factory() -> time_entries_domain.TimeEntry:
46+
def _time_entry_factory() -> domain_time_entries.TimeEntry:
3547
def _make_time_entry(
3648
id=Faker().random_int(),
3749
start_date=str(Faker().date_time()),
@@ -45,7 +57,7 @@ def _make_time_entry(
4557
timezone_offset="300",
4658
project_id=Faker().random_int(),
4759
):
48-
time_entry = time_entries_domain.TimeEntry(
60+
time_entry = domain_time_entries.TimeEntry(
4961
id=id,
5062
start_date=start_date,
5163
owner_id=owner_id,
@@ -64,8 +76,8 @@ def _make_time_entry(
6476

6577
@pytest.fixture(name='insert_activity')
6678
def _insert_activity() -> dict:
67-
def _new_activity(activity: activities_domain.Activity, database: DB):
68-
dao = activities_infrastructure.ActivitiesSQLDao(database)
79+
def _new_activity(activity: domain_activities.Activity, database: DB):
80+
dao = infrastructure_activities.ActivitiesSQLDao(database)
6981
new_activity = dao.create(activity)
7082
return new_activity
7183
return _new_activity
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import pytest
2+
import typing
3+
4+
from faker import Faker
5+
6+
import time_tracker.activities._infrastructure as infrastructure_activities
7+
8+
from time_tracker.time_entries._infrastructure import TimeEntriesSQLDao
9+
from time_tracker.time_entries._domain import TimeEntry
10+
11+
from time_tracker._infrastructure import DB
12+
13+
14+
@pytest.fixture(name='create_time_enty_fake_dao')
15+
def _create_fake_dao() -> TimeEntriesSQLDao:
16+
db_fake = DB('sqlite:///:memory:')
17+
dao = TimeEntriesSQLDao(db_fake)
18+
return dao
19+
20+
21+
@pytest.fixture(name='clean_database', autouse=True)
22+
def _clean_database():
23+
yield
24+
db_fake = DB('sqlite:///:memory:')
25+
dao = infrastructure_activities.ActivitiesSQLDao(db_fake)
26+
query = dao.activity.delete()
27+
dao.db.get_session().execute(query)
28+
29+
30+
def test__get_all__returns_a_list_of_time_entries_dto_objects__when_one_or_more_time_entries_are_found_in_sql_database(
31+
create_time_enty_fake_dao, time_entry_factory, insert_activity, activity_factory
32+
):
33+
34+
dao = create_time_enty_fake_dao
35+
inserted_activity = insert_activity(activity_factory(), dao.db)
36+
existent_time_entries = time_entry_factory(activity_id=inserted_activity.id, technologies="[jira,sql]")
37+
inserted_time_entries = [dao.create(existent_time_entries)]
38+
39+
time_entry = dao.get_all()
40+
41+
assert isinstance(time_entry, typing.List)
42+
assert time_entry == inserted_time_entries
43+
44+
45+
def test__get_all__returns_an_empty_list__when_doesnt_found_any_time_entries_in_sql_database(
46+
create_time_enty_fake_dao, insert_activity, activity_factory
47+
):
48+
dao = create_time_enty_fake_dao
49+
insert_activity(activity_factory(), dao.db)
50+
51+
time_entry = dao.get_all()
52+
assert time_entry == []
53+
54+
55+
def test__get_by_id__returns_a_time_entry_dto__when_found_one_time_entry_that_match_id_with_sql_database(
56+
create_time_enty_fake_dao, time_entry_factory, insert_activity, activity_factory
57+
):
58+
dao = create_time_enty_fake_dao
59+
inserted_activity = insert_activity(activity_factory(), dao.db)
60+
existent_time_entries = time_entry_factory(activity_id=inserted_activity.id, technologies="[jira,sql]")
61+
inserted_time_entries = dao.create(existent_time_entries)
62+
63+
time_entry = dao.get_by_id(existent_time_entries.id)
64+
65+
assert isinstance(time_entry, TimeEntry)
66+
assert time_entry.id == inserted_time_entries.id
67+
assert time_entry == inserted_time_entries
68+
69+
70+
def test__get_by_id__returns_none__when_no_time_entry_matches_by_id(
71+
create_time_enty_fake_dao, time_entry_factory, insert_activity, activity_factory
72+
):
73+
dao = create_time_enty_fake_dao
74+
inserted_activity = insert_activity(activity_factory(), dao.db)
75+
existent_time_entries = time_entry_factory(activity_id=inserted_activity.id, technologies="[jira,sql]")
76+
dao.create(existent_time_entries)
77+
78+
time_entry = dao.get_by_id(Faker().pyint())
79+
80+
assert time_entry is None

V2/tests/unit/services/time_entry_service_test.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from faker import Faker
2+
13
from time_tracker.time_entries._domain import TimeEntryService
24

35

@@ -12,3 +14,29 @@ def test__create_time_entries__uses_the_time_entry_dao__to_create_an_time_entry(
1214

1315
assert time_entry_dao.create.called
1416
assert expected_time_entry == actual_time_entry
17+
18+
19+
def test__get_all__uses_the_time_entry_dao__to_retrieve_time_entries(mocker):
20+
expected_time_entries = mocker.Mock()
21+
time_entry_dao = mocker.Mock(
22+
get_all=mocker.Mock(return_value=expected_time_entries)
23+
)
24+
time_activity_service = TimeEntryService(time_entry_dao)
25+
26+
actual_activities = time_activity_service.get_all()
27+
28+
assert time_entry_dao.get_all.called
29+
assert expected_time_entries == actual_activities
30+
31+
32+
def test__get_by_id__uses_the_time_entry_dao__to_retrieve_one_time_entry(mocker):
33+
expected_time_entry = mocker.Mock()
34+
time_entry_dao = mocker.Mock(
35+
get_by_id=mocker.Mock(return_value=expected_time_entry)
36+
)
37+
time_entry_service = TimeEntryService(time_entry_dao)
38+
39+
actual_time_entry = time_entry_service.get_by_id(Faker().uuid4())
40+
41+
assert time_entry_dao.get_by_id.called
42+
assert expected_time_entry == actual_time_entry

V2/tests/unit/use_cases/time_entries_use_case_test.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
from pytest_mock import MockFixture
2+
from faker import Faker
23

34
from time_tracker.time_entries._domain import _use_cases
45

6+
fake = Faker()
7+
58

69
def test__create_time_entry_function__uses_the_time_entries_service__to_create_time_entry(
710
mocker: MockFixture, time_entry_factory
@@ -16,3 +19,33 @@ def test__create_time_entry_function__uses_the_time_entries_service__to_create_t
1619

1720
assert time_entry_service.create.called
1821
assert expected_time_entry == actual_time_entry
22+
23+
24+
def test__get_list_time_entries_function__uses_the_time_entry_service__to_retrieve_time_entries(
25+
mocker: MockFixture,
26+
):
27+
expected_time_entries = mocker.Mock()
28+
time_entry_service = mocker.Mock(
29+
get_all=mocker.Mock(return_value=expected_time_entries)
30+
)
31+
32+
time_entries_use_case = _use_cases.GetTimeEntriesUseCase(time_entry_service)
33+
actual_time_entries = time_entries_use_case.get_time_entries()
34+
35+
assert time_entry_service.get_all.called
36+
assert expected_time_entries == actual_time_entries
37+
38+
39+
def test__get_time_entry_by_id_function__uses_the_time_entry_service__to_retrieve_time_entry(
40+
mocker: MockFixture,
41+
):
42+
expected_time_entries = mocker.Mock()
43+
time_entry_service = mocker.Mock(
44+
get_by_id=mocker.Mock(return_value=expected_time_entries)
45+
)
46+
47+
time_entry_use_case = _use_cases.GetTimeEntryUseCase(time_entry_service)
48+
actual_time_entry = time_entry_use_case.get_time_entry_by_id(fake.uuid4())
49+
50+
assert time_entry_service.get_by_id.called
51+
assert expected_time_entries == actual_time_entry

V2/time_tracker/_infrastructure/_db.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from . import _config
44

5+
_TEST_DIALECT = "sqlite"
6+
57

68
class DB():
79
config = _config.load_config()
@@ -17,4 +19,6 @@ def get_session(self):
1719
self.metadata.create_all(self.engine)
1820
if self.connection is None:
1921
self.connection = self.engine.connect()
22+
if self.engine.dialect.name == _TEST_DIALECT:
23+
self.connection.execute("pragma foreign_keys=ON")
2024
return self.connection
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
# flake8: noqa
2-
from ._time_entries import create_time_entry
2+
from ._time_entries import create_time_entry
3+
from ._time_entries import get_time_entries
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
# flake8: noqa
2-
from ._create_time_entry import create_time_entry
2+
from ._create_time_entry import create_time_entry
3+
from ._get_time_entries import get_time_entries

0 commit comments

Comments
 (0)