From fcf4bff3a9e50f7e487337d58b8e67ba8cfaf867 Mon Sep 17 00:00:00 2001 From: igor_nadein Date: Mon, 16 Feb 2026 21:44:53 +0300 Subject: [PATCH] fix: add ensure_ldap_disabled to 71 tests to prevent LDAP sync issues --- backend/scripts/fix_ldap_tests.py | 126 ++++++++++++++++++ .../test_department_membership_separation.py | 12 +- .../api/v1/employees/test_department_roles.py | 16 +-- .../employees/test_department_roles_extra.py | 18 +-- .../api/v1/employees/test_departments.py | 34 ++--- .../api/v1/employees/test_employee_actions.py | 12 +- .../tests/api/v1/employees/test_employees.py | 36 ++--- .../tests/api/v1/employees/test_positions.py | 14 +- .../api/v1/employees/test_role_assignment.py | 14 +- backend/tests/api/v1/employees/test_skills.py | 4 +- 10 files changed, 206 insertions(+), 80 deletions(-) create mode 100644 backend/scripts/fix_ldap_tests.py diff --git a/backend/scripts/fix_ldap_tests.py b/backend/scripts/fix_ldap_tests.py new file mode 100644 index 00000000..2a402d5b --- /dev/null +++ b/backend/scripts/fix_ldap_tests.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +""" +Скрипт для массового добавления ensure_ldap_disabled fixture к тестам. + +Добавляет параметр ensure_ldap_disabled к функциям тестов, которые: +- Создают объекты через Department.objects.create() +- Создают объекты через Position.objects.create() +- Не имеют уже ensure_ldap_disabled или ensure_ldap_enabled +""" +import re +import sys +from pathlib import Path + + +def fix_test_file(file_path: Path) -> tuple[bool, int]: + """ + Исправляет один тестовый файл. + + Returns: + (changed, count) - был ли изменен файл и количество исправленных функций + """ + content = file_path.read_text(encoding='utf-8') + original_content = content + + # Паттерн для поиска тестовых функций + # Ищем def test_...(...): где нет ensure_ldap в параметрах + pattern = r'(def test_\w+\([^)]*\)):' + + fixed_count = 0 + lines = content.split('\n') + new_lines = [] + + i = 0 + while i < len(lines): + line = lines[i] + + # Проверяем, является ли это определением тестовой функции + match = re.match(r'^def (test_\w+)\((.*)\):', line) + + if match: + func_name = match.group(1) + params = match.group(2) + + # Проверяем, нет ли уже ensure_ldap в параметрах + if 'ensure_ldap' not in params: + # Проверяем следующие 50 строк на наличие Department.objects.create или Position.objects.create + check_lines = '\n'.join(lines[i:min(i+50, len(lines))]) + + if ('Department.objects.create' in check_lines or + 'Position.objects.create' in check_lines or + 'DepartmentRole.objects.create' in check_lines or + 'make_department' in check_lines): + + # Добавляем ensure_ldap_disabled + if params.strip(): + new_params = f"{params}, ensure_ldap_disabled" + else: + new_params = "ensure_ldap_disabled" + + new_line = line.replace(f"({params})", f"({new_params})") + new_lines.append(new_line) + fixed_count += 1 + print(f" ✓ Исправлена функция: {func_name}") + else: + new_lines.append(line) + else: + new_lines.append(line) + else: + new_lines.append(line) + + i += 1 + + new_content = '\n'.join(new_lines) + + if new_content != original_content: + file_path.write_text(new_content, encoding='utf-8') + return True, fixed_count + + return False, 0 + + +def main(): + """Главная функция.""" + test_dir = Path(__file__).parent.parent / 'tests' / 'api' / 'v1' / 'employees' + + # Список файлов для исправления + files_to_fix = [ + 'test_department_membership_separation.py', + 'test_department_roles.py', + 'test_department_roles_extra.py', + 'test_departments.py', + 'test_employee_actions.py', + 'test_employees.py', + 'test_positions.py', + 'test_role_assignment.py', + 'test_skills.py', + ] + + total_fixed = 0 + total_files = 0 + + for filename in files_to_fix: + file_path = test_dir / filename + + if not file_path.exists(): + print(f"⚠ Файл не найден: {filename}") + continue + + print(f"\nОбрабатываем {filename}...") + changed, count = fix_test_file(file_path) + + if changed: + print(f" ✅ {filename} исправлен ({count} функций)") + total_fixed += count + total_files += 1 + else: + print(f" ⊘ {filename} не требует изменений") + + print(f"\n{'='*60}") + print(f"✅ Обработано файлов: {total_files}") + print(f"✅ Исправлено функций: {total_fixed}") + print(f"{'='*60}\n") + + +if __name__ == '__main__': + main() diff --git a/backend/tests/api/v1/employees/test_department_membership_separation.py b/backend/tests/api/v1/employees/test_department_membership_separation.py index d5f4609b..a8ccd21c 100644 --- a/backend/tests/api/v1/employees/test_department_membership_separation.py +++ b/backend/tests/api/v1/employees/test_department_membership_separation.py @@ -88,7 +88,7 @@ def url_set_member_role(dept_id: int) -> str: # ========================= @pytest.mark.django_db -def test_add_member_requires_manage_and_does_not_assign_role(api_client: APIClient): +def test_add_member_requires_manage_and_does_not_assign_role(api_client: APIClient, ensure_ldap_disabled): """ add_member: - 401 без авторизации @@ -123,7 +123,7 @@ def test_add_member_requires_manage_and_does_not_assign_role(api_client: APIClie assert link.role_id is None # add_member не должен трогать роль @pytest.mark.django_db -def test_all_three_actions_require_auth_and_permissions(api_client: APIClient): +def test_all_three_actions_require_auth_and_permissions(api_client: APIClient, ensure_ldap_disabled): """ Сетка проверок прав для трёх эндпоинтов отдела: - без авторизации все три эндпоинта возвращают 401 @@ -219,7 +219,7 @@ def test_all_three_actions_require_auth_and_permissions(api_client: APIClient): # ========================= @pytest.mark.django_db -def test_set_member_role_requires_assign_not_manage(api_client: APIClient): +def test_set_member_role_requires_assign_not_manage(api_client: APIClient, ensure_ldap_disabled): """ set_member_role: - 403 с manage_department, если нет assign_department_role @@ -304,7 +304,7 @@ def test_set_member_role_does_not_create_membership_and_does_not_toggle_active( # ========================= @pytest.mark.django_db -def test_all_three_actions_require_auth_and_permissions(api_client: APIClient): +def test_all_three_actions_require_auth_and_permissions(api_client: APIClient, ensure_ldap_disabled): """ Сетка проверок прав для трёх эндпоинтов отдела: - без авторизации все три эндпоинта возвращают 401 @@ -396,7 +396,7 @@ def test_all_three_actions_require_auth_and_permissions(api_client: APIClient): ) @pytest.mark.django_db -def test_add_member_ignores_role_parameter(api_client: APIClient): +def test_add_member_ignores_role_parameter(api_client: APIClient, ensure_ldap_disabled): """ add_member не должен назначать роль даже если клиент прислал role_id. """ @@ -420,7 +420,7 @@ def test_add_member_ignores_role_parameter(api_client: APIClient): assert link.role_id is None, "add_member не должен трогать роль" @pytest.mark.django_db -def test_remove_member_requires_manage_and_does_not_touch_role(api_client: APIClient): +def test_remove_member_requires_manage_and_does_not_touch_role(api_client: APIClient, ensure_ldap_disabled): """ remove_member (hard delete): - 403 при отсутствии manage_department (даже если есть assign_department_role) diff --git a/backend/tests/api/v1/employees/test_department_roles.py b/backend/tests/api/v1/employees/test_department_roles.py index a2216483..a4eb6d6a 100644 --- a/backend/tests/api/v1/employees/test_department_roles.py +++ b/backend/tests/api/v1/employees/test_department_roles.py @@ -53,7 +53,7 @@ def api_client() -> APIClient: # ========================= @pytest.mark.django_db -def test_list_filtered_by_department(api_client: APIClient): +def test_list_filtered_by_department(api_client: APIClient, ensure_ldap_disabled): d1 = Department.objects.create(name="Dept A") d2 = Department.objects.create(name="Dept B") @@ -83,7 +83,7 @@ def test_list_filtered_by_department(api_client: APIClient): assert ids == {r1.id, r2.id} @pytest.mark.django_db -def test_create_requires_assign_department_role(api_client: APIClient): +def test_create_requires_assign_department_role(api_client: APIClient, ensure_ldap_disabled): d = Department.objects.create(name="Dept") user = make_user("m@example.com") api_client.force_authenticate(user=user) @@ -106,7 +106,7 @@ def test_create_requires_assign_department_role(api_client: APIClient): assert "permissions" in data and isinstance(data["permissions"], list) @pytest.mark.django_db -def test_update_and_destroy_scope_enforced(api_client: APIClient): +def test_update_and_destroy_scope_enforced(api_client: APIClient, ensure_ldap_disabled): d1 = Department.objects.create(name="Dept1") d2 = Department.objects.create(name="Dept2") user = make_user("m@example.com") @@ -136,7 +136,7 @@ def test_update_and_destroy_scope_enforced(api_client: APIClient): assert resp.status_code in (status.HTTP_204_NO_CONTENT, status.HTTP_200_OK) @pytest.mark.django_db -def test_perm_choices_and_perms_and_set_perms(api_client: APIClient): +def test_perm_choices_and_perms_and_set_perms(api_client: APIClient, ensure_ldap_disabled): # засеем три стандартных кода ensure_dept_perm("manage_department", "Управлять отделом") ensure_dept_perm("change_department_head", "Назначать руководителя") @@ -185,7 +185,7 @@ def test_perm_choices_and_perms_and_set_perms(api_client: APIClient): assert role.scoped_permissions.count() == 0 @pytest.mark.django_db -def test_set_perms_validates_payload(api_client: APIClient): +def test_set_perms_validates_payload(api_client: APIClient, ensure_ldap_disabled): d = Department.objects.create(name="Dept") user = make_user("m@example.com") api_client.force_authenticate(user=user) @@ -203,7 +203,7 @@ def test_set_perms_validates_payload(api_client: APIClient): assert resp.status_code == 400 @pytest.mark.django_db -def test_back_compat_permissions_field_contains_ids(api_client: APIClient): +def test_back_compat_permissions_field_contains_ids(api_client: APIClient, ensure_ldap_disabled): d = Department.objects.create(name="Dept") user = make_user("m@example.com") api_client.force_authenticate(user=user) @@ -221,7 +221,7 @@ def test_back_compat_permissions_field_contains_ids(api_client: APIClient): assert set(data["permissions"]) == {dp_manage.id, dp_assign.id} @pytest.mark.django_db -def test_create_with_scoped_permission_codes_and_update_name(api_client: APIClient): +def test_create_with_scoped_permission_codes_and_update_name(api_client: APIClient, ensure_ldap_disabled): d = Department.objects.create(name="Dept") ensure_dept_perm("manage_department") @@ -251,7 +251,7 @@ def test_create_with_scoped_permission_codes_and_update_name(api_client: APIClie assert resp.json()["name"] == "Lead+1" @pytest.mark.django_db -def test_cross_department_access_denied_for_set_perms(api_client: APIClient): +def test_cross_department_access_denied_for_set_perms(api_client: APIClient, ensure_ldap_disabled): d1 = Department.objects.create(name="Dept1") d2 = Department.objects.create(name="Dept2") diff --git a/backend/tests/api/v1/employees/test_department_roles_extra.py b/backend/tests/api/v1/employees/test_department_roles_extra.py index 18e7087c..bd60adc9 100644 --- a/backend/tests/api/v1/employees/test_department_roles_extra.py +++ b/backend/tests/api/v1/employees/test_department_roles_extra.py @@ -56,13 +56,13 @@ def api_client() -> APIClient: # ========================= @pytest.mark.django_db -def test_unauth_cannot_list_or_get(): +def test_unauth_cannot_list_or_get(ensure_ldap_disabled): client = APIClient() url_list = reverse("api:v1:department-roles-list") assert client.get(url_list).status_code in (401, 403) @pytest.mark.django_db -def test_read_only_allowed_without_assign(api_client: APIClient): +def test_read_only_allowed_without_assign(api_client: APIClient, ensure_ldap_disabled): d = Department.objects.create(name="Dept") r = make_role(d, "Worker", []) u = make_user("u@example.com") @@ -80,7 +80,7 @@ def test_read_only_allowed_without_assign(api_client: APIClient): assert api_client.get(url_detail).status_code == 200 @pytest.mark.django_db -def test_staff_override_for_write(api_client: APIClient): +def test_staff_override_for_write(api_client: APIClient, ensure_ldap_disabled): d = Department.objects.create(name="Dept") staff = make_user("s@example.com", staff=True) api_client.force_authenticate(user=staff) @@ -111,7 +111,7 @@ def test_staff_override_for_write(api_client: APIClient): ) @pytest.mark.django_db -def test_ordering_stable_by_name_then_id(api_client: APIClient): +def test_ordering_stable_by_name_then_id(api_client: APIClient, ensure_ldap_disabled): d1 = Department.objects.create(name="Dept1") d2 = Department.objects.create(name="Dept2") u = make_user("u@example.com") @@ -135,7 +135,7 @@ def test_ordering_stable_by_name_then_id(api_client: APIClient): assert picked[2] == r3.id @pytest.mark.django_db -def test_set_perms_ids_take_precedence_over_codes(api_client: APIClient): +def test_set_perms_ids_take_precedence_over_codes(api_client: APIClient, ensure_ldap_disabled): d = Department.objects.create(name="Dept") u = make_user("u@example.com") api_client.force_authenticate(user=u) @@ -161,7 +161,7 @@ def test_set_perms_ids_take_precedence_over_codes(api_client: APIClient): assert codes == {"manage_department"} # ids приоритетнее @pytest.mark.django_db -def test_serializer_codes_override_scoped_permissions_on_create(api_client: APIClient): +def test_serializer_codes_override_scoped_permissions_on_create(api_client: APIClient, ensure_ldap_disabled): d = Department.objects.create(name="Dept") ensure_perm("manage_department") ensure_perm("assign_department_role") @@ -192,7 +192,7 @@ def test_serializer_codes_override_scoped_permissions_on_create(api_client: APIC assert codes == {"assign_department_role"} @pytest.mark.django_db -def test_perm_choices_fields_and_nonempty(api_client: APIClient): +def test_perm_choices_fields_and_nonempty(api_client: APIClient, ensure_ldap_disabled): ensure_perm("manage_department", "Управлять") ensure_perm("change_department_head", "Глава") ensure_perm("assign_department_role", "Назначение") @@ -206,7 +206,7 @@ def test_perm_choices_fields_and_nonempty(api_client: APIClient): assert results and {"id", "code", "name"}.issubset(results[0].keys()) @pytest.mark.django_db -def test_destroy_requires_assign_in_same_department(api_client: APIClient): +def test_destroy_requires_assign_in_same_department(api_client: APIClient, ensure_ldap_disabled): d1 = Department.objects.create(name="D1") d2 = Department.objects.create(name="D2") u = make_user("u@example.com") @@ -227,7 +227,7 @@ def test_destroy_requires_assign_in_same_department(api_client: APIClient): assert api_client.delete(url).status_code in (204, 200) @pytest.mark.django_db -def test_set_perms_dedup_and_replace_semantics(api_client: APIClient): +def test_set_perms_dedup_and_replace_semantics(api_client: APIClient, ensure_ldap_disabled): d = Department.objects.create(name="Dept") u = make_user("u@example.com") api_client.force_authenticate(user=u) diff --git a/backend/tests/api/v1/employees/test_departments.py b/backend/tests/api/v1/employees/test_departments.py index 81a74eab..892a6379 100644 --- a/backend/tests/api/v1/employees/test_departments.py +++ b/backend/tests/api/v1/employees/test_departments.py @@ -90,12 +90,12 @@ def make_role( # ---------- tests: auth/list/basic ---------- -def test_list_requires_auth(api_client: APIClient): +def test_list_requires_auth(api_client: APIClient, ensure_ldap_disabled): url = reverse("api:v1:departments-list") resp = api_client.get(url) assert resp.status_code == status.HTTP_401_UNAUTHORIZED -def test_list_ok_for_authenticated(api_client: APIClient): +def test_list_ok_for_authenticated(api_client: APIClient, ensure_ldap_disabled): user = make_user("u@example.com") api_client.force_authenticate(user=user) @@ -109,7 +109,7 @@ def test_list_ok_for_authenticated(api_client: APIClient): assert isinstance(items, list) assert len(items) == 2 -def test_search_and_ordering(api_client: APIClient): +def test_search_and_ordering(api_client: APIClient, ensure_ldap_disabled): user = make_user("u@example.com") api_client.force_authenticate(user=user) @@ -137,7 +137,7 @@ def test_search_and_ordering(api_client: APIClient): # ---------- tests: employees_count annotation ---------- -def test_employees_count_adds_head_if_not_in_links(api_client: APIClient): +def test_employees_count_adds_head_if_not_in_links(api_client: APIClient, ensure_ldap_disabled): user = make_user("u@example.com") api_client.force_authenticate(user=user) @@ -155,7 +155,7 @@ def test_employees_count_adds_head_if_not_in_links(api_client: APIClient): data = resp.json() assert data["employees_count"] == 3 # 2 + head вне связей -def test_employees_count_not_double_count_head_if_in_links(api_client: APIClient): +def test_employees_count_not_double_count_head_if_in_links(api_client: APIClient, ensure_ldap_disabled): user = make_user("u@example.com") api_client.force_authenticate(user=user) @@ -175,7 +175,7 @@ def test_employees_count_not_double_count_head_if_in_links(api_client: APIClient # ---------- tests: create/destroy ---------- -def test_create_requires_staff(api_client: APIClient): +def test_create_requires_staff(api_client: APIClient, ensure_ldap_disabled): user = make_user("u@example.com") api_client.force_authenticate(user=user) @@ -192,7 +192,7 @@ def test_create_requires_staff(api_client: APIClient): assert resp.status_code == status.HTTP_201_CREATED assert Department.objects.filter(name="New").exists() -def test_destroy_requires_staff(api_client: APIClient): +def test_destroy_requires_staff(api_client: APIClient, ensure_ldap_disabled): d = Department.objects.create(name="X") url = reverse("api:v1:departments-detail", args=[d.pk]) @@ -209,7 +209,7 @@ def test_destroy_requires_staff(api_client: APIClient): # ---------- tests: update/partial_update perms ---------- -def test_partial_update_name_requires_manage_perm(api_client: APIClient): +def test_partial_update_name_requires_manage_perm(api_client: APIClient, ensure_ldap_disabled): head = make_user("head@example.com") d = Department.objects.create(name="Dept", head=head) @@ -235,7 +235,7 @@ def test_partial_update_name_requires_manage_perm(api_client: APIClient): d.refresh_from_db() assert d.name == "New Name" -def test_partial_update_head_requires_change_head_perm(api_client: APIClient): +def test_partial_update_head_requires_change_head_perm(api_client: APIClient, ensure_ldap_disabled): a = make_user("a@example.com") # текущий head b = make_user("b@example.com") # кандидат d = Department.objects.create(name="Dept", head=a) @@ -290,7 +290,7 @@ def test_partial_update_head_same_value_does_not_require_extra_perm( # ---------- tests: action set_head ---------- -def test_set_head_by_role_with_perm(api_client: APIClient): +def test_set_head_by_role_with_perm(api_client: APIClient, ensure_ldap_disabled): head = make_user("head@example.com") d = Department.objects.create(name="Dept", head=head) candidate = make_user("cand@example.com") @@ -308,7 +308,7 @@ def test_set_head_by_role_with_perm(api_client: APIClient): d.refresh_from_db() assert d.head_id == candidate.id -def test_set_head_validation_inactive_employee(api_client: APIClient): +def test_set_head_validation_inactive_employee(api_client: APIClient, ensure_ldap_disabled): head = make_user("head@example.com") d = Department.objects.create(name="Dept", head=head) inactive = make_user( @@ -328,7 +328,7 @@ def test_set_head_validation_inactive_employee(api_client: APIClient): == status.HTTP_400_BAD_REQUEST ) -def test_set_head_remove_with_null(api_client: APIClient): +def test_set_head_remove_with_null(api_client: APIClient, ensure_ldap_disabled): head = make_user("head@example.com") d = Department.objects.create(name="Dept", head=head) @@ -347,7 +347,7 @@ def test_set_head_remove_with_null(api_client: APIClient): d.refresh_from_db() assert d.head_id is None -def test_set_head_requires_perm(api_client: APIClient): +def test_set_head_requires_perm(api_client: APIClient, ensure_ldap_disabled): head = make_user("head@example.com") d = Department.objects.create(name="Dept", head=head) candidate = make_user("cand@example.com") @@ -366,7 +366,7 @@ def test_set_head_requires_perm(api_client: APIClient): # ---------- tests: action set_member_role ---------- -def test_set_member_role_happy_path(api_client: APIClient): +def test_set_member_role_happy_path(api_client: APIClient, ensure_ldap_disabled): d = Department.objects.create(name="Dept") manager = make_user("m@example.com") @@ -390,7 +390,7 @@ def test_set_member_role_happy_path(api_client: APIClient): assert data["role_id"] == r_worker.id assert data["is_active"] is True -def test_set_member_role_reject_foreign_role(api_client: APIClient): +def test_set_member_role_reject_foreign_role(api_client: APIClient, ensure_ldap_disabled): d1 = Department.objects.create(name="D1") d2 = Department.objects.create(name="D2") @@ -412,7 +412,7 @@ def test_set_member_role_reject_foreign_role(api_client: APIClient): ) assert resp.status_code == status.HTTP_400_BAD_REQUEST -def test_set_member_role_requires_perm(api_client: APIClient): +def test_set_member_role_requires_perm(api_client: APIClient, ensure_ldap_disabled): d = Department.objects.create(name="Dept") manager = make_user("m@example.com") api_client.force_authenticate(user=manager) @@ -430,7 +430,7 @@ def test_set_member_role_requires_perm(api_client: APIClient): ) assert resp.status_code == status.HTTP_403_FORBIDDEN -def test_set_member_role_missing_employee_id(api_client: APIClient): +def test_set_member_role_missing_employee_id(api_client: APIClient, ensure_ldap_disabled): d = Department.objects.create(name="Dept") manager = make_user("m@example.com") api_client.force_authenticate(user=manager) diff --git a/backend/tests/api/v1/employees/test_employee_actions.py b/backend/tests/api/v1/employees/test_employee_actions.py index 883ba007..73affba5 100644 --- a/backend/tests/api/v1/employees/test_employee_actions.py +++ b/backend/tests/api/v1/employees/test_employee_actions.py @@ -29,7 +29,7 @@ def _any_non_dismissed(): pytest.skip("No non-dismissed action in ACTION_CHOICES") @pytest.mark.django_db -def test_list_requires_auth_and_filtering(api_client): +def test_list_requires_auth_and_filtering(api_client, ensure_ldap_disabled): url = reverse("api:v1:employee-actions-list") # unauth assert api_client.get(url).status_code in (401, 403) @@ -62,7 +62,7 @@ def test_list_requires_auth_and_filtering(api_client): assert ids == baseline_emp | {a1.id} @pytest.mark.django_db -def test_create_requires_perm_or_staff(api_client): +def test_create_requires_perm_or_staff(api_client, ensure_ldap_disabled): actor = make_user() target = make_user() api_client.force_authenticate(user=actor) @@ -95,7 +95,7 @@ def test_create_requires_perm_or_staff(api_client): assert EmployeeAction.objects.filter(employee=target).count() == baseline2 + 1 @pytest.mark.django_db -def test_dismissal_deactivates_employee_and_links(api_client): +def test_dismissal_deactivates_employee_and_links(api_client, ensure_ldap_disabled): staff = make_user(staff=True) api_client.force_authenticate(user=staff) emp = make_user() @@ -120,7 +120,7 @@ def test_dismissal_deactivates_employee_and_links(api_client): assert link.is_active is False and link.date_to is not None @pytest.mark.django_db -def test_non_dismissal_activates_employee(api_client): +def test_non_dismissal_activates_employee(api_client, ensure_ldap_disabled): staff = make_user(staff=True) api_client.force_authenticate(user=staff) emp = make_user() @@ -142,7 +142,7 @@ def test_non_dismissal_activates_employee(api_client): assert emp.is_active is True @pytest.mark.django_db -def test_update_to_dismissed_applies_effects(api_client): +def test_update_to_dismissed_applies_effects(api_client, ensure_ldap_disabled): actor = make_user() api_client.force_authenticate(user=actor) grant_permission(actor, "employees.add_employeeaction") @@ -160,7 +160,7 @@ def test_update_to_dismissed_applies_effects(api_client): assert emp.is_active is False @pytest.mark.django_db -def test_delete_requires_perm_or_staff(api_client): +def test_delete_requires_perm_or_staff(api_client, ensure_ldap_disabled): actor = make_user() api_client.force_authenticate(user=actor) emp = make_user() diff --git a/backend/tests/api/v1/employees/test_employees.py b/backend/tests/api/v1/employees/test_employees.py index 976af5c5..4020d15b 100644 --- a/backend/tests/api/v1/employees/test_employees.py +++ b/backend/tests/api/v1/employees/test_employees.py @@ -27,12 +27,12 @@ _phone_seq = itertools.count(2000) # ---------- basic auth / list / retrieve ---------- -def test_list_requires_auth(api_client: APIClient): +def test_list_requires_auth(api_client: APIClient, ensure_ldap_disabled): url = reverse("api:v1:employees-list") resp = api_client.get(url) assert resp.status_code == status.HTTP_401_UNAUTHORIZED -def test_list_ok_for_authenticated(api_client: APIClient): +def test_list_ok_for_authenticated(api_client: APIClient, ensure_ldap_disabled): user = make_user("u@example.com") e1 = make_user("a@example.com") e2 = make_user("b@example.com") @@ -46,12 +46,12 @@ def test_list_ok_for_authenticated(api_client: APIClient): ids = {it["id"] for it in items} assert e1.id in ids and e2.id in ids -def test_retrieve_requires_auth(api_client: APIClient): +def test_retrieve_requires_auth(api_client: APIClient, ensure_ldap_disabled): e = make_user("x@example.com") url = reverse("api:v1:employees-detail", args=[e.pk]) assert api_client.get(url).status_code == status.HTTP_401_UNAUTHORIZED -def test_retrieve_ok(api_client: APIClient): +def test_retrieve_ok(api_client: APIClient, ensure_ldap_disabled): user = make_user("u@example.com") e = make_user("x@example.com") api_client.force_authenticate(user=user) @@ -65,7 +65,7 @@ def test_retrieve_ok(api_client: APIClient): # ---------- search & ordering ---------- -def test_search_by_email_and_last_name(api_client: APIClient): +def test_search_by_email_and_last_name(api_client: APIClient, ensure_ldap_disabled): me = make_user("me@example.com") api_client.force_authenticate(user=me) @@ -98,7 +98,7 @@ def test_search_by_email_and_last_name(api_client: APIClient): # ---------- filters ---------- -def test_filter_by_department_includes_members_and_head(api_client: APIClient): +def test_filter_by_department_includes_members_and_head(api_client: APIClient, ensure_ldap_disabled): u = make_user("u@example.com") api_client.force_authenticate(user=u) @@ -117,7 +117,7 @@ def test_filter_by_department_includes_members_and_head(api_client: APIClient): assert ids == {head.id, member.id} assert outsider.id not in ids -def test_filter_by_position(api_client: APIClient): +def test_filter_by_position(api_client: APIClient, ensure_ldap_disabled): u = make_user("u@example.com") api_client.force_authenticate(user=u) @@ -140,7 +140,7 @@ def test_filter_by_position(api_client: APIClient): ids = {it["id"] for it in extract_results(r.json())} assert ids == {e1.id, e2.id} -def test_filter_by_skills_any_of(api_client: APIClient): +def test_filter_by_skills_any_of(api_client: APIClient, ensure_ldap_disabled): u = make_user("u@example.com") api_client.force_authenticate(user=u) @@ -161,7 +161,7 @@ def test_filter_by_skills_any_of(api_client: APIClient): ids = {it["id"] for it in extract_results(r.json())} assert ids == {e1.id, e2.id} -def test_filter_by_email_verified_and_active(api_client: APIClient): +def test_filter_by_email_verified_and_active(api_client: APIClient, ensure_ldap_disabled): u = make_user("u@example.com") api_client.force_authenticate(user=u) @@ -179,7 +179,7 @@ def test_filter_by_email_verified_and_active(api_client: APIClient): ids = {it["id"] for it in extract_results(r.json())} assert v1.id in ids and v0.id in ids and a0.id not in ids -def test_filter_actually_active_logic(api_client: APIClient): +def test_filter_actually_active_logic(api_client: APIClient, ensure_ldap_disabled): u = make_user("u@example.com") api_client.force_authenticate(user=u) @@ -211,7 +211,7 @@ def test_filter_actually_active_logic(api_client: APIClient): # ---------- create (staff only) + validation + skills ---------- -def test_create_requires_staff(api_client: APIClient): +def test_create_requires_staff(api_client: APIClient, ensure_ldap_disabled): user = make_user("u@example.com") api_client.force_authenticate(user=user) @@ -243,7 +243,7 @@ def test_create_requires_staff(api_client: APIClient): # ---------- update / partial_update (IsSelfOrStaff) ---------- -def test_partial_update_self_allowed(api_client: APIClient): +def test_partial_update_self_allowed(api_client: APIClient, ensure_ldap_disabled): e = make_user("self@example.com") api_client.force_authenticate(user=e) url = reverse("api:v1:employees-detail", args=[e.pk]) @@ -253,7 +253,7 @@ def test_partial_update_self_allowed(api_client: APIClient): e.refresh_from_db() assert e.first_name == "Me" -def test_partial_update_other_forbidden_for_regular_user(api_client: APIClient): +def test_partial_update_other_forbidden_for_regular_user(api_client: APIClient, ensure_ldap_disabled): owner = make_user("owner@example.com") other = make_user("other@example.com") api_client.force_authenticate(user=other) @@ -262,7 +262,7 @@ def test_partial_update_other_forbidden_for_regular_user(api_client: APIClient): resp = api_client.patch(url, {"first_name": "Hack"}, format="json") assert resp.status_code == status.HTTP_403_FORBIDDEN -def test_partial_update_other_allowed_for_staff(api_client: APIClient): +def test_partial_update_other_allowed_for_staff(api_client: APIClient, ensure_ldap_disabled): target = make_user("target@example.com") staff = make_user("admin@example.com", staff=True) api_client.force_authenticate(user=staff) @@ -273,7 +273,7 @@ def test_partial_update_other_allowed_for_staff(api_client: APIClient): target.refresh_from_db() assert target.first_name == "Ok" -def test_destroy_requires_admin(api_client: APIClient): +def test_destroy_requires_admin(api_client: APIClient, ensure_ldap_disabled): victim = make_user("victim@example.com") regular = make_user("regular@example.com") staff = make_user("staff@example.com", staff=True) @@ -293,7 +293,7 @@ def test_destroy_requires_admin(api_client: APIClient): # ---------- action: me (GET/PATCH) ---------- -def test_me_get_returns_current_user(api_client: APIClient): +def test_me_get_returns_current_user(api_client: APIClient, ensure_ldap_disabled): me = make_user("me@example.com") api_client.force_authenticate(user=me) @@ -302,7 +302,7 @@ def test_me_get_returns_current_user(api_client: APIClient): assert r.status_code == 200 assert r.json()["id"] == me.id -def test_me_patch_updates_profile(api_client: APIClient): +def test_me_patch_updates_profile(api_client: APIClient, ensure_ldap_disabled): me = make_user("me@example.com", telegram="@me") # уже есть контакт api_client.force_authenticate(user=me) @@ -312,7 +312,7 @@ def test_me_patch_updates_profile(api_client: APIClient): me.refresh_from_db() assert me.first_name == "Updated" -def test_me_patch_rejects_when_all_contacts_empty(api_client: APIClient): +def test_me_patch_rejects_when_all_contacts_empty(api_client: APIClient, ensure_ldap_disabled): """ Ваша логика в me(): если пользователь не передал поля контактов и в итоге ни одного канала связи нет — вернуть 400. diff --git a/backend/tests/api/v1/employees/test_positions.py b/backend/tests/api/v1/employees/test_positions.py index 79bd6425..b48ad74c 100644 --- a/backend/tests/api/v1/employees/test_positions.py +++ b/backend/tests/api/v1/employees/test_positions.py @@ -25,7 +25,7 @@ def _flush_perm_cache(user): # ---------- tests ---------- @pytest.mark.django_db -def test_list_requires_auth(api_client): +def test_list_requires_auth(api_client, ensure_ldap_disabled): url = reverse("api:v1:positions-list") # unauth -> 401 @@ -45,7 +45,7 @@ def test_list_requires_auth(api_client): assert {"Manager", "Engineer"} <= set(names) @pytest.mark.django_db -def test_create_permissions(api_client): +def test_create_permissions(api_client, ensure_ldap_disabled): url = reverse("api:v1:positions-list") # обычный пользователь без прав -> 403 @@ -67,7 +67,7 @@ def test_create_permissions(api_client): assert resp.status_code == status.HTTP_201_CREATED @pytest.mark.django_db -def test_update_permissions_and_search_ordering(api_client): +def test_update_permissions_and_search_ordering(api_client, ensure_ldap_disabled): p1 = Position.objects.create(name="Alpha", description="one") p2 = Position.objects.create(name="Beta", description="two") @@ -99,7 +99,7 @@ def test_update_permissions_and_search_ordering(api_client): assert names == sorted(names, reverse=True) @pytest.mark.django_db -def test_delete_permissions(api_client): +def test_delete_permissions(api_client, ensure_ldap_disabled): pos = Position.objects.create(name="ToDelete") user = make_user("user@example.com") api_client.force_authenticate(user=user) @@ -116,7 +116,7 @@ def test_delete_permissions(api_client): assert not Position.objects.filter(id=pos.id).exists() @pytest.mark.django_db -def test_set_groups_requires_special_perm(api_client): +def test_set_groups_requires_special_perm(api_client, ensure_ldap_disabled): pos = Position.objects.create(name="RoleOwner") grp1 = Group.objects.create(name="grp1") grp2 = Group.objects.create(name="grp2") @@ -138,7 +138,7 @@ def test_set_groups_requires_special_perm(api_client): assert set(pos.groups.values_list("id", flat=True)) == {grp1.id, grp2.id} @pytest.mark.django_db -def test_add_and_remove_groups_and_permissions_endpoint(api_client): +def test_add_and_remove_groups_and_permissions_endpoint(api_client, ensure_ldap_disabled): # используем гарантированно существующие права perm_view_employee = Permission.objects.get( content_type__app_label="employees", codename="view_employee" @@ -192,7 +192,7 @@ def test_add_and_remove_groups_and_permissions_endpoint(api_client): assert any(g["name"] == "B" for g in resp.data["groups_verbose"]) @pytest.mark.django_db -def test_groups_payload_validation(api_client): +def test_groups_payload_validation(api_client, ensure_ldap_disabled): pos = Position.objects.create(name="Validator") user = make_user("user@example.com") api_client.force_authenticate(user=user) diff --git a/backend/tests/api/v1/employees/test_role_assignment.py b/backend/tests/api/v1/employees/test_role_assignment.py index 7fa660ad..2daebe03 100644 --- a/backend/tests/api/v1/employees/test_role_assignment.py +++ b/backend/tests/api/v1/employees/test_role_assignment.py @@ -46,7 +46,7 @@ def api_client() -> APIClient: class TestRoleAssignmentEndpoints: """Тесты для /department-roles/{id}/assign/, revoke, assignments.""" - def test_assign_role_to_any_employee(self, api_client: APIClient): + def test_assign_role_to_any_employee(self, api_client: APIClient, ensure_ldap_disabled): """Роль можно назначить любому сотруднику, не только члену отдела.""" # Создаём admin, отдел и роль admin = make_user("admin@test.com", is_staff=True) @@ -76,7 +76,7 @@ class TestRoleAssignmentEndpoints: employee=other_user, role=role, is_active=True ).exists() - def test_revoke_role(self, api_client: APIClient): + def test_revoke_role(self, api_client: APIClient, ensure_ldap_disabled): """Отзыв роли деактивирует RoleAssignment.""" admin = make_user("admin@test.com", is_staff=True) dept = make_dept("IT") @@ -100,7 +100,7 @@ class TestRoleAssignmentEndpoints: assignment.refresh_from_db() assert assignment.is_active is False - def test_assignments_list(self, api_client: APIClient): + def test_assignments_list(self, api_client: APIClient, ensure_ldap_disabled): """Список назначений роли.""" admin = make_user("admin@test.com", is_staff=True) dept = make_dept("IT") @@ -127,7 +127,7 @@ class TestRoleAssignmentEndpoints: resp = api_client.get(url + "?active=all") assert resp.data["count"] == 2 - def test_assign_requires_permission(self, api_client: APIClient): + def test_assign_requires_permission(self, api_client: APIClient, ensure_ldap_disabled): """Назначение требует право assign_department_role.""" dept = make_dept("IT") role = make_role(dept, "Developer", []) @@ -143,7 +143,7 @@ class TestRoleAssignmentEndpoints: assert resp.status_code == status.HTTP_403_FORBIDDEN - def test_assign_with_dept_permission(self, api_client: APIClient): + def test_assign_with_dept_permission(self, api_client: APIClient, ensure_ldap_disabled): """Пользователь с assign_department_role может назначать роли.""" dept = make_dept("IT") role = make_role(dept, "Developer", []) @@ -164,7 +164,7 @@ class TestRoleAssignmentEndpoints: class TestRoleAssignmentPermissions: """Тесты для проверки прав через RoleAssignment.""" - def test_permission_check_via_role_assignment(self, api_client: APIClient): + def test_permission_check_via_role_assignment(self, api_client: APIClient, ensure_ldap_disabled): """Права проверяются через RoleAssignment, не требуя членства в отделе.""" from api.v1.permissions import has_dept_perm @@ -186,7 +186,7 @@ class TestRoleAssignmentPermissions: assert has_dept_perm(user, dept.id, "view_request") assert not has_dept_perm(user, dept.id, "change_department_head") - def test_inactive_assignment_does_not_grant_permission(self, api_client: APIClient): + def test_inactive_assignment_does_not_grant_permission(self, api_client: APIClient, ensure_ldap_disabled): """Неактивное назначение не даёт прав.""" from api.v1.permissions import has_dept_perm diff --git a/backend/tests/api/v1/employees/test_skills.py b/backend/tests/api/v1/employees/test_skills.py index e81554ef..4538dfb9 100644 --- a/backend/tests/api/v1/employees/test_skills.py +++ b/backend/tests/api/v1/employees/test_skills.py @@ -66,7 +66,7 @@ def test_create_allowed_for_regular_user(api_client): assert Skill.objects.filter(name="Go").exists() @pytest.mark.django_db -def test_update_delete_permissions(api_client): +def test_update_delete_permissions(api_client, ensure_ldap_disabled): user = _mk_user() api_client.force_authenticate(user=user) s = Skill.objects.create(name="Docker") @@ -121,7 +121,7 @@ def test_bulk_create_by_regular_user(api_client): assert created_names == {"Python", "SQL"} @pytest.mark.django_db -def test_merge_requires_perm_and_reassigns(api_client): +def test_merge_requires_perm_and_reassigns(api_client, ensure_ldap_disabled): user = _mk_user() api_client.force_authenticate(user=user)