From f4f9072c3f5d5976fefe98496185a4e1b2c3f0d8 Mon Sep 17 00:00:00 2001 From: dominik24c Date: Mon, 16 Jan 2023 21:59:49 +0100 Subject: [PATCH] update and add functional tests for students view --- backend/app/students/routes/enrollments.py | 10 +- backend/tests/factory.py | 76 ++++- .../coordinator/test_enrollments.py | 58 ++-- .../students/test_enrollments.py | 298 ++++++++++++++++++ .../students/test_project_grade_sheet.py | 82 +++++ .../students/test_registrations.py | 52 +-- .../students/test_year_group.py | 44 --- backend/tests/utils.py | 48 ++- 8 files changed, 539 insertions(+), 129 deletions(-) create mode 100644 backend/tests/functional_tests/students/test_enrollments.py delete mode 100644 backend/tests/functional_tests/students/test_year_group.py diff --git a/backend/app/students/routes/enrollments.py b/backend/app/students/routes/enrollments.py index 196376f..990e15b 100644 --- a/backend/app/students/routes/enrollments.py +++ b/backend/app/students/routes/enrollments.py @@ -18,7 +18,7 @@ bp = APIBlueprint("enrollments", __name__, url_prefix="/") @bp.post("//enrollments//") @bp.input(TemporaryStudentSchema) -@bp.output(MessageSchema) +@bp.output(MessageSchema, status_code=201) def assign_your_group_to_term_of_defence( examination_schedule_id: int, term_of_defence_id: int, data: dict ) -> dict: @@ -37,7 +37,7 @@ def assign_your_group_to_term_of_defence( ) if term_of_defence is None or (ex := term_of_defence.examination_schedule) is None: - abort(400, "Term of defence not found!") + abort(404, "Term of defence not found!") if ex.open_enrollments != EnrollmentsMode.OPEN.value: abort(400, "Enrollments is closed! You have been delayed!") @@ -97,9 +97,9 @@ def delete_your_group_from_term_of_defence( .first() ) - ex = term_of_defence.examination_schedule if term_of_defence is None: - abort(404, "Term of defence doesn't exist!") + abort(404, "Not found term of defence!") + ex = term_of_defence.examination_schedule group = ( Group.query.filter(Group.year_group_id == ex.year_group_id) @@ -107,7 +107,7 @@ def delete_your_group_from_term_of_defence( .filter_by(index=student.index) .first() ) - if group.id != term_of_defence.group_id: + if group is None or group.id != term_of_defence.group_id: abort(400, "You are not assigned to this group!") term_of_defence.group_id = None diff --git a/backend/tests/factory.py b/backend/tests/factory.py index 67a4dc2..95ae2dd 100644 --- a/backend/tests/factory.py +++ b/backend/tests/factory.py @@ -1,4 +1,5 @@ import datetime +import random from factory import Sequence, alchemy from factory.faker import Faker @@ -12,7 +13,7 @@ from app.examination_schedule.models import ( TermOfDefence, ) from app.project_supervisor.models import ProjectSupervisor -from app.students.models import Group, Student, YearGroup +from app.students.models import Group, Student, YearGroup, ProjectGradeSheet class YearGroupFactory(alchemy.SQLAlchemyModelFactory): @@ -82,11 +83,11 @@ class TermOfDefenceFactory(alchemy.SQLAlchemyModelFactory): start_date = Sequence( lambda n: datetime.datetime(2020, 1, 1, tzinfo=datetime.timezone.utc) - + datetime.timedelta(n * 30) + + datetime.timedelta(n * 30) ) end_date = Sequence( lambda n: datetime.datetime(2020, 1, 1, tzinfo=datetime.timezone.utc) - + datetime.timedelta(n * 30 + 30) + + datetime.timedelta(n * 30 + 30) ) @@ -97,9 +98,74 @@ class TemporaryAvailabilityFactory(alchemy.SQLAlchemyModelFactory): start_date = Sequence( lambda n: datetime.datetime(2020, 1, 1, tzinfo=datetime.timezone.utc) - + datetime.timedelta(n * 30) + + datetime.timedelta(n * 30) ) end_date = Sequence( lambda n: datetime.datetime(2020, 1, 1, tzinfo=datetime.timezone.utc) - + datetime.timedelta(n * 30 + 30) + + datetime.timedelta(n * 30 + 30) ) + + +class ProjectGradeSheetFactory(alchemy.SQLAlchemyModelFactory): + class Meta: + model = ProjectGradeSheet + sqlalchemy_session = db.session + + presentation_required_content_1 = random.choice([0, 1, 3, 4]) + presentation_required_content_2 = random.choice([0, 1, 3, 4]) + presentation_was_compatible_1 = random.choice([0, 1, 3, 4]) + presentation_was_compatible_2 = random.choice([0, 1, 3, 4]) + presentation_showing_1 = random.choice([0, 1, 3, 4]) + presentation_showing_2 = random.choice([0, 1, 3, 4]) + presentation_answers_to_questions_from_committee_1 = random.choice([0, 1, 3, 4]) + presentation_answers_to_questions_from_committee_2 = random.choice([0, 1, 3, 4]) + documentation_project_vision_1 = random.choice([0, 1, 3, 4]) + documentation_project_vision_2 = random.choice([0, 1, 3, 4]) + documentation_requirements_1 = random.choice([0, 1, 3, 4]) + documentation_requirements_2 = random.choice([0, 1, 3, 4]) + documentation_for_clients_1 = random.choice([0, 1, 3, 4]) + documentation_for_clients_2 = random.choice([0, 1, 3, 4]) + documentation_for_developers_1 = random.choice([0, 1, 3, 4]) + documentation_for_developers_2 = random.choice([0, 1, 3, 4]) + documentation_license_1 = random.choice([0, 1, 3, 4]) + documentation_license_2 = random.choice([0, 1, 3, 4]) + + group_work_regularity_1 = random.choice([0, 1, 3, 4]) + group_work_regularity_2 = random.choice([0, 1, 3, 4]) + group_work_division_of_work_1 = random.choice([0, 1, 3, 4]) + group_work_division_of_work_2 = random.choice([0, 1, 3, 4]) + group_work_contact_with_client_1 = random.choice([0, 1, 3, 4]) + group_work_contact_with_client_2 = random.choice([0, 1, 3, 4]) + group_work_management_of_risk_1 = random.choice([0, 1, 3, 4]) + group_work_management_of_risk_2 = random.choice([0, 1, 3, 4]) + group_work_work_methodology_1 = random.choice([0, 1, 3, 4]) + group_work_work_methodology_2 = random.choice([0, 1, 3, 4]) + group_work_management_of_source_code_1 = random.choice([0, 1, 3, 4]) + group_work_management_of_source_code_2 = random.choice([0, 1, 3, 4]) + group_work_devops_1 = random.choice([0, 1, 3, 4]) + group_work_devops_2 = random.choice([0, 1, 3, 4]) + + products_project_complexity_of_product_1 = random.choice([0, 1, 3, 4]) + products_project_complexity_of_product_2 = random.choice([0, 1, 3, 4]) + products_project_access_to_application_1 = random.choice([0, 1, 3, 4]) + products_project_access_to_application_2 = random.choice([0, 1, 3, 4]) + products_project_security_issues_1 = random.choice([0, 1, 3, 4]) + products_project_security_issues_2 = random.choice([0, 1, 3, 4]) + products_project_access_to_test_application_1 = random.choice([0, 1, 3, 4]) + products_project_access_to_test_application_2 = random.choice([0, 1, 3, 4]) + products_project_acceptance_criteria_1 = random.choice([0, 1, 3, 4]) + products_project_acceptance_criteria_2 = random.choice([0, 1, 3, 4]) + products_project_expected_functionality_1 = random.choice([0, 1, 3, 4]) + products_project_expected_functionality_2 = random.choice([0, 1, 3, 4]) + products_project_promises_well_1 = random.choice([0, 1, 3, 4]) + products_project_promises_well_2 = random.choice([0, 1, 3, 4]) + products_project_has_been_implemented_1 = random.choice([0, 1, 3, 4]) + products_project_has_been_implemented_2 = random.choice([0, 1, 3, 4]) + products_project_is_useful_1 = random.choice([0, 1, 3, 4]) + products_project_is_useful_2 = random.choice([0, 1, 3, 4]) + products_project_prototype_1 = random.choice([0, 1, 3, 4]) + products_project_prototype_2 = random.choice([0, 1, 3, 4]) + products_project_tests_1 = random.choice([0, 1, 3, 4]) + products_project_tests_2 = random.choice([0, 1, 3, 4]) + products_project_technology_1 = random.choice([0, 1, 3, 4]) + products_project_technology_2 = random.choice([0, 1, 3, 4]) diff --git a/backend/tests/functional_tests/coordinator/test_enrollments.py b/backend/tests/functional_tests/coordinator/test_enrollments.py index d968791..e1713a1 100644 --- a/backend/tests/functional_tests/coordinator/test_enrollments.py +++ b/backend/tests/functional_tests/coordinator/test_enrollments.py @@ -18,25 +18,10 @@ from ...utils import ( assert_model_changes, create_many_models, create_one_model, + get_data_of_term_of_defence ) -def get_data_of_term_of_defence(timedelta_minutes: int = 30) -> dict: - ex = ExaminationSchedule.query.first() - if ex is None: - date = datetime.datetime.now() - else: - date = ex.start_date - return { - "start_date": (date + datetime.timedelta(days=1)).strftime( - "%Y-%m-%dT%H:%M:%S.000Z" - ), - "end_date": ( - date + datetime.timedelta(days=1, minutes=timedelta_minutes) - ).strftime("%Y-%m-%dT%H:%M:%S.000Z"), - } - - def test_list_of_term_of_defences(test_app_with_context) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) @@ -63,7 +48,7 @@ def test_delete_term_of_defence(test_app_with_context) -> None: def test_delete_term_of_defence_if_term_of_defence_or_examination_schedule_doesnt_exist( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: _test_case_client( @@ -133,7 +118,7 @@ def test_create_many_term_of_defences(test_app_with_context) -> None: def test_create_many_term_of_defences_with_invalid_id_of_chairman( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) @@ -157,7 +142,7 @@ def test_create_many_term_of_defences_with_invalid_id_of_chairman( def test_create_many_term_of_defences_if_examination_schedule_doesnt_exist( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) @@ -180,7 +165,7 @@ def test_create_many_term_of_defences_if_examination_schedule_doesnt_exist( def test_create_many_term_of_defences_if_project_supervisors_doesnt_exist( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) @@ -201,7 +186,7 @@ def test_create_many_term_of_defences_if_project_supervisors_doesnt_exist( def test_create_many_term_of_defences_with_invalid_duration_time( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) @@ -226,7 +211,7 @@ def test_create_many_term_of_defences_with_invalid_duration_time( def test_create_many_term_of_defences_if_start_date_is_greater_than_end_date( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) @@ -251,7 +236,7 @@ def test_create_many_term_of_defences_if_start_date_is_greater_than_end_date( def test_create_many_term_of_defences_with_invalid_date_range( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) @@ -303,7 +288,7 @@ def test_update_term_of_defence(test_app_with_context) -> None: def test_update_term_of_defence_with_invalid_id_of_chairman( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) @@ -328,7 +313,7 @@ def test_update_term_of_defence_with_invalid_id_of_chairman( def test_update_term_of_defence_if_examination_schedule_or_term_of_defence_doesnt_exist( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: data = get_data_of_term_of_defence(150) @@ -346,7 +331,7 @@ def test_update_term_of_defence_if_examination_schedule_or_term_of_defence_doesn def test_update_term_of_defence_if_project_supervisors_doesnt_exist( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) @@ -367,7 +352,7 @@ def test_update_term_of_defence_if_project_supervisors_doesnt_exist( def test_update_term_of_defence_with_invalid_duration_time( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) @@ -392,7 +377,7 @@ def test_update_term_of_defence_with_invalid_duration_time( def test_update_term_of_defence_if_start_date_is_greater_than_end_date( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) @@ -461,7 +446,7 @@ def test_list_temporary_availabilities(test_app_with_context) -> None: def test_list_temporary_availabilities_if_examination_schedule_doesnt_exist( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: url = "/api/coordinator/enrollments/43/temporary-availabilities/" @@ -498,7 +483,7 @@ def test_list_of_assigned_group_to_term_of_defences(test_app_with_context) -> No def test_list_of_assigned_group_to_term_of_defences_if_examination_schedule_doesnt_exist( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: url = "/api/coordinator/enrollments/43/assigned-group-to-term-of-defences/" @@ -532,7 +517,7 @@ def test_set_new_group_to_term_of_defence(test_app_with_context) -> None: def test_set_new_group_to_term_of_defence_if_examination_schedule_or_term_of_defence_dont_exist( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: url = "/api/coordinator/enrollments/34/term-of-defence/4/group/" @@ -548,7 +533,7 @@ def test_set_new_group_to_term_of_defence_if_examination_schedule_or_term_of_def def test_set_new_group_to_term_of_defence_if_group_doesnt_exist( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) @@ -567,7 +552,8 @@ def test_set_new_group_to_term_of_defence_if_group_doesnt_exist( ) -def test_set_new_group_to_term_of_defence_if_(test_app_with_context) -> None: +def test_set_new_group_to_term_of_defence_if_group_has_already_assigned_to_term_of_defence( + test_app_with_context) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id) @@ -611,7 +597,7 @@ def test_delete_group_to_term_of_defence(test_app_with_context) -> None: def test_delete_group_to_term_of_defence_if_examination_schedule_doesnt_exist( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: url = "/api/coordinator/enrollments/3/term-of-defence/1/group/" @@ -649,7 +635,7 @@ def test_update_group_for_term_of_defence(test_app_with_context) -> None: def test_update_group_for_term_of_defence_if_examination_schedule_or_term_of_defence_dont_exist( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: url = "/api/coordinator/enrollments/34/term-of-defence/4/group/" @@ -665,7 +651,7 @@ def test_update_group_for_term_of_defence_if_examination_schedule_or_term_of_def def test_update_group_for_term_of_defence_if_group_doesnt_exist( - test_app_with_context, + test_app_with_context, ) -> None: with test_app_with_context.test_client() as client: year_group = create_one_model(YearGroupFactory) diff --git a/backend/tests/functional_tests/students/test_enrollments.py b/backend/tests/functional_tests/students/test_enrollments.py new file mode 100644 index 0000000..455fa1d --- /dev/null +++ b/backend/tests/functional_tests/students/test_enrollments.py @@ -0,0 +1,298 @@ +import datetime + +from app.base.mode import EnrollmentsMode +from app.dependencies import db +from app.examination_schedule.models import ExaminationSchedule, TermOfDefence + +from ...factory import ( + ExaminationScheduleFactory, + GroupFactory, + StudentFactory, + ProjectSupervisorFactory, + TermOfDefenceFactory, + YearGroupFactory, +) +from ...utils import ( + _test_case_client, + _test_case_client_without_response, + assert_model_changes, + create_many_models, + create_one_model, + get_data_of_term_of_defence +) + + +def test_list_examination_schedule(test_app_with_context) -> None: + with test_app_with_context.test_client() as client: + year_group = create_one_model(YearGroupFactory) + st = create_one_model(StudentFactory, year_group_id=year_group.id) + create_many_models(23, ExaminationScheduleFactory, year_group_id=year_group.id) + url = f"/api/students/examination-schedule/year-group/{year_group.id}/?student_id={st.id}" + data = _test_case_client_without_response(client, url, None, 200, method="get") + assert len(data.get("examination_schedules")) == 23 + + +def test_list_examination_schedule_if_student_doesnt_exist(test_app_with_context) -> None: + with test_app_with_context.test_client() as client: + yg = create_one_model(YearGroupFactory) + _test_case_client( + client, + f"/api/students/examination-schedule/year-group/{yg.id}/?student_id=2", + None, + "Not found student!", + 404, + method="get", + key="error", + ) + + +def test_list_term_of_defences(test_app_with_context) -> None: + with test_app_with_context.test_client() as client: + year_group = create_one_model(YearGroupFactory) + st = create_one_model(StudentFactory, year_group_id=year_group.id) + ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id) + project_supervisors = create_many_models(13, ProjectSupervisorFactory, year_group_id=year_group.id) + ps = project_supervisors[0] + group = create_one_model(GroupFactory, year_group_id=year_group.id, project_supervisor_id=ps.id) + group.students.append(st) + db.session.commit() + + term_of_defences = create_many_models(13, TermOfDefenceFactory, examination_schedule_id=ex.id) + ps_amount = 6 + for i in range(ps_amount): + term_of_defences[i].members_of_committee.append(ps) + db.session.commit() + + url = f"/api/students/examination-schedule/{ex.id}/enrollments/?student_id={st.id}" + data = _test_case_client_without_response(client, url, None, 200, method="get") + assert len(data.get("term_of_defences")) == ps_amount + + +def test_list_term_of_defences_if_student_doesnt_exist(test_app_with_context) -> None: + with test_app_with_context.test_client() as client: + _test_case_client( + client, + "/api/students/examination-schedule/3/enrollments/?student_id=2", + None, + "Not found student!", + 404, + method="get", + key="error", + ) + + +def test_assign_your_group_to_term_of_defence(test_app_with_context) -> None: + with test_app_with_context.test_client() as client: + year_group = create_one_model(YearGroupFactory) + ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id, + open_enrollments=EnrollmentsMode.OPEN.value) + ps = create_one_model(ProjectSupervisorFactory, year_group_id=year_group.id) + st = create_one_model(StudentFactory, year_group_id=year_group.id) + td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id) + group = create_one_model(GroupFactory, year_group_id=year_group.id, project_supervisor_id=ps.id) + td.members_of_committee.append(ps) + group.students.append(st) + db.session.commit() + + _test_case_client( + client, + f"/api/students/{ex.id}/enrollments/{td.id}/", + {"student_id": st.id}, + "You have just assigned the group for this exam date!", + 201, + method="post", + ) + + +def test_assign_your_group_to_term_of_defence_if_student_doesnt_exist( + test_app_with_context, +) -> None: + with test_app_with_context.test_client() as client: + _test_case_client( + client, + "/api/students/3/enrollments/1/", + {"student_id": 2}, + "Not found student!", + 404, + method="post", + key="error", + ) + + +def test_assign_your_group_to_term_of_defence_if_term_of_defence_doesnt_exist( + test_app_with_context, +) -> None: + with test_app_with_context.test_client() as client: + st = create_one_model(StudentFactory) + _test_case_client( + client, + "/api/students/3/enrollments/1/", + {"student_id": st.id}, + "Term of defence not found!", + 404, + method="post", + key="error", + ) + + +def test_assign_your_group_to_term_of_defence_if_enrollments_havent_started_yet( + test_app_with_context, +) -> None: + with test_app_with_context.test_client() as client: + year_group = create_one_model(YearGroupFactory) + ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id) + td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id) + st = create_one_model(StudentFactory, year_group_id=year_group.id) + _test_case_client( + client, + f"/api/students/{ex.id}/enrollments/{td.id}/", + {"student_id": st.id}, + "Enrollments is closed! You have been delayed!", + 400, + method="post", + key="error", + ) + + +def test_assign_your_group_to_term_of_defence_if_you_dont_have_group( + test_app_with_context, +) -> None: + with test_app_with_context.test_client() as client: + year_group = create_one_model(YearGroupFactory) + ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id, + open_enrollments=EnrollmentsMode.OPEN.value) + td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id) + st = create_one_model(StudentFactory, year_group_id=year_group.id) + _test_case_client( + client, + f"/api/students/{ex.id}/enrollments/{td.id}/", + {"student_id": st.id}, + "You don't have a group or your group doesn't have an assigned project supervisor!", + 400, + method="post", + key="error", + ) + + +def test_assign_your_group_to_term_of_defence_if_your_group_has_already_assigned_to_any_term_of_defence( + test_app_with_context, +) -> None: + with test_app_with_context.test_client() as client: + year_group = create_one_model(YearGroupFactory) + ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id, + open_enrollments=EnrollmentsMode.OPEN.value) + td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id) + st = create_one_model(StudentFactory, year_group_id=year_group.id) + ps = create_one_model(ProjectSupervisorFactory, year_group_id=year_group.id) + group = create_one_model(GroupFactory, year_group_id=year_group.id, project_supervisor_id=ps.id) + td.group_id = group.id + group.students.append(st) + db.session.commit() + + _test_case_client( + client, + f"/api/students/{ex.id}/enrollments/{td.id}/", + {"student_id": st.id}, + "Your group has already assigned to any exam date!", + 400, + method="post", + key="error", + ) + +def test_assign_your_group_to_term_of_defence_if_your_project_supervisor_is_not_in_committee( + test_app_with_context, +) -> None: + with test_app_with_context.test_client() as client: + year_group = create_one_model(YearGroupFactory) + ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id, + open_enrollments=EnrollmentsMode.OPEN.value) + td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id) + st = create_one_model(StudentFactory, year_group_id=year_group.id) + ps = create_one_model(ProjectSupervisorFactory, year_group_id=year_group.id) + group = create_one_model(GroupFactory, year_group_id=year_group.id, project_supervisor_id=ps.id) + group.students.append(st) + db.session.commit() + + _test_case_client( + client, + f"/api/students/{ex.id}/enrollments/{td.id}/", + {"student_id": st.id}, + "Your project supervisor is not in committee!", + 400, + method="post", + key="error", + ) + +def test_delete_your_group_from_term_of_defence(test_app_with_context) -> None: + with test_app_with_context.test_client() as client: + year_group = create_one_model(YearGroupFactory) + ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id, + open_enrollments=EnrollmentsMode.OPEN.value) + ps = create_one_model(ProjectSupervisorFactory, year_group_id=year_group.id) + st = create_one_model(StudentFactory, year_group_id=year_group.id) + group = create_one_model(GroupFactory, year_group_id=year_group.id, project_supervisor_id=ps.id) + td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id, group_id=group.id) + td.members_of_committee.append(ps) + group.students.append(st) + db.session.commit() + + _test_case_client( + client, + f"/api/students/{ex.id}/enrollments/{td.id}/", + {"student_id": st.id}, + "You have just removed the group for this exam date!", + 200, + method="delete", + ) +def test_delete_your_group_from_term_of_defence_if_student_doesnt_exist( + test_app_with_context, +) -> None: + with test_app_with_context.test_client() as client: + _test_case_client( + client, + "/api/students/3/enrollments/1/", + {"student_id": 2}, + "Not found student!", + 404, + method="delete", + key="error", + ) + +def test_delete_your_group_from_term_of_defence_if_term_of_defence_doesnt_exist( + test_app_with_context, +) -> None: + with test_app_with_context.test_client() as client: + st = create_one_model(StudentFactory) + _test_case_client( + client, + "/api/students/3/enrollments/1/", + {"student_id": st.id}, + "Not found term of defence!", + 404, + method="delete", + key="error", + ) + +def test_assign_your_group_to_term_of_defence_if_you_try_delete_not_your_group( + test_app_with_context, +) -> None: + with test_app_with_context.test_client() as client: + year_group = create_one_model(YearGroupFactory) + ex = create_one_model(ExaminationScheduleFactory, year_group_id=year_group.id, + open_enrollments=EnrollmentsMode.OPEN.value) + td = create_one_model(TermOfDefenceFactory, examination_schedule_id=ex.id) + st = create_one_model(StudentFactory, year_group_id=year_group.id) + ps = create_one_model(ProjectSupervisorFactory, year_group_id=year_group.id) + group = create_one_model(GroupFactory, year_group_id=year_group.id, project_supervisor_id=ps.id) + td.group_id = group.id + db.session.commit() + + _test_case_client( + client, + f"/api/students/{ex.id}/enrollments/{td.id}/", + {"student_id": st.id}, + "You are not assigned to this group!", + 400, + method="delete", + key="error", + ) diff --git a/backend/tests/functional_tests/students/test_project_grade_sheet.py b/backend/tests/functional_tests/students/test_project_grade_sheet.py index e69de29..272ced1 100644 --- a/backend/tests/functional_tests/students/test_project_grade_sheet.py +++ b/backend/tests/functional_tests/students/test_project_grade_sheet.py @@ -0,0 +1,82 @@ +import copy + +from app.dependencies import db + +from ...factory import StudentFactory, GroupFactory, YearGroupFactory, ProjectGradeSheetFactory +from ...utils import ( + _test_case_client, + _test_case_client_without_response, + assert_model_changes, + create_many_models, + create_one_model, +) + +terms = [1, 2] + + +def test_detail_project_grade_sheet_first_term(test_app_with_context) -> None: + with test_app_with_context.test_client() as client: + for term in terms: + yg = create_one_model(YearGroupFactory) + group = create_one_model(GroupFactory, year_group_id=yg.id) + st = create_one_model(StudentFactory, year_group_id=yg.id) + pgs = create_one_model(ProjectGradeSheetFactory, group_id=group.id) + group.students.append(st) + db.session.commit() + data = _test_case_client_without_response( + client, + f"/api/students/project-grade-sheet/year-group/{yg.id}/?student_id={st.id}&term={term}", + None, + 200, + method="get", + ) + assert_model_changes(pgs, data) + + +def test_detail_student_if_student_doesnt_exist(test_app_with_context) -> None: + with test_app_with_context.test_client() as client: + for term in terms: + yg = create_one_model(YearGroupFactory) + _test_case_client( + client, + f"/api/students/project-grade-sheet/year-group/{yg.id}/?student_id=3&term={term}", + None, + "Not found student!", + 404, + method="get", + key="error", + ) + +def test_detail_student_if_group_doesnt_exist(test_app_with_context) -> None: + with test_app_with_context.test_client() as client: + for term in terms: + yg = create_one_model(YearGroupFactory) + st = create_one_model(StudentFactory, year_group_id=yg.id) + _test_case_client( + client, + f"/api/students/project-grade-sheet/year-group/{yg.id}/?student_id={st.id}&term={term}", + None, + "Not found group!", + 404, + method="get", + key="error", + ) + +def test_detail_student_if_project_grade_sheet_doesnt_exist(test_app_with_context) -> None: + with test_app_with_context.test_client() as client: + for term in terms: + yg = create_one_model(YearGroupFactory) + st = create_one_model(StudentFactory, year_group_id=yg.id) + group = create_one_model(GroupFactory, year_group_id=yg.id) + group.students.append(st) + db.session.commit() + _test_case_client( + client, + f"/api/students/project-grade-sheet/year-group/{yg.id}/?student_id={st.id}&term={term}", + None, + "Not found project grade sheet!", + 404, + method="get", + key="error", + ) + \ No newline at end of file diff --git a/backend/tests/functional_tests/students/test_registrations.py b/backend/tests/functional_tests/students/test_registrations.py index 704a7e3..6c5e3fc 100644 --- a/backend/tests/functional_tests/students/test_registrations.py +++ b/backend/tests/functional_tests/students/test_registrations.py @@ -1,32 +1,38 @@ from app.dependencies import db +from app.students.models import Group -from ...fake_data import create_groups, create_project_supervisors, create_year_group -from ...utils import _test_case_client_without_response, assert_model_changes +from ...utils import _test_case_client_without_response, create_many_models, create_one_model +from ...factory import GroupFactory, YearGroupFactory, ProjectSupervisorFactory -def test_list_year_group_for_specific_student(test_app_with_context) -> None: +def test_list_available_groups(test_app_with_context) -> None: with test_app_with_context.test_client() as client: - year_group = create_year_group() - amount_of_project_supervisors = 3 - project_supervisors = create_project_supervisors( - year_group, amount_of_project_supervisors - ) - groups = create_groups(year_group, 6) - - for i in range(1, 4): - for _ in range(i): - gr = groups.pop() - gr.project_supervisor_id = project_supervisors[i - 1].id + yg = create_one_model(YearGroupFactory) + amount = 6 + limit_group_1 = 4 + limit_group_2 = 2 + groups = create_many_models(amount, GroupFactory, year_group_id=yg.id) + ps1 = create_many_models(amount // 2, ProjectSupervisorFactory, year_group_id=yg.id, limit_group=limit_group_1) + ps2 = create_many_models(amount // 2, ProjectSupervisorFactory, year_group_id=yg.id, limit_group=limit_group_2) + for g, ps in zip(groups, [*ps1, *ps2]): + g.project_supervisor_id = ps.id db.session.commit() - url = f"/api/students/registrations/{year_group.id}/?per_page=10" - data = _test_case_client_without_response(client, url, None, 200, method="get") - assert data.get("max_pages") == 1 + data = _test_case_client_without_response( + client, + f"/api/students/registrations/{yg.id}/?per_page=10", + None, + 200, + method="get", + ) + project_supervisors = [*ps1, *ps2] project_supervisors_data = data.get("project_supervisors") - assert len(project_supervisors_data) == amount_of_project_supervisors + assert data.get("max_pages") == 1 + assert len(project_supervisors_data) == amount + for ps_data in project_supervisors_data: + for ps_obj in project_supervisors: + if ps_data['email'] == ps_obj.email: + assert ps_data['available_groups'] == (ps_obj.limit_group - Group.query.filter( + Group.project_supervisor_id == ps_obj.id).count()) + continue - for ps, expected_available_groups in zip(project_supervisors, [2, 1, 0]): - ps_dict = list( - filter(lambda p: p.get("email") == ps.email, project_supervisors_data) - )[0] - assert ps_dict.get("available_groups") == expected_available_groups diff --git a/backend/tests/functional_tests/students/test_year_group.py b/backend/tests/functional_tests/students/test_year_group.py deleted file mode 100644 index 7d9dace..0000000 --- a/backend/tests/functional_tests/students/test_year_group.py +++ /dev/null @@ -1,44 +0,0 @@ -from app.base.mode import ModeGroups -from app.dependencies import db -from app.students.models import YearGroupStudents - -from ...fake_data import create_student, create_year_group -from ...utils import _test_case_client, _test_case_client_without_response - -valid_data = {"first_name": "Dominic", "last_name": "Mozart", "index": 123_345} - -year_group_data = [ - {"name": "2022/2023", "mode": ModeGroups.STATIONARY.value}, - {"name": "2021/2022", "mode": ModeGroups.STATIONARY.value}, - {"name": "2023/2024", "mode": ModeGroups.NON_STATIONARY.value}, - {"name": "1997/1998", "mode": ModeGroups.NON_STATIONARY.value}, -] - - -def test_list_year_group_for_specific_student(test_app_with_context) -> None: - with test_app_with_context.test_client() as client: - year_groups = [create_year_group(data) for data in year_group_data] - student = create_student(valid_data) - for yg in year_groups[:-1]: - db.session.add( - YearGroupStudents(year_group_id=yg.id, student_index=student.index) - ) - db.session.commit() - - url = f"/api/students/year-group/?per_page=10&index={student.index}" - data = _test_case_client_without_response(client, url, None, 200, method="get") - assert data.get("max_pages") == 1 - assert len(data.get("year_groups")) == len(year_groups) - 1 - - -def test_list_year_group_if_student_doesnt_exist(test_app_with_context) -> None: - with test_app_with_context.test_client() as client: - _test_case_client( - client, - "/api/students/year-group/?per_page=10&index=23", - None, - "Not found student!", - 404, - method="get", - key="error", - ) diff --git a/backend/tests/utils.py b/backend/tests/utils.py index 5150c83..4d9123e 100644 --- a/backend/tests/utils.py +++ b/backend/tests/utils.py @@ -17,11 +17,11 @@ def assert_model_changes(model: db.Model, expected_data: dict) -> None: def _test_case_client_without_response( - test_client: FlaskClient, - url: str, - data: Union[dict, None], - status_code: int, - method: str = "post", + test_client: FlaskClient, + url: str, + data: Union[dict, None], + status_code: int, + method: str = "post", ) -> dict: method_func = getattr(test_client, method) if data is not None: @@ -34,13 +34,13 @@ def _test_case_client_without_response( def _test_case_client( - test_client: FlaskClient, - url: str, - data: Union[dict, None], - message: str, - status_code: int, - key: str = "message", - method: str = "post", + test_client: FlaskClient, + url: str, + data: Union[dict, None], + message: str, + status_code: int, + key: str = "message", + method: str = "post", ) -> dict: response_data = _test_case_client_without_response( test_client, url, data, status_code, method @@ -59,7 +59,7 @@ def _test_case_group(group: Group, data: dict) -> None: def create_many_models( - amount: int, factory: Type[SQLAlchemyModelFactory], **kwargs + amount: int, factory: Type[SQLAlchemyModelFactory], **kwargs ) -> List[SQLAlchemyModelFactory]: models = [factory(**kwargs) for _ in range(amount)] db.session.add_all(models) @@ -68,9 +68,9 @@ def create_many_models( def create_one_model( - model: Union[Type[db.Model], Type[SQLAlchemyModelFactory]], - data: dict = None, - **kwargs + model: Union[Type[db.Model], Type[SQLAlchemyModelFactory]], + data: dict = None, + **kwargs ) -> Union[db.Model, SQLAlchemyModelFactory]: if issubclass(model, SQLAlchemyModelFactory): m = model(**kwargs) # it's a factory @@ -79,3 +79,19 @@ def create_one_model( db.session.add(m) db.session.commit() return m + + +def get_data_of_term_of_defence(timedelta_minutes: int = 30) -> dict: + ex = ExaminationSchedule.query.first() + if ex is None: + date = datetime.datetime.now() + else: + date = ex.start_date + return { + "start_date": (date + datetime.timedelta(days=1)).strftime( + "%Y-%m-%dT%H:%M:%S.000Z" + ), + "end_date": ( + date + datetime.timedelta(days=1, minutes=timedelta_minutes) + ).strftime("%Y-%m-%dT%H:%M:%S.000Z"), + }