import pytest
from unittest.mock import AsyncMock, patch
from fastapi.testclient import TestClient
from preloop.models.models.tracker import Tracker
@pytest.fixture(autouse=True)
def mock_event_bus_connect():
"""Auto-mock the event bus connect method to avoid NATS connection attempts."""
with patch(
"preloop.sync.services.event_bus.EventBus.connect", new_callable=AsyncMock
) as mock_connect:
yield mock_connect
def test_list_trackers_empty(client: TestClient, db_session):
"""Test listing trackers when none exist."""
response = client.get("/api/v1/trackers")
assert response.status_code == 200
assert response.json() == []
def test_list_trackers_with_data(client: TestClient, db_session, test_user):
"""Test listing trackers with existing data."""
tracker = Tracker(
name="Test Tracker",
tracker_type="jira",
url="https://test.jira.com",
account_id=test_user.account_id,
api_key="dummy_key",
)
db_session.add(tracker)
db_session.commit()
response = client.get("/api/v1/trackers")
assert response.status_code == 200
response_json = response.json()
assert len(response_json) == 1
assert response_json[0]["name"] == "Test Tracker"
def test_get_tracker_not_found(client: TestClient, db_session, test_user):
"""Test getting a tracker that does not exist."""
import uuid
response = client.get(f"/api/v1/trackers/{uuid.uuid4()}")
assert response.status_code == 404
def test_get_tracker_success(client: TestClient, db_session, test_user):
"""Test getting a tracker successfully."""
tracker = Tracker(
name="Test Tracker",
tracker_type="jira",
url="https://test.jira.com",
account_id=test_user.account_id,
api_key="dummy_key",
)
db_session.add(tracker)
db_session.commit()
response = client.get(f"/api/v1/trackers/{tracker.id}")
assert response.status_code == 200
assert response.json()["name"] == "Test Tracker"
def test_delete_tracker(client: TestClient, db_session, test_user):
"""Test deleting a tracker."""
tracker = Tracker(
name="Test Tracker",
tracker_type="jira",
url="https://test.jira.com",
account_id=test_user.account_id,
api_key="dummy_key",
)
db_session.add(tracker)
db_session.commit()
response = client.delete(f"/api/v1/trackers/{tracker.id}")
assert response.status_code == 200
assert response.json()["message"] == "Tracker soft deleted successfully"
# Verify the tracker is marked as deleted
db_session.refresh(tracker)
deleted_tracker = db_session.query(Tracker).filter(Tracker.id == tracker.id).first()
assert deleted_tracker.is_deleted is True
@pytest.mark.asyncio
@patch("preloop.api.endpoints.trackers.create_tracker_client")
async def test_test_connection_and_list_orgs_uses_correct_args(
mock_create_tracker_client, client: TestClient, db_session, test_user
):
"""Test that test_connection_and_list_orgs calls create_tracker_client with the correct arguments."""
mock_tracker_client = AsyncMock()
mock_tracker_client.test_connection.return_value.connected = True
mock_tracker_client.get_organizations.return_value = []
mock_create_tracker_client.return_value = mock_tracker_client
test_data = {
"tracker_type": "gitlab",
"url": "https://gitlab.com",
"api_key": "test-key",
"connection_details": {"project_id": "123"},
}
response = client.post("/api/v1/trackers/test-and-list-orgs", json=test_data)
assert response.status_code == 200
mock_create_tracker_client.assert_called_once_with(
tracker_type="gitlab",
tracker_id="test-connection",
api_key="test-key",
connection_details={"url": "https://gitlab.com", "project_id": "123"},
)
@pytest.mark.asyncio
@patch("preloop.api.endpoints.trackers.create_tracker_client")
async def test_list_projects_for_org_uses_correct_args(
mock_create_tracker_client, client: TestClient, db_session, test_user
):
"""Test that list_projects_for_org calls create_tracker_client with the correct arguments."""
mock_tracker_client = AsyncMock()
mock_tracker_client.get_projects.return_value = []
mock_create_tracker_client.return_value = mock_tracker_client
test_data = {
"tracker_type": "gitlab",
"url": "https://gitlab.com",
"api_key": "test-key",
"connection_details": {"project_id": "123"},
"organization_identifier": "test-org",
}
response = client.post("/api/v1/trackers/list-projects-for-org", json=test_data)
assert response.status_code == 200
mock_create_tracker_client.assert_called_once_with(
tracker_type="gitlab",
tracker_id="list-projects",
api_key="test-key",
connection_details={
"url": "https://gitlab.com/",
"project_id": "123",
},
)
@pytest.mark.asyncio
@patch("preloop.api.endpoints.trackers.create_tracker_client")
@patch("preloop.api.endpoints.trackers.event_bus_service.publish_task")
@patch("preloop.api.endpoints.trackers.send_tracker_registered_email")
async def test_register_tracker_success(
mock_send_email,
mock_publish_task,
mock_create_tracker_client,
client: TestClient,
db_session,
test_user,
):
"""Test successful tracker registration."""
mock_tracker_client = AsyncMock()
mock_tracker_client.test_connection.return_value.connected = True
mock_create_tracker_client.return_value = mock_tracker_client
tracker_data = {
"name": "New Test Tracker",
"type": "jira",
"url": "https://test.jira.com",
"api_key": "new_dummy_key",
"config": {"username": "testuser"},
}
response = client.post("/api/v1/trackers", json=tracker_data)
assert response.status_code == 201
response_json = response.json()
assert "id" in response_json
mock_publish_task.assert_called_once()
mock_send_email.assert_called_once()
@pytest.mark.asyncio
@patch("preloop.api.endpoints.trackers.event_bus_service.publish_task")
async def test_update_tracker_success(
mock_publish_task, client: TestClient, db_session, test_user
):
"""Test successful tracker update."""
tracker = Tracker(
name="Tracker to Update",
tracker_type="jira",
url="https://update.jira.com",
account_id=test_user.account_id,
api_key="update_key",
)
db_session.add(tracker)
db_session.commit()
update_data = {"name": "Updated Tracker Name"}
response = client.put(f"/api/v1/trackers/{tracker.id}", json=update_data)
assert response.status_code == 200
response_json = response.json()
assert response_json["name"] == "Updated Tracker Name"
# UUID is converted to string for JSON serialization
mock_publish_task.assert_called_once_with("poll_tracker", str(tracker.id))