import pytest from fastapi.testclient import TestClient from app.schemas.base import PartnerType class TestPartnerCreation: """Test partner creation endpoints.""" def test_create_partner_with_admin_access(self, client: TestClient, admin_token: str): """Test partner creation with admin token.""" partner_data = { "tin_number": 987654321, "names": "New Test Partner", "type": PartnerType.CLIENT, "phone_number": "0987654321" } response = client.post("/api/v1/partners/", json=partner_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 201 data = response.json() assert data["tin_number"] == 987654321 assert data["names"] == "New Test Partner" assert data["type"] == PartnerType.CLIENT assert data["phone_number"] == "0987654321" assert "id" in data def test_create_partner_with_write_access(self, client: TestClient, write_token: str): """Test partner creation with write token.""" partner_data = { "tin_number": 555666777, "names": "Write Access Partner", "type": PartnerType.SUPPLIER, "phone_number": "0555666777" } response = client.post("/api/v1/partners/", json=partner_data, headers={"Authorization": f"Bearer {write_token}"}) assert response.status_code == 201 data = response.json() assert data["tin_number"] == 555666777 assert data["type"] == PartnerType.SUPPLIER def test_create_partner_without_phone(self, client: TestClient, admin_token: str): """Test partner creation without phone number.""" partner_data = { "tin_number": 111222333, "names": "Partner Without Phone", "type": PartnerType.CLIENT } response = client.post("/api/v1/partners/", json=partner_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 201 data = response.json() assert data["tin_number"] == 111222333 def test_create_partner_unauthorized(self, client: TestClient): """Test partner creation without authentication.""" partner_data = { "tin_number": 444555666, "names": "Unauthorized Partner", "type": PartnerType.CLIENT } response = client.post("/api/v1/partners/", json=partner_data) assert response.status_code == 403 def test_create_partner_read_only_forbidden(self, client: TestClient, read_only_token: str): """Test partner creation with read-only access should fail.""" partner_data = { "tin_number": 777888999, "names": "Read Only Attempt", "type": PartnerType.CLIENT } response = client.post("/api/v1/partners/", json=partner_data, headers={"Authorization": f"Bearer {read_only_token}"}) assert response.status_code == 403 def test_create_partner_duplicate_tin(self, client: TestClient, admin_token: str, sample_partner): """Test creation with duplicate TIN number should fail.""" partner_data = { "tin_number": sample_partner.tin_number, # Duplicate TIN "names": "Duplicate TIN Partner", "type": PartnerType.SUPPLIER } response = client.post("/api/v1/partners/", json=partner_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 400 assert "TIN number already exists" in response.json()["detail"] class TestPartnerRetrieval: """Test partner retrieval endpoints.""" def test_get_all_partners_with_auth(self, client: TestClient, admin_token: str, multiple_partners): """Test retrieving all partners with authentication.""" response = client.get("/api/v1/partners/", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 200 data = response.json() assert isinstance(data, list) assert len(data) >= 3 # At least the fixture partners def test_get_all_partners_read_only_access(self, client: TestClient, read_only_token: str, multiple_partners): """Test read-only user can retrieve partners.""" response = client.get("/api/v1/partners/", headers={"Authorization": f"Bearer {read_only_token}"}) assert response.status_code == 200 data = response.json() assert isinstance(data, list) def test_get_partners_unauthorized(self, client: TestClient): """Test retrieving partners without authentication.""" response = client.get("/api/v1/partners/") assert response.status_code == 403 def test_get_partners_with_pagination(self, client: TestClient, admin_token: str, multiple_partners): """Test partner retrieval with pagination.""" response = client.get("/api/v1/partners/?skip=0&limit=2", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 200 data = response.json() assert len(data) <= 2 def test_get_single_partner_by_id(self, client: TestClient, admin_token: str, sample_partner): """Test retrieving a single partner by ID.""" response = client.get(f"/api/v1/partners/{sample_partner.id}", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 200 data = response.json() assert data["id"] == sample_partner.id assert data["tin_number"] == sample_partner.tin_number assert data["names"] == sample_partner.names def test_get_nonexistent_partner(self, client: TestClient, admin_token: str): """Test retrieving a non-existent partner.""" response = client.get("/api/v1/partners/99999", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 404 assert "Partner not found" in response.json()["detail"] class TestPartnerUpdate: """Test partner update endpoints.""" def test_update_partner_with_write_access(self, client: TestClient, write_token: str, sample_partner): """Test updating partner with write access.""" update_data = { "names": "Updated Partner Name", "type": PartnerType.SUPPLIER } response = client.put(f"/api/v1/partners/{sample_partner.id}", json=update_data, headers={"Authorization": f"Bearer {write_token}"}) assert response.status_code == 200 data = response.json() assert data["names"] == "Updated Partner Name" assert data["type"] == PartnerType.SUPPLIER assert data["tin_number"] == sample_partner.tin_number # Unchanged def test_update_partner_tin_number(self, client: TestClient, admin_token: str, sample_partner): """Test updating partner TIN number.""" update_data = { "tin_number": 999888777 } response = client.put(f"/api/v1/partners/{sample_partner.id}", json=update_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 200 data = response.json() assert data["tin_number"] == 999888777 def test_update_partner_read_only_forbidden(self, client: TestClient, read_only_token: str, sample_partner): """Test updating partner with read-only access should fail.""" update_data = { "names": "Should Not Update" } response = client.put(f"/api/v1/partners/{sample_partner.id}", json=update_data, headers={"Authorization": f"Bearer {read_only_token}"}) assert response.status_code == 403 def test_update_partner_duplicate_tin(self, client: TestClient, admin_token: str, multiple_partners): """Test updating partner with duplicate TIN should fail.""" partner_to_update = multiple_partners[0] existing_tin = multiple_partners[1].tin_number update_data = { "tin_number": existing_tin } response = client.put(f"/api/v1/partners/{partner_to_update.id}", json=update_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 400 assert "TIN number already exists" in response.json()["detail"] def test_update_nonexistent_partner(self, client: TestClient, admin_token: str): """Test updating a non-existent partner.""" update_data = { "names": "Non-existent Partner" } response = client.put("/api/v1/partners/99999", json=update_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 404 assert "Partner not found" in response.json()["detail"] class TestPartnerDeletion: """Test partner deletion endpoints.""" def test_delete_partner_with_admin_access(self, client: TestClient, admin_token: str, sample_partner): """Test deleting partner with admin access.""" response = client.delete(f"/api/v1/partners/{sample_partner.id}", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 204 # Verify partner is deleted get_response = client.get(f"/api/v1/partners/{sample_partner.id}", headers={"Authorization": f"Bearer {admin_token}"}) assert get_response.status_code == 404 def test_delete_partner_write_access_forbidden(self, client: TestClient, write_token: str, sample_partner): """Test deleting partner with write access should fail.""" response = client.delete(f"/api/v1/partners/{sample_partner.id}", headers={"Authorization": f"Bearer {write_token}"}) assert response.status_code == 403 def test_delete_partner_read_only_forbidden(self, client: TestClient, read_only_token: str, sample_partner): """Test deleting partner with read-only access should fail.""" response = client.delete(f"/api/v1/partners/{sample_partner.id}", headers={"Authorization": f"Bearer {read_only_token}"}) assert response.status_code == 403 def test_delete_nonexistent_partner(self, client: TestClient, admin_token: str): """Test deleting a non-existent partner.""" response = client.delete("/api/v1/partners/99999", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 404 assert "Partner not found" in response.json()["detail"] def test_delete_partner_unauthorized(self, client: TestClient, sample_partner): """Test deleting partner without authentication.""" response = client.delete(f"/api/v1/partners/{sample_partner.id}") assert response.status_code == 403 class TestPartnerValidation: """Test partner data validation.""" def test_create_partner_invalid_data(self, client: TestClient, admin_token: str): """Test creating partner with invalid data.""" # Missing required field partner_data = { "names": "Missing TIN Partner", "type": PartnerType.CLIENT } response = client.post("/api/v1/partners/", json=partner_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 422 # Validation error def test_create_partner_invalid_type(self, client: TestClient, admin_token: str): """Test creating partner with invalid type.""" partner_data = { "tin_number": 123456789, "names": "Invalid Type Partner", "type": "INVALID_TYPE" } response = client.post("/api/v1/partners/", json=partner_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 422 # Validation error