Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Project-Teams API tests #5631

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 14 additions & 10 deletions backend/api/projects/teams.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def get(self, project_id):
responses:
200:
description: Teams listed successfully
403:
401:
description: Forbidden, if user is not authenticated
404:
description: Not found
Expand All @@ -41,6 +41,8 @@ def get(self, project_id):
try:
teams_dto = TeamService.get_project_teams_as_dto(project_id)
return teams_dto.to_primitive(), 200
except NotFound:
return {"Error": "Project Not Found", "SubCode": "NotFound"}, 404
except Exception as e:
error_msg = f"Team GET - unhandled error: {str(e)}"
current_app.logger.critical(error_msg)
Expand Down Expand Up @@ -85,9 +87,9 @@ def post(self, team_id, project_id):
201:
description: Team project assignment created
401:
description: Forbidden, if user is not a manager of the project
403:
description: Forbidden, if user is not authenticated
403:
description: Forbidden, if user is not a manager of the project or team
404:
description: Not found
500:
Expand All @@ -97,7 +99,7 @@ def post(self, team_id, project_id):
return {
"Error": "User is not an admin or a manager for the team",
"SubCode": "UserPermissionError",
}, 401
}, 403

try:
role = request.get_json(force=True)["role"]
Expand All @@ -107,7 +109,7 @@ def post(self, team_id, project_id):

