klg-asutk-app/backend/tests/test_personnel_plg.py

196 lines
8.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Tests for Personnel PLG — сертификация персонала ПЛГ.
Проверяет: программы подготовки, CRUD специалистов, аттестацию, ПК, compliance.
"""
import pytest
from tests.conftest import *
class TestTrainingPrograms:
"""11 программ подготовки с правовыми основаниями."""
def test_list_programs(self, client, auth_headers):
resp = client.get("/api/v1/personnel-plg/programs", headers=auth_headers)
assert resp.status_code == 200
data = resp.json()
assert data["total"] == 11
def test_programs_have_legal_basis(self, client, auth_headers):
resp = client.get("/api/v1/personnel-plg/programs", headers=auth_headers)
data = resp.json()
for prog in data["programs"]:
assert "legal_basis" in prog, f"Program {prog['id']} missing legal_basis"
assert len(prog["legal_basis"]) > 10
def test_initial_program_structure(self, client, auth_headers):
resp = client.get("/api/v1/personnel-plg/programs/PLG-INIT-001", headers=auth_headers)
assert resp.status_code == 200
prog = resp.json()
assert prog["type"] == "initial"
assert prog["duration_hours"] == 240
assert len(prog["modules"]) >= 12
# Verify key modules exist
codes = [m["code"] for m in prog["modules"]]
assert "M7" in codes # Practical maintenance
assert "M9" in codes # Human factors
assert "M10" in codes # Aviation law
assert "P1" in codes # OJT
def test_recurrent_program_periodicity(self, client, auth_headers):
resp = client.get("/api/v1/personnel-plg/programs/PLG-REC-001", headers=auth_headers)
prog = resp.json()
assert "24 месяца" in prog.get("periodicity", "")
assert prog["duration_hours"] == 40
def test_type_rating_program(self, client, auth_headers):
resp = client.get("/api/v1/personnel-plg/programs/PLG-TYPE-001", headers=auth_headers)
prog = resp.json()
assert prog["type"] == "type_rating"
assert prog["duration_hours"] == 80
def test_special_courses_exist(self, client, auth_headers):
special = ["PLG-EWIS-001", "PLG-FUEL-001", "PLG-NDT-001",
"PLG-HF-001", "PLG-SMS-001", "PLG-CRS-001"]
for pid in special:
resp = client.get(f"/api/v1/personnel-plg/programs/{pid}", headers=auth_headers)
assert resp.status_code == 200, f"Program {pid} not found"
def test_program_not_found(self, client, auth_headers):
resp = client.get("/api/v1/personnel-plg/programs/NONEXISTENT", headers=auth_headers)
assert resp.status_code == 404
def test_programs_cover_all_regulatory_frameworks(self, client, auth_headers):
"""All 3 frameworks (RF, ICAO, EASA) must be covered."""
resp = client.get("/api/v1/personnel-plg/programs", headers=auth_headers)
all_basis = " ".join(p.get("legal_basis", "") for p in resp.json()["programs"])
assert "ФАП-147" in all_basis
assert "EASA" in all_basis or "Part-66" in all_basis
assert "ICAO" in all_basis
class TestSpecialists:
"""CRUD для специалистов ПЛГ."""
def test_create_specialist(self, client, auth_headers):
resp = client.post("/api/v1/personnel-plg/specialists", headers=auth_headers, json={
"full_name": "Иванов Иван Иванович",
"personnel_number": "ТН-001",
"position": "Авиатехник по АиРЭО",
"category": "B1",
"specializations": ["SSJ-100", "Ан-148"],
"license_number": "АС-12345",
})
assert resp.status_code == 200
data = resp.json()
assert data["full_name"] == "Иванов Иван Иванович"
assert data["category"] == "B1"
assert "SSJ-100" in data["specializations"]
return data["id"]
def test_list_specialists(self, client, auth_headers):
resp = client.get("/api/v1/personnel-plg/specialists", headers=auth_headers)
assert resp.status_code == 200
assert "items" in resp.json()
def test_get_specialist_detail(self, client, auth_headers):
# Create first
create_resp = client.post("/api/v1/personnel-plg/specialists", headers=auth_headers, json={
"full_name": "Петров Пётр Петрович",
"personnel_number": "ТН-002",
"position": "Инженер по ПЛГ",
"category": "C",
})
sid = create_resp.json()["id"]
resp = client.get(f"/api/v1/personnel-plg/specialists/{sid}", headers=auth_headers)
assert resp.status_code == 200
data = resp.json()
assert data["full_name"] == "Петров Пётр Петрович"
assert "compliance" in data
assert "attestations" in data
assert "qualifications" in data
class TestAttestations:
"""Первичная аттестация и переаттестация."""
def test_record_attestation(self, client, auth_headers):
# Create specialist
spec = client.post("/api/v1/personnel-plg/specialists", headers=auth_headers, json={
"full_name": "Сидоров А.А.",
"personnel_number": "ТН-003",
"position": "Авиатехник",
"category": "B1",
}).json()
resp = client.post("/api/v1/personnel-plg/attestations", headers=auth_headers, json={
"specialist_id": spec["id"],
"attestation_type": "initial",
"program_id": "PLG-INIT-001",
"program_name": "Первичная подготовка специалиста по ПЛГ",
"training_center": "АУЦ ГА",
"date_start": "2026-01-10",
"date_end": "2026-02-10",
"hours_theory": 200,
"hours_practice": 40,
"exam_score": 87.5,
"result": "passed",
"certificate_number": "ПА-2026-001",
})
assert resp.status_code == 200
data = resp.json()
assert data["result"] == "passed"
assert data["exam_score"] == 87.5
def test_attestation_unknown_specialist(self, client, auth_headers):
resp = client.post("/api/v1/personnel-plg/attestations", headers=auth_headers, json={
"specialist_id": "nonexistent",
"attestation_type": "initial",
"program_id": "PLG-INIT-001",
"program_name": "Test",
"date_start": "2026-01-01",
"date_end": "2026-01-02",
"result": "passed",
})
assert resp.status_code == 404
class TestQualificationUpgrade:
"""Повышение квалификации."""
def test_record_qualification(self, client, auth_headers):
spec = client.post("/api/v1/personnel-plg/specialists", headers=auth_headers, json={
"full_name": "Козлов Б.В.",
"personnel_number": "ТН-004",
"position": "Инженер по ТО",
"category": "B2",
}).json()
resp = client.post("/api/v1/personnel-plg/qualifications", headers=auth_headers, json={
"specialist_id": spec["id"],
"program_id": "PLG-REC-001",
"program_name": "Периодическое ПК",
"program_type": "recurrent",
"training_center": "АУЦ ГА",
"date_start": "2026-02-01",
"date_end": "2026-02-05",
"hours_total": 40,
"result": "passed",
"next_due": "2028-02-05",
})
assert resp.status_code == 200
assert resp.json()["result"] == "passed"
class TestComplianceReport:
"""Отчёт о соответствии квалификаций."""
def test_compliance_report_structure(self, client, auth_headers):
resp = client.get("/api/v1/personnel-plg/compliance-report", headers=auth_headers)
assert resp.status_code == 200
data = resp.json()
assert "total_specialists" in data
assert "compliant" in data
assert "non_compliant" in data
assert "overdue" in data
assert "expiring_soon" in data