Newer
Older
vmk-360-data_collector / tests / integration / test_api_ingest.py
@Eugene Sukhodolskiy Eugene Sukhodolskiy 1 day ago 4 KB fix: code review critical and high issues
"""Integration tests for the ingest endpoint."""

from typing import Any
from unittest.mock import AsyncMock, MagicMock

import pytest
from httpx import AsyncClient

from vmk_data_collector.api.v1 import router_properties


class TestIngest:
    @pytest.mark.asyncio
    async def test_ingest_returns_202_and_pending(
        self,
        async_client: AsyncClient,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        monkeypatch.setattr(
            router_properties.RawDataRepository,
            "create",
            AsyncMock(return_value=MagicMock(id=42)),
        )

        response = await async_client.post(
            "/api/v1/ingest",
            json={
                "source_slug": "test",
                "external_id": "ext-1",
                "payload": {
                    "title": "2-комнатная квартира",
                    "price": 100000,
                },
            },
        )

        assert response.status_code == 202
        data = response.json()
        assert data["status"] == "pending"
        assert data["job_id"] == 42
        assert "Queued" in data["message"]

    @pytest.mark.asyncio
    async def test_ingest_invalid_payload_returns_422(
        self,
        async_client: AsyncClient,
    ) -> None:
        response = await async_client.post(
            "/api/v1/ingest",
            json={
                "source_slug": "test",
                "external_id": "ext-1",
                "payload": {},  # missing title and description
            },
        )
        assert response.status_code == 422


class TestArchiveCheck:
    @pytest.mark.asyncio
    async def test_not_found_returns_404(
        self,
        async_client: AsyncClient,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        monkeypatch.setattr(
            router_properties.PropertyRepository,
            "get_by_id",
            AsyncMock(return_value=None),
        )

        response = await async_client.post("/api/v1/listings/99/archive-check")
        assert response.status_code == 404

    @pytest.mark.asyncio
    async def test_no_url_returns_422(
        self,
        async_client: AsyncClient,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        listing = MagicMock()
        listing.url_source = None
        monkeypatch.setattr(
            router_properties.PropertyRepository,
            "get_by_id",
            AsyncMock(return_value=listing),
        )

        response = await async_client.post("/api/v1/listings/1/archive-check")
        assert response.status_code == 422

    @pytest.mark.asyncio
    async def test_archived_on_404(
        self,
        async_client: AsyncClient,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        listing = MagicMock()
        listing.url_source = "http://example.com/ad/1"
        monkeypatch.setattr(
            router_properties.PropertyRepository,
            "get_by_id",
            AsyncMock(return_value=listing),
        )
        monkeypatch.setattr(
            router_properties.PropertyRepository,
            "mark_archived",
            AsyncMock(return_value=listing),
        )

        # Patch httpx.AsyncClient.head
        async def fake_head(*_a, **_k) -> Any:
            resp = MagicMock()
            resp.status_code = 404
            return resp

        monkeypatch.setattr(
            "httpx.AsyncClient.head",
            fake_head,
        )

        response = await async_client.post("/api/v1/listings/1/archive-check")
        assert response.status_code == 200
        data = response.json()
        assert data["was_archived"] is True
        assert data["reason"] == "status_404"

    @pytest.mark.asyncio
    async def test_not_archived_on_200(
        self,
        async_client: AsyncClient,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        listing = MagicMock()
        listing.url_source = "http://example.com/ad/1"
        monkeypatch.setattr(
            router_properties.PropertyRepository,
            "get_by_id",
            AsyncMock(return_value=listing),
        )

        async def fake_head(*_a, **_k) -> Any:
            resp = MagicMock()
            resp.status_code = 200
            return resp

        monkeypatch.setattr("httpx.AsyncClient.head", fake_head)

        response = await async_client.post("/api/v1/listings/1/archive-check")
        assert response.status_code == 200
        data = response.json()
        assert data["was_archived"] is False
        assert data["reason"] == "status_200"


class TestCleanupRaw:
    @pytest.mark.asyncio
    async def test_cleanup_returns_deleted_count(
        self,
        async_client: AsyncClient,
        monkeypatch: pytest.MonkeyPatch,
    ) -> None:
        monkeypatch.setattr(
            router_properties.RawDataRepository,
            "delete_old_completed",
            AsyncMock(return_value=5),
        )

        response = await async_client.post("/api/v1/admin/cleanup-raw?days=30")
        assert response.status_code == 200
        data = response.json()
        assert data["deleted_count"] == 5