try:
if not ProjectAdminService.is_user_action_permitted_on_project(
token_auth.current_user, project_id
token_auth.current_user(), project_id
):
raise ValueError()
TeamService.add_team_project(team_id, project_id, role)
Expand All @@ -119,6 +121,8 @@ def post(self, team_id, project_id):
},
201,
)
except NotFound:
return {"Error": "No Project Found", "SubCode": "NotFound"}, 404
except ValueError:
return {
"Error": "User is not a manager of the project",
Expand Down Expand Up @@ -184,11 +188,11 @@ def patch(self, team_id, project_id):

try:
if not ProjectAdminService.is_user_action_permitted_on_project(
token_auth.current_user, project_id
token_auth.current_user(), project_id
):
raise ValueError()
TeamService.change_team_role(team_id, project_id, role)
return {"Status": "Team role updated successfully."}, 200
return {"Status": "Team role updated successfully"}, 200
except NotFound as e:
return {"Error": str(e), "SubCode": "NotFound"}, 404
except ValueError:
Expand Down Expand Up @@ -229,17 +233,17 @@ def delete(self, team_id, project_id):
200:
description: Team unassigned of the project
401:
description: Forbidden, if user is not a manager of the project
403:
description: Forbidden, if user is not authenticated
403:
description: Forbidden, if user is not a manager of the project
404:
description: Not found
500:
description: Internal Server Error
"""
try:
if not ProjectAdminService.is_user_action_permitted_on_project(
token_auth.current_user, project_id
token_auth.current_user(), project_id
):
raise ValueError()
TeamService.delete_team_project(team_id, project_id)
Expand Down
8 changes: 6 additions & 2 deletions backend/services/team_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from backend.models.dtos.stats_dto import Pagination
from backend.models.postgis.message import Message, MessageType
from backend.models.postgis.team import Team, TeamMembers
from backend.models.postgis.project import ProjectTeams
from backend.models.postgis.project import Project, ProjectTeams
from backend.models.postgis.project_info import ProjectInfo
from backend.models.postgis.utils import NotFound
from backend.models.postgis.statuses import (
Expand Down Expand Up @@ -388,8 +388,12 @@ def get_projects_by_team_id(team_id: int):
@staticmethod
def get_project_teams_as_dto(project_id: int) -> TeamsListDTO:
"""Gets all the teams for a specified project"""
project = Project.get(project_id)
if project is None:
raise NotFound()

project_teams = ProjectTeams.query.filter(
ProjectTeams.project_id == project_id
ProjectTeams.project_id == project.id
).all()
teams_list_dto = TeamsListDTO()

Expand Down
238 changes: 238 additions & 0 deletions tests/backend/integration/api/projects/test_teams.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
from tests.backend.base import BaseTestCase
from tests.backend.helpers.test_helpers import (
assign_team_to_project,
create_canned_project,
create_canned_team,
return_canned_user,
generate_encoded_token,
TEST_TEAM_NAME,
)
from backend.models.postgis.statuses import UserRole, TeamRoles


class TestProjectsTeamsAPI(BaseTestCase):
def setUp(self):
super().setUp()
self.test_project, self.test_author = create_canned_project()
self.test_author.role = UserRole.ADMIN.value
self.test_team = create_canned_team()
self.test_user = return_canned_user("test_user", 11111111)
self.test_user.create()
self.test_author_session_token = generate_encoded_token(self.test_author.id)
self.test_user_session_token = generate_encoded_token(self.test_user.id)
self.all_project_teams_url = f"/api/v2/projects/{self.test_project.id}/teams/"
self.single_project_team_url = (
f"/api/v2/projects/{self.test_project.id}/teams/{self.test_team.id}/"
)
self.non_existent_project_team_url = "/api/v2/projects/99/teams/99/"

# get
def test_get_project_teams_by_unauthenticated_user_fails(self):
"""
Test that endpoint returns 401 when an unauthenticated user retrieves teams
"""
response = self.client.get(self.all_project_teams_url)
response_body = response.get_json()
self.assertEqual(response.status_code, 401)
self.assertEqual(response_body["SubCode"], "InvalidToken")

def test_get_project_teams_for_non_existent_project_fails(self):
"""
Test that endpoint returns 404 when retrieving teams for non-existent projects
"""
response = self.client.get(
"/api/v2/projects/99/teams/",
headers={"Authorization": self.test_user_session_token},
)
response_body = response.get_json()
self.assertEqual(response.status_code, 404)
self.assertEqual(response_body["Error"], "Project Not Found")
self.assertEqual(response_body["SubCode"], "NotFound")

def test_get_project_teams_passes(self):
"""
Test that endpoint returns 200 when an authenticated user retrieves teams
"""
response = self.client.get(
self.all_project_teams_url,
headers={"Authorization": self.test_user_session_token},
)
response_body = response.get_json()
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response_body["teams"]), 0)
self.assertEqual(response_body["teams"], [])
# setup: add team to project
assign_team_to_project(project=self.test_project, team=self.test_team, role=0)
response = self.client.get(
self.all_project_teams_url,
headers={"Authorization": self.test_user_session_token},
)
response_body = response.get_json()
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response_body["teams"]), 1)
self.assertEqual(response_body["teams"][0]["name"], TEST_TEAM_NAME)
self.assertEqual(response_body["teams"][0]["role"], 0)

# post
def test_assign_team_to_project_by_unauthenticated_user_fails(self):
"""
Test that endpoint returns 401 when unauthenticated user assigns team to project
"""
response = self.client.post(
self.single_project_team_url, json={"role": TeamRoles.MAPPER.name}
)
response_body = response.get_json()
self.assertEqual(response.status_code, 401)
self.assertEqual(response_body["SubCode"], "InvalidToken")

def test_assign_team_to_project_by_non_admin_fails(self):
"""
Test that endpoint returns 403 when non admin assigns team to a project
"""
response = self.client.post(
self.single_project_team_url,
json={"role": TeamRoles.MAPPER.name},
headers={"Authorization": self.test_user_session_token},
)
response_body = response.get_json()
self.assertEqual(response.status_code, 403)
self.assertEqual(
response_body["Error"], "User is not an admin or a manager for the team"
)
self.assertEqual(response_body["SubCode"], "UserPermissionError")

Copy link
Contributor

Choose a reason for hiding this comment

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

A test to determine if 403 is raised when the user does not have permission to update the project appears to be missing as well. Only a team's user permission is tested in the test above

Also test to determine whether a 400 is raised when an invalid team role is passed appears to be missing.

def test_assign_team_to_non_existent_project_fails(self):
"""
Test that endpoint returns 404 when admin assigns a team to a non-existent project
"""
response = self.client.post(
f"/api/v2/projects/99/teams/{self.test_team.id}/",
json={"role": TeamRoles.MAPPER.name},
headers={"Authorization": self.test_author_session_token},
)
response_body = response.get_json()
self.assertEqual(response.status_code, 404)
self.assertEqual(response_body["Error"], "No Project Found")
self.assertEqual(response_body["SubCode"], "NotFound")

def test_assign_team_to_project_by_admin_passes(self):
"""
Test that endpoint returns 201 when admin successfully assigns a team to a project
"""
response = self.client.post(
self.single_project_team_url,
json={"role": TeamRoles.MAPPER.name},
headers={"Authorization": self.test_author_session_token},
)
response_body = response.get_json()
self.assertEqual(response.status_code, 201)
self.assertEqual(
response_body["Success"],
f"Team {self.test_team.id} assigned to project {self.test_project.id} with role MAPPER",
)

# patch
def test_update_team_role_by_unauthenticated_user_fails(self):
"""
Test that endpoint returns 401 when unauthenticated user updates project team role
"""
response = self.client.patch(
self.single_project_team_url, json={"role": TeamRoles.MAPPER.name}
)
response_body = response.get_json()
self.assertEqual(response.status_code, 401)
self.assertEqual(response_body["SubCode"], "InvalidToken")

def test_update_team_role_by_non_admin_fails(self):
"""
Test that endpoint returns 403 when non admin updates project team role
"""
response = self.client.patch(
self.single_project_team_url,
json={"role": TeamRoles.MAPPER.name},
headers={"Authorization": self.test_user_session_token},
)
response_body = response.get_json()
self.assertEqual(response.status_code, 403)
self.assertEqual(response_body["Error"], "User is not a manager of the project")
self.assertEqual(response_body["SubCode"], "UserPermissionError")

Copy link
Contributor

Choose a reason for hiding this comment

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

Same here a test to determine whether a 400 is raised when an invalid team role is passed appears to be missing.

def test_update_team_role_of_non_existent_project_fails(self):
"""
Test that endpoint returns 404 when admin updates non-existent project team role
"""
response = self.client.patch(
self.non_existent_project_team_url,
json={"role": TeamRoles.MAPPER.name},
headers={"Authorization": self.test_author_session_token},
)
response_body = response.get_json()
self.assertEqual(response.status_code, 404)
self.assertEqual(response_body["SubCode"], "NotFound")

def test_update_team_role_by_admin_passes(self):
"""
Test that endpoint returns 200 when admin successfully updates project team role
"""
assign_team_to_project(
self.test_project, self.test_team, TeamRoles.MAPPER.value
)
response = self.client.patch(
self.single_project_team_url,
json={"role": TeamRoles.VALIDATOR.name},
headers={"Authorization": self.test_author_session_token},
)
response_body = response.get_json()
self.assertEqual(response.status_code, 200)
self.assertEqual(response_body["Status"], "Team role updated successfully")

# delete
def test_delete_project_team_by_unauthenticated_user_fails(self):
"""
Test that endpoint returns 401 when unauthenticated user deletes project team
"""
response = self.client.delete(self.single_project_team_url)
response_body = response.get_json()
self.assertEqual(response.status_code, 401)
self.assertEqual(response_body["SubCode"], "InvalidToken")

def test_delete_project_team_by_non_admin_fails(self):
"""
Test that endpoint returns 403 when non admin deletes project team
"""
response = self.client.delete(
self.single_project_team_url,
headers={"Authorization": self.test_user_session_token},
)
response_body = response.get_json()
self.assertEqual(response.status_code, 403)
self.assertEqual(response_body["Error"], "User is not a manager of the project")
self.assertEqual(response_body["SubCode"], "UserPermissionError")

def test_delete_non_existent_project_team_fails(self):
"""
Test that endpoint returns 404 when admin deletes non-existent project team
"""
response = self.client.delete(
self.non_existent_project_team_url,
headers={"Authorization": self.test_author_session_token},
)
response_body = response.get_json()
self.assertEqual(response.status_code, 404)
self.assertEqual(response_body["Error"], "No team found")
self.assertEqual(response_body["SubCode"], "NotFound")

def test_delete_project_team_by_admin_passes(self):
"""
Test that endpoint returns 200 when admin successfully deletes project team
"""
assign_team_to_project(
self.test_project, self.test_team, TeamRoles.MAPPER.value
)
response = self.client.delete(
self.single_project_team_url,
headers={"Authorization": self.test_author_session_token},
)
response_body = response.get_json()
self.assertEqual(response.status_code, 200)
self.assertEqual(response_body["Success"], True)