From c4154f1ee86cf1f033d91a6304dfa04e762071b2 Mon Sep 17 00:00:00 2001 From: shayan-7 <39003982+shayan-7@users.noreply.github.com> Date: Wed, 3 Jul 2019 17:32:57 +0430 Subject: [PATCH] Fix a bug on project boarding calculation (#980) * Add project model test * Fix a bug on project boarding calculation, #149 * Enhance tests --- dolphin/models/project.py | 49 ++++------- dolphin/tests/test_project_create.py | 2 +- dolphin/tests/test_project_list.py | 13 ++- dolphin/tests/test_project_model.py | 126 +++++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 41 deletions(-) create mode 100644 dolphin/tests/test_project_model.py diff --git a/dolphin/models/project.py b/dolphin/models/project.py index 7885f427..437e223f 100644 --- a/dolphin/models/project.py +++ b/dolphin/models/project.py @@ -4,7 +4,7 @@ OrderingMixin, FilteringMixin, PaginationMixin from restfulpy.orm.metadata import MetadataField from sqlalchemy import Integer, ForeignKey, Enum, select, func, bindparam, \ - join, case + join, case, exists from sqlalchemy.orm import column_property from sqlalchemy.ext.hybrid import hybrid_property @@ -172,40 +172,23 @@ class Project(ModifiedByMixin, OrderingMixin, FilteringMixin, PaginationMixin, deferred=True ) - boarding_value = column_property( - select([func.max(Issue.boarding_value)]) - .where(Issue.project_id == id) - .where(status == 'active') + boarding = column_property( + case([ + ( + status == 'queued', + None + ), + ( + exists( + select([Issue.id]) + .where(Issue.project_id == id) + .where(Issue.boarding == 'delayed') + ), + 'delayed' + )], else_='on-time' + ) ) - @hybrid_property - def boarding(self): - if self.status == 'on-hold': - return Boarding.frozen[1] - - elif self.status == 'queued': - return None - - elif self.boarding_value == Boarding.ontime[0]: - return Boarding.ontime[1] - - elif self.boarding_value == Boarding.delayed[0]: - return Boarding.delayed[1] - - elif self.boarding_value == Boarding.frozen[0]: - return Boarding.frozen[1] - - return None - - @boarding.expression - def boarding(cls): - return case([ - (cls.status == 'on-hold', Boarding.frozen[1]), - (cls.boarding_value == Boarding.ontime[0], Boarding.ontime[1]), - (cls.boarding_value == Boarding.delayed[0], Boarding.delayed[1]), - (cls.boarding_value == Boarding.frozen[0], Boarding.frozen[1]), - ]) - @classmethod def iter_metadata_fields(cls): yield from super().iter_metadata_fields() diff --git a/dolphin/tests/test_project_create.py b/dolphin/tests/test_project_create.py index 9bf841a1..d68c3fb6 100644 --- a/dolphin/tests/test_project_create.py +++ b/dolphin/tests/test_project_create.py @@ -83,7 +83,7 @@ def test_create(self): assert response.json['title'] == 'My awesome project' assert response.json['description'] == 'A decription for my project' assert response.json['status'] == 'active' - assert response.json['boarding'] == None + assert response.json['boarding'] == 'on-time' assert response.json['dueDate'] == None assert response.json['managerId'] == self.member.id assert response.json['secondaryManagerId'] is None diff --git a/dolphin/tests/test_project_list.py b/dolphin/tests/test_project_list.py index 265a6770..7d2538e3 100644 --- a/dolphin/tests/test_project_list.py +++ b/dolphin/tests/test_project_list.py @@ -343,8 +343,8 @@ def test_list(self): assert status == 200 assert len(response.json) == 4 assert response.json[0]['title'] == self.project1.title - assert response.json[1]['title'] == self.project3.title - assert response.json[2]['title'] == self.project2.title + assert response.json[1]['title'] == self.project2.title + assert response.json[2]['title'] == self.project3.title assert response.json[3]['title'] == self.project4.title when( @@ -354,8 +354,8 @@ def test_list(self): assert status == 200 assert len(response.json) == 4 assert response.json[0]['title'] == self.project3.title - assert response.json[1]['title'] == self.project2.title - assert response.json[2]['title'] == self.project1.title + assert response.json[1]['title'] == self.project1.title + assert response.json[2]['title'] == self.project2.title assert response.json[3]['title'] == self.project4.title with self.given( @@ -384,7 +384,7 @@ def test_list(self): query=dict(sort='id', status='on-hold') ) assert response.json[0]['status'] == 'on-hold' - assert response.json[0]['boarding'] == 'frozen' + assert response.json[0]['boarding'] == 'on-time' when( 'List projects excepts one of statuses', @@ -397,8 +397,7 @@ def test_list(self): query=dict(boarding='on-time') ) assert status == 200 - assert len(response.json) == 1 - assert response.json[0]['title'] == self.project2.title + assert len(response.json) == 3 when( 'Filter project by boarding using IN clause', diff --git a/dolphin/tests/test_project_model.py b/dolphin/tests/test_project_model.py new file mode 100644 index 00000000..fd731ba1 --- /dev/null +++ b/dolphin/tests/test_project_model.py @@ -0,0 +1,126 @@ +from datetime import datetime + +from auditor.context import Context as AuditLogContext +from nanohttp import context +from nanohttp.contexts import Context +from restfulpy.testing import db +from sqlalchemy.orm import aliased + +from dolphin.models import Item, Project, Member, Workflow, Group, Release, \ + Skill, Phase, Issue, IssuePhase, Dailyreport + + +def test_boarding(db): + session = db() + session.expire_on_commit = True + + with AuditLogContext(dict()): + member = Member( + title='First Member', + email='member1@example.com', + access_token='access token 1', + phone=123456789, + reference_id=1 + ) + session.add(member) + session.commit() + + workflow = Workflow(title='Default') + skill = Skill(title='First Skill') + group = Group(title='default') + + release = Release( + title='My first release', + description='A decription for my first release', + cutoff='2030-2-20', + launch_date='2030-2-20', + manager=member, + room_id=0, + group=group, + ) + + project = Project( + release=release, + workflow=workflow, + group=group, + manager=member, + title='My first project', + description='A decription for my project', + room_id=1, + status='active', + ) + + with Context(dict()): + context.identity = member + + issue1 = Issue( + project=project, + title='First issue', + description='This is description of first issue', + days=1, + room_id=2, + ) + session.add(issue1) + + issue2 = Issue( + project=project, + title='Second issue', + description='This is description of second issue', + kind='feature', + days=2, + room_id=3, + ) + session.add(issue2) + + phase1 = Phase( + workflow=workflow, + title='Backlog', + order=1, + skill=skill, + ) + session.add(phase1) + + phase2 = Phase( + workflow=workflow, + title='Test', + order=2, + skill=skill, + ) + session.add(phase1) + + phase3 = Phase( + workflow=workflow, + title='Development', + order=3, + skill=skill, + ) + session.add(phase1) + session.flush() + + issue_phase1 = IssuePhase( + issue_id=issue1.id, + phase_id=phase1.id, + ) + session.add(issue_phase1) + session.flush() + + item1 = Item( + issue_phase_id=issue_phase1.id, + member_id=member.id, + start_date=datetime.strptime('2020-2-2', '%Y-%m-%d'), + end_date=datetime.strptime('2020-2-3', '%Y-%m-%d'), + estimated_hours=4, + ) + session.add(item1) + session.commit() + + assert project.boarding == 'on-time' + + item1.end_date = datetime.strptime('2019-2-3', '%Y-%m-%d'), + session.commit() + assert project.boarding == 'delayed' + + project.status = 'queued' + session.commit() + assert project.boarding == None +