Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
fix: allow limits overlap in time entries #217
  • Loading branch information
Angeluz-07 committed Oct 6, 2020
commit ce996032bf4cf20c129b84ad293db4c031571c95
164 changes: 121 additions & 43 deletions tests/time_tracker_api/time_entries/time_entries_model_test.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,27 @@
from datetime import datetime, timedelta

import pytest
from faker import Faker

from utils.time import datetime_str, current_datetime
from commons.data_access_layer.database import EventContext
from time_tracker_api.time_entries.time_entries_model import (
TimeEntryCosmosDBRepository,
TimeEntryCosmosDBModel,
container_definition,
)

fake = Faker()

now = current_datetime()
yesterday = current_datetime() - timedelta(days=1)
two_days_ago = current_datetime() - timedelta(days=2)


def create_time_entry(
start_date: datetime,
end_date: datetime,
start_date: str,
end_date: str,
owner_id: str,
tenant_id: str,
event_context: EventContext,
time_entry_repository: TimeEntryCosmosDBRepository,
) -> TimeEntryCosmosDBModel:
data = {
"project_id": fake.uuid4(),
"activity_id": fake.uuid4(),
"description": fake.paragraph(nb_sentences=2),
"start_date": datetime_str(start_date),
"end_date": datetime_str(end_date),
"project_id": Faker().uuid4(),
"activity_id": Faker().uuid4(),
"description": Faker().paragraph(nb_sentences=2),
"start_date": start_date,
"end_date": end_date,
"owner_id": owner_id,
"tenant_id": tenant_id,
}
Expand All @@ -43,59 +33,146 @@ def create_time_entry(


@pytest.mark.parametrize(
'start_date,end_date', [(two_days_ago, yesterday), (now, None)]
'start_date,end_date,start_date_,end_date_',
[
(
"2020-10-01T05:00:00.000Z",
"2020-10-01T10:00:00.000Z",
"2020-10-01T05:00:00.000Z",
"2020-10-01T10:00:00.000Z",
),
(
"2020-10-01T05:00:00.000Z",
"2020-10-01T10:00:00.000Z",
"2020-10-01T07:00:00.000Z",
"2020-10-01T12:00:00.000Z",
),
(
"2020-10-01T05:00:00.000Z",
"2020-10-01T10:00:00.000Z",
"2020-10-01T02:00:00.000Z",
"2020-10-01T07:00:00.000Z",
),
(
"2020-10-01T05:00:00.000Z",
"2020-10-01T10:00:00.000Z",
"2020-10-01T02:00:00.000Z",
"2020-10-01T12:00:00.000Z",
),
],
)
def test_find_interception_with_date_range_should_find(
start_date: datetime,
end_date: datetime,
start_date: str,
end_date: str,
start_date_: str,
end_date_: str,
owner_id: str,
tenant_id: str,
time_entry_repository: TimeEntryCosmosDBRepository,
event_context: EventContext,
):
event_ctx = EventContext(
container_definition["id"],
"create",
tenant_id=tenant_id,
user_id=owner_id,
)

existing_item = create_time_entry(
start_date,
end_date,
owner_id,
tenant_id,
event_ctx,
event_context,
time_entry_repository,
)

try:
result = time_entry_repository.find_interception_with_date_range(
datetime_str(yesterday), datetime_str(now), owner_id, tenant_id
start_date_, end_date_, owner_id, tenant_id
)

assert result is not None
assert len(result) > 0
assert any([existing_item.id == item.id for item in result])
finally:
time_entry_repository.delete_permanently(existing_item.id, event_ctx)
time_entry_repository.delete_permanently(
existing_item.id, event_context
)


def test_find_interception_should_ignore_id_of_existing_item(
@pytest.mark.parametrize(
'start_date,end_date,start_date_,end_date_',
[
(
"2020-10-01T05:00:00.000Z",
"2020-10-01T10:00:00.000Z",
"2020-10-01T10:00:00.000Z",
"2020-10-01T15:00:00.000Z",
),
(
"2020-10-01T05:00:00.000Z",
"2020-10-01T10:00:00.000Z",
"2020-10-01T12:00:00.000Z",
"2020-10-01T15:00:00.000Z",
),
(
"2020-10-01T05:00:00.000Z",
"2020-10-01T10:00:00.000Z",
"2020-10-01T02:00:00.000Z",
"2020-10-01T05:00:00.000Z",
),
(
"2020-10-01T05:00:00.000Z",
"2020-10-01T10:00:00.000Z",
"2020-10-01T02:00:00.000Z",
"2020-10-01T04:00:00.000Z",
),
],
)
def test_find_interception_with_date_range_should_not_find(
start_date: str,
end_date: str,
start_date_: str,
end_date_: str,
owner_id: str,
tenant_id: str,
time_entry_repository: TimeEntryCosmosDBRepository,
event_context: EventContext,
):
event_ctx = EventContext(
container_definition["id"],
"create",
tenant_id=tenant_id,
user_id=owner_id,
existing_item = create_time_entry(
start_date,
end_date,
owner_id,
tenant_id,
event_context,
time_entry_repository,
)
start_date = datetime_str(yesterday)
end_date = datetime_str(now)

try:
result = time_entry_repository.find_interception_with_date_range(
start_date_, end_date_, owner_id, tenant_id
)

assert result == []
assert len(result) == 0
assert not any([existing_item.id == item.id for item in result])
finally:
time_entry_repository.delete_permanently(
existing_item.id, event_context
)


def test_find_interception_should_ignore_id_of_existing_item(
owner_id: str,
tenant_id: str,
time_entry_repository: TimeEntryCosmosDBRepository,
event_context: EventContext,
):
start_date = "2020-10-01T05:00:00.000Z"
end_date = "2020-10-01T10:00:00.000Z"
existing_item = create_time_entry(
yesterday, now, owner_id, tenant_id, event_ctx, time_entry_repository
start_date,
end_date,
owner_id,
tenant_id,
event_context,
time_entry_repository,
)

try:
colliding_result = time_entry_repository.find_interception_with_date_range(
start_date, end_date, owner_id, tenant_id
Expand All @@ -109,15 +186,16 @@ def test_find_interception_should_ignore_id_of_existing_item(
ignore_id=existing_item.id,
)

colliding_result is not None
assert colliding_result is not None
assert any([existing_item.id == item.id for item in colliding_result])

non_colliding_result is not None
assert non_colliding_result is not None
assert not any(
[existing_item.id == item.id for item in non_colliding_result]
)
finally:
time_entry_repository.delete_permanently(existing_item.id, event_ctx)
time_entry_repository.delete_permanently(
existing_item.id, event_context
)


def test_find_running_should_return_running_time_entry(
Expand Down
28 changes: 9 additions & 19 deletions time_tracker_api/time_entries/time_entries_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,8 @@ def find_interception_with_date_range(
SELECT * FROM c
WHERE ((c.start_date BETWEEN @start_date AND @end_date)
OR (c.end_date BETWEEN @start_date AND @end_date))
AND c.start_date!= @end_date
AND c.end_date!= @start_date
{conditions_clause}
{ignore_id_condition}
{visibility_condition}
Expand Down Expand Up @@ -455,8 +457,7 @@ def get_all(self, conditions: dict = None, **kwargs) -> list:
conditions.update({"owner_id": event_ctx.user_id})

custom_query = self.build_custom_query(
is_admin=event_ctx.is_admin,
conditions=conditions,
is_admin=event_ctx.is_admin, conditions=conditions,
)
date_range = self.handle_date_filter_args(args=conditions)
limit = conditions.get("limit", None)
Expand All @@ -476,8 +477,7 @@ def get_all_paginated(self, conditions: dict = None, **kwargs) -> list:
event_ctx = self.create_event_context("read-many")
get_all_conditions.update({"owner_id": event_ctx.user_id})
custom_query = self.build_custom_query(
is_admin=event_ctx.is_admin,
conditions=get_all_conditions,
is_admin=event_ctx.is_admin, conditions=get_all_conditions,
)
date_range = self.handle_date_filter_args(args=get_all_conditions)
records_total = self.repository.count(
Expand All @@ -488,8 +488,7 @@ def get_all_paginated(self, conditions: dict = None, **kwargs) -> list:
)
conditions.update({"owner_id": event_ctx.user_id})
custom_query = self.build_custom_query(
is_admin=event_ctx.is_admin,
conditions=conditions,
is_admin=event_ctx.is_admin, conditions=conditions,
)
date_range = self.handle_date_filter_args(args=conditions)
length = conditions.get("length", None)
Expand Down Expand Up @@ -533,11 +532,7 @@ def update(self, id, data: dict, description=None):
time_entry = self.repository.find(id, event_ctx)
self.check_whether_current_user_owns_item(time_entry)

return self.repository.partial_update(
id,
data,
event_ctx,
)
return self.repository.partial_update(id, data, event_ctx,)

def stop(self, id):
event_ctx = self.create_event_context("update", "Stop time entry")
Expand All @@ -547,9 +542,7 @@ def stop(self, id):
self.check_time_entry_is_not_stopped(time_entry)

return self.repository.partial_update(
id,
{'end_date': current_datetime_str()},
event_ctx,
id, {'end_date': current_datetime_str()}, event_ctx,
)

def restart(self, id):
Expand All @@ -560,18 +553,15 @@ def restart(self, id):
self.check_time_entry_is_not_started(time_entry)

return self.repository.partial_update(
id,
{'end_date': None},
event_ctx,
id, {'end_date': None}, event_ctx,
)

def delete(self, id):
event_ctx = self.create_event_context("delete")
time_entry = self.repository.find(id, event_ctx)
self.check_whether_current_user_owns_item(time_entry)
self.repository.delete(
id,
event_ctx,
id, event_ctx,
)

def find_running(self):
Expand Down