diff --git a/pyproject.toml b/pyproject.toml index 809dd45..b960d20 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ Tracker = "https://github.com/ibutsu/ibutsu-client-python/issues" test = [ "pytest", "pytest-cov", + "pytest-mock", "coverage[toml]", ] dev = [ diff --git a/test/__init__.py b/test/__init__.py index e69de29..dd9545f 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -0,0 +1 @@ +"""Test utilities for ibutsu_client tests.""" diff --git a/test/conftest.py b/test/conftest.py index 439732b..627bf93 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -9,25 +9,15 @@ from ibutsu_client.rest import RESTResponse -@pytest.fixture -def mock_api_client(mocker): - """Create a mock ApiClient for testing API methods.""" - from ibutsu_client.api_client import ApiClient - - client = ApiClient() - mocker.patch.object(client, "call_api") - return client - - -def create_mock_response( - data: dict[str, Any] | list[Any] | None = None, +def _make_mock_response( + data: dict[str, Any] | list[Any] | bytes | None = None, status: int = 200, headers: dict[str, str] | None = None, ) -> RESTResponse: - """Create a mock REST response for testing. + """Internal helper to create a mock REST response. Args: - data: The response data (will be JSON-encoded) + data: The response data (will be JSON-encoded unless bytes) status: HTTP status code headers: Response headers @@ -43,7 +33,11 @@ def create_mock_response( response = Mock(spec=RESTResponse) response.status = status response.headers = headers - response.data = json.dumps(data).encode("utf-8") + # Handle bytes data directly without JSON encoding + if isinstance(data, bytes): + response.data = data + else: + response.data = json.dumps(data).encode("utf-8") response.reason = "OK" if status < 400 else "Error" def mock_read(): @@ -65,6 +59,46 @@ def mock_getheaders() -> dict[str, str]: @pytest.fixture -def mock_rest_response(): - """Fixture that provides the create_mock_response function.""" - return create_mock_response +def mock_api_client(): + """Create a mock ApiClient for testing API methods.""" + from ibutsu_client.api_client import ApiClient + + client = ApiClient() + client.call_api = Mock() + return client + + +@pytest.fixture +def create_mock_response(request): + """Parametrized fixture for creating mock API responses. + + Use with indirect parametrization. Call factory functions directly in the parametrize decorator: + + Example: + from test.utils import sample_project_data + + @pytest.mark.parametrize('create_mock_response', [ + {'data': sample_project_data(name='test', title='Test'), 'status': 201}, + {'data': {'error': 'not found'}, 'status': 404}, + ], indirect=True) + def test_api_method(self, mocker, create_mock_response): + api = SomeApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + result = api.method() + ... + + Args: + request.param: Dict with keys: + - data: Response data dict/list/bytes + - status: HTTP status code (default: 200) + - headers: Response headers dict (optional) + + Returns: + Mock RESTResponse object ready to use + """ + params = request.param + data = params.get("data", {}) + status = params.get("status", 200) + headers = params.get("headers", None) + + return _make_mock_response(data=data, status=status, headers=headers) diff --git a/test/test_admin_project_management_api.py b/test/test_admin_project_management_api.py index b159f9e..8acf403 100644 --- a/test/test_admin_project_management_api.py +++ b/test/test_admin_project_management_api.py @@ -3,6 +3,8 @@ from urllib.parse import parse_qs, urlparse from uuid import uuid4 +import pytest + from ibutsu_client.api.admin_project_management_api import AdminProjectManagementApi from ibutsu_client.models.project import Project from ibutsu_client.models.project_list import ProjectList @@ -11,19 +13,30 @@ class TestAdminProjectManagementApi: """AdminProjectManagementApi Tests""" - def test_admin_add_project(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "PROJECT_ID_PLACEHOLDER", + "name": "New Project", + "title": "New Project Title", + }, + "status": 201, + } + ], + indirect=True, + ) + def test_admin_add_project(self, mock_api_client, create_mock_response): """Test case for admin_add_project""" api = AdminProjectManagementApi(api_client=mock_api_client) project_id = uuid4() - project_data = { - "id": str(project_id), - "name": "New Project", - "title": "New Project Title", - } - # Mock the API response - mock_response = mock_rest_response(data=project_data, status=201) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual project_id + create_mock_response.data = create_mock_response.data.replace( + b"PROJECT_ID_PLACEHOLDER", str(project_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Call the API new_project = Project(name="New Project", title="New Project Title") @@ -40,14 +53,18 @@ def test_admin_add_project(self, mock_api_client, mock_rest_response): assert args[0] == "POST" assert args[1].endswith("/admin/project") - def test_admin_delete_project(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {}, "status": 200}], + indirect=True, + ) + def test_admin_delete_project(self, mock_api_client, create_mock_response): """Test case for admin_delete_project""" api = AdminProjectManagementApi(api_client=mock_api_client) project_id = uuid4() # Mock the API response - mock_response = mock_rest_response(status=200) - mock_api_client.call_api.return_value = mock_response + mock_api_client.call_api.return_value = create_mock_response # Call the API api.admin_delete_project(id=project_id) @@ -58,18 +75,29 @@ def test_admin_delete_project(self, mock_api_client, mock_rest_response): assert args[0] == "DELETE" assert args[1].endswith(f"/admin/project/{project_id}") - def test_admin_get_project(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "PROJECT_ID_PLACEHOLDER", + "name": "My Project", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_admin_get_project(self, mock_api_client, create_mock_response): """Test case for admin_get_project""" api = AdminProjectManagementApi(api_client=mock_api_client) project_id = uuid4() - project_data = { - "id": str(project_id), - "name": "My Project", - } - # Mock the API response - mock_response = mock_rest_response(data=project_data, status=200) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual project_id + create_mock_response.data = create_mock_response.data.replace( + b"PROJECT_ID_PLACEHOLDER", str(project_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.admin_get_project(id=project_id) @@ -85,21 +113,28 @@ def test_admin_get_project(self, mock_api_client, mock_rest_response): assert args[0] == "GET" assert args[1].endswith(f"/admin/project/{project_id}") - def test_admin_get_project_list(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "projects": [ + {"id": "00000000-0000-0000-0000-000000000001", "name": "Project 1"}, + {"id": "00000000-0000-0000-0000-000000000002", "name": "Project 2"}, + ], + "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, + }, + "status": 200, + } + ], + indirect=True, + ) + def test_admin_get_project_list(self, mock_api_client, create_mock_response): """Test case for admin_get_project_list""" api = AdminProjectManagementApi(api_client=mock_api_client) - project_list_data = { - "projects": [ - {"id": str(uuid4()), "name": "Project 1"}, - {"id": str(uuid4()), "name": "Project 2"}, - ], - "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, - } - # Mock the API response - mock_response = mock_rest_response(data=project_list_data, status=200) - mock_api_client.call_api.return_value = mock_response + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.admin_get_project_list(page=1, page_size=25) @@ -121,18 +156,29 @@ def test_admin_get_project_list(self, mock_api_client, mock_rest_response): assert query_params["page"] == ["1"] assert query_params["pageSize"] == ["25"] - def test_admin_update_project(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "PROJECT_ID_PLACEHOLDER", + "name": "Updated Project", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_admin_update_project(self, mock_api_client, create_mock_response): """Test case for admin_update_project""" api = AdminProjectManagementApi(api_client=mock_api_client) project_id = uuid4() - project_data = { - "id": str(project_id), - "name": "Updated Project", - } - # Mock the API response - mock_response = mock_rest_response(data=project_data, status=200) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual project_id + create_mock_response.data = create_mock_response.data.replace( + b"PROJECT_ID_PLACEHOLDER", str(project_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Call the API update_project = Project(name="Updated Project") diff --git a/test/test_admin_user_management_api.py b/test/test_admin_user_management_api.py index 6424685..2d8db01 100644 --- a/test/test_admin_user_management_api.py +++ b/test/test_admin_user_management_api.py @@ -9,50 +9,350 @@ Do not edit the class manually. """ -import unittest +import pytest from ibutsu_client.api.admin_user_management_api import AdminUserManagementApi +from ibutsu_client.exceptions import NotFoundException, ServiceException +from ibutsu_client.models.user import User +from ibutsu_client.models.user_list import UserList +from test.utils import sample_pagination_data, sample_user_data -class TestAdminUserManagementApi(unittest.TestCase): - """AdminUserManagementApi unit test stubs""" +class TestAdminUserManagementApi: + """AdminUserManagementApi comprehensive tests""" - def setUp(self) -> None: - self.api = AdminUserManagementApi() + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_user_data(email="newuser@example.com", name="New User"), "status": 201}], + indirect=True, + ) + def test_admin_add_user_success(self, mocker, create_mock_response): + """Test case for admin_add_user - successfully add a user""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def tearDown(self) -> None: - pass + user = User(email="newuser@example.com", name="New User") + result = api.admin_add_user(user=user) - def test_admin_add_user(self) -> None: - """Test case for admin_add_user + assert isinstance(result, User) + assert result.email == "newuser@example.com" + assert result.name == "New User" + api.api_client.call_api.assert_called_once() - Administration endpoint to manually add a user. Only accessible to superadmins. - """ + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "unauthorized"}, "status": 403}], + indirect=True, + ) + def test_admin_add_user_unauthorized(self, mocker, create_mock_response): + """Test case for admin_add_user without superadmin privileges""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def test_admin_delete_user(self) -> None: - """Test case for admin_delete_user + user = User(email="test@example.com", name="Test") + with pytest.raises((ServiceException, Exception)): + api.admin_add_user(user=user) - Administration endpoint to delete a user. Only accessible to superadmins. - """ + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "user already exists"}, "status": 409}], + indirect=True, + ) + def test_admin_add_user_conflict(self, mocker, create_mock_response): + """Test case for admin_add_user with existing email""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def test_admin_get_user(self) -> None: - """Test case for admin_get_user + user = User(email="existing@example.com", name="Existing User") + with pytest.raises((ServiceException, Exception)): + api.admin_add_user(user=user) - Administration endpoint to return a user. Only accessible to superadmins. - """ + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_user_data(), "status": 201}], + indirect=True, + ) + def test_admin_add_user_with_http_info(self, mocker, create_mock_response): + """Test case for admin_add_user_with_http_info""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def test_admin_get_user_list(self) -> None: - """Test case for admin_get_user_list + user = User(email="test@example.com", name="Test User") + result = api.admin_add_user_with_http_info(user=user) - Administration endpoint to return a list of users. Only accessible to superadmins. - """ + assert result.status_code == 201 + assert isinstance(result.data, User) - def test_admin_update_user(self) -> None: - """Test case for admin_update_user + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {}, "status": 204}], + indirect=True, + ) + def test_admin_delete_user_success(self, mocker, create_mock_response): + """Test case for admin_delete_user - successfully delete a user""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - Administration endpoint to update a user. Only accessible to superadmins. - """ + user_id = "550e8400-e29b-41d4-a716-446655440000" + api.admin_delete_user(id=user_id) + # 204 No Content typically returns None + api.api_client.call_api.assert_called_once() -if __name__ == "__main__": - unittest.main() + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "not found"}, "status": 404}], + indirect=True, + ) + def test_admin_delete_user_not_found(self, mocker, create_mock_response): + """Test case for admin_delete_user with non-existent user""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + user_id = "550e8400-e29b-41d4-a716-446655440000" + with pytest.raises(NotFoundException): + api.admin_delete_user(id=user_id) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "forbidden"}, "status": 403}], + indirect=True, + ) + def test_admin_delete_user_forbidden(self, mocker, create_mock_response): + """Test case for admin_delete_user without superadmin privileges""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + user_id = "550e8400-e29b-41d4-a716-446655440000" + with pytest.raises((ServiceException, Exception)): + api.admin_delete_user(id=user_id) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {}, "status": 204}], + indirect=True, + ) + def test_admin_delete_user_with_http_info(self, mocker, create_mock_response): + """Test case for admin_delete_user_with_http_info""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + user_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.admin_delete_user_with_http_info(id=user_id) + + assert result.status_code == 204 + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": sample_user_data(email="admin@example.com", is_superadmin=True), + "status": 200, + } + ], + indirect=True, + ) + def test_admin_get_user_success(self, mocker, create_mock_response): + """Test case for admin_get_user - retrieve a single user""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + user_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.admin_get_user(id=user_id) + + assert isinstance(result, User) + assert result.email == "admin@example.com" + assert result.is_superadmin is True + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "not found"}, "status": 404}], + indirect=True, + ) + def test_admin_get_user_not_found(self, mocker, create_mock_response): + """Test case for admin_get_user with non-existent user""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + user_id = "550e8400-e29b-41d4-a716-446655440000" + with pytest.raises(NotFoundException): + api.admin_get_user(id=user_id) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_user_data(), "status": 200}], + indirect=True, + ) + def test_admin_get_user_with_http_info(self, mocker, create_mock_response): + """Test case for admin_get_user_with_http_info""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + user_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.admin_get_user_with_http_info(id=user_id) + + assert result.status_code == 200 + assert isinstance(result.data, User) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "users": [ + sample_user_data(email="user1@example.com", name="User One"), + sample_user_data(email="user2@example.com", name="User Two"), + ], + "pagination": sample_pagination_data(total_items=2), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_admin_get_user_list_success(self, mocker, create_mock_response): + """Test case for admin_get_user_list - retrieve list of users""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.admin_get_user_list() + + assert isinstance(result, UserList) + assert len(result.users) == 2 + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "users": [sample_user_data()], + "pagination": sample_pagination_data(page=2, page_size=10, total_items=15), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_admin_get_user_list_with_pagination(self, mocker, create_mock_response): + """Test case for admin_get_user_list with pagination parameters""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.admin_get_user_list(page=2, page_size=10) + + assert isinstance(result, UserList) + api.api_client.call_api.assert_called_once() + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "users": [sample_user_data(is_superadmin=True)], + "pagination": sample_pagination_data(total_items=1), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_admin_get_user_list_with_filters(self, mocker, create_mock_response): + """Test case for admin_get_user_list with filter parameters""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.admin_get_user_list(filter=["is_superadmin=true"]) + + assert isinstance(result, UserList) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "users": [], + "pagination": sample_pagination_data(), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_admin_get_user_list_with_http_info(self, mocker, create_mock_response): + """Test case for admin_get_user_list_with_http_info""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.admin_get_user_list_with_http_info() + + assert result.status_code == 200 + assert isinstance(result.data, UserList) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": sample_user_data(email="updated@example.com", is_superadmin=True), + "status": 200, + } + ], + indirect=True, + ) + def test_admin_update_user_success(self, mocker, create_mock_response): + """Test case for admin_update_user - successfully update a user""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + user_id = "550e8400-e29b-41d4-a716-446655440000" + user = User(email="updated@example.com", is_superadmin=True) + result = api.admin_update_user(id=user_id, user=user) + + assert isinstance(result, User) + assert result.is_superadmin is True + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "not found"}, "status": 404}], + indirect=True, + ) + def test_admin_update_user_not_found(self, mocker, create_mock_response): + """Test case for admin_update_user with non-existent user""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + user_id = "550e8400-e29b-41d4-a716-446655440000" + user = User(email="test@example.com", name="Test") + with pytest.raises(NotFoundException): + api.admin_update_user(id=user_id, user=user) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_user_data(), "status": 200}], + indirect=True, + ) + def test_admin_update_user_with_http_info(self, mocker, create_mock_response): + """Test case for admin_update_user_with_http_info""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + user_id = "550e8400-e29b-41d4-a716-446655440000" + user = User(email="test@example.com", name="Test") + result = api.admin_update_user_with_http_info(id=user_id, user=user) + + assert result.status_code == 200 + assert isinstance(result.data, User) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "internal error"}, "status": 500}], + indirect=True, + ) + def test_admin_update_user_server_error(self, mocker, create_mock_response): + """Test case for admin_update_user with server error""" + api = AdminUserManagementApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + user_id = "550e8400-e29b-41d4-a716-446655440000" + user = User(email="test@example.com", name="Test") + with pytest.raises(ServiceException): + api.admin_update_user(id=user_id, user=user) diff --git a/test/test_artifact_api.py b/test/test_artifact_api.py index b879858..2893d3a 100644 --- a/test/test_artifact_api.py +++ b/test/test_artifact_api.py @@ -2,6 +2,8 @@ from uuid import uuid4 +import pytest + from ibutsu_client.api.artifact_api import ArtifactApi from ibutsu_client.models.artifact import Artifact from ibutsu_client.models.artifact_list import ArtifactList @@ -10,21 +12,36 @@ class TestArtifactApi: """ArtifactApi Tests""" - def test_get_artifact_list(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "artifacts": [ + { + "id": "00000000-0000-0000-0000-000000000001", + "filename": "test1.txt", + "mime_type": "text/plain", + }, + { + "id": "00000000-0000-0000-0000-000000000002", + "filename": "test2.png", + "mime_type": "image/png", + }, + ], + "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_artifact_list(self, mock_api_client, create_mock_response): """Test case for get_artifact_list""" api = ArtifactApi(api_client=mock_api_client) - artifact_list_data = { - "artifacts": [ - {"id": str(uuid4()), "filename": "test1.txt", "mime_type": "text/plain"}, - {"id": str(uuid4()), "filename": "test2.png", "mime_type": "image/png"}, - ], - "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, - } - # Mock the API response - mock_response = mock_rest_response(data=artifact_list_data, status=200) - mock_api_client.call_api.return_value = mock_response + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.get_artifact_list(page=1, page_size=25) @@ -43,19 +60,30 @@ def test_get_artifact_list(self, mock_api_client, mock_rest_response): assert "page=1" in args[1] assert "pageSize=25" in args[1] - def test_get_artifact(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "ARTIFACT_ID_PLACEHOLDER", + "filename": "test.txt", + "mime_type": "text/plain", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_artifact(self, mock_api_client, create_mock_response): """Test case for get_artifact""" api = ArtifactApi(api_client=mock_api_client) artifact_id = uuid4() - artifact_data = { - "id": str(artifact_id), - "filename": "test.txt", - "mime_type": "text/plain", - } - # Mock the API response - mock_response = mock_rest_response(data=artifact_data, status=200) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual artifact_id + create_mock_response.data = create_mock_response.data.replace( + b"ARTIFACT_ID_PLACEHOLDER", str(artifact_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.get_artifact(id=artifact_id) @@ -71,17 +99,19 @@ def test_get_artifact(self, mock_api_client, mock_rest_response): assert args[0] == "GET" assert args[1].endswith(f"/artifact/{artifact_id}") - def test_download_artifact(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [{"data": b"file content", "status": 200}], + indirect=True, + ) + def test_download_artifact(self, mock_api_client, create_mock_response): """Test case for download_artifact""" api = ArtifactApi(api_client=mock_api_client) artifact_id = uuid4() file_content = b"file content" # Mock the API response - # Note: download_artifact returns bytearray, so we mock the raw data - mock_response = mock_rest_response(status=200) - mock_response.data = file_content - mock_api_client.call_api.return_value = mock_response + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.download_artifact(id=artifact_id) @@ -95,16 +125,19 @@ def test_download_artifact(self, mock_api_client, mock_rest_response): assert args[0] == "GET" assert args[1].endswith(f"/artifact/{artifact_id}/download") - def test_view_artifact(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [{"data": b"file content", "status": 200}], + indirect=True, + ) + def test_view_artifact(self, mock_api_client, create_mock_response): """Test case for view_artifact""" api = ArtifactApi(api_client=mock_api_client) artifact_id = uuid4() file_content = b"file content" # Mock the API response - mock_response = mock_rest_response(status=200) - mock_response.data = file_content - mock_api_client.call_api.return_value = mock_response + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.view_artifact(id=artifact_id) @@ -118,23 +151,37 @@ def test_view_artifact(self, mock_api_client, mock_rest_response): assert args[0] == "GET" assert args[1].endswith(f"/artifact/{artifact_id}/view") - def test_upload_artifact(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "ARTIFACT_ID_PLACEHOLDER", + "filename": "test.txt", + "result_id": None, + "run_id": "RUN_ID_PLACEHOLDER", + }, + "status": 201, + } + ], + indirect=True, + ) + def test_upload_artifact(self, mock_api_client, create_mock_response): """Test case for upload_artifact""" api = ArtifactApi(api_client=mock_api_client) run_id = uuid4() + artifact_id = uuid4() filename = "test.txt" file_content = b"content" - artifact_data = { - "id": str(uuid4()), - "filename": filename, - "result_id": None, - "run_id": str(run_id), - } - - # Mock the API response - mock_response = mock_rest_response(data=artifact_data, status=201) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual IDs + create_mock_response.data = create_mock_response.data.replace( + b"ARTIFACT_ID_PLACEHOLDER", str(artifact_id).encode() + ) + create_mock_response.data = create_mock_response.data.replace( + b"RUN_ID_PLACEHOLDER", str(run_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.upload_artifact(filename=filename, file=file_content, run_id=run_id) @@ -161,14 +208,18 @@ def test_upload_artifact(self, mock_api_client, mock_rest_response): ) assert file_found - def test_delete_artifact(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {}, "status": 200}], + indirect=True, + ) + def test_delete_artifact(self, mock_api_client, create_mock_response): """Test case for delete_artifact""" api = ArtifactApi(api_client=mock_api_client) artifact_id = uuid4() # Mock the API response - mock_response = mock_rest_response(status=200) - mock_api_client.call_api.return_value = mock_response + mock_api_client.call_api.return_value = create_mock_response # Call the API api.delete_artifact(id=artifact_id) diff --git a/test/test_dashboard_api.py b/test/test_dashboard_api.py index a6cb58d..c8702c3 100644 --- a/test/test_dashboard_api.py +++ b/test/test_dashboard_api.py @@ -3,6 +3,8 @@ from urllib.parse import parse_qs, urlparse from uuid import uuid4 +import pytest + from ibutsu_client.api.dashboard_api import DashboardApi from ibutsu_client.models.dashboard import Dashboard from ibutsu_client.models.dashboard_list import DashboardList @@ -11,19 +13,30 @@ class TestDashboardApi: """DashboardApi Tests""" - def test_add_dashboard(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "DASHBOARD_ID_PLACEHOLDER", + "title": "New Dashboard", + "description": "Description", + }, + "status": 201, + } + ], + indirect=True, + ) + def test_add_dashboard(self, mock_api_client, create_mock_response): """Test case for add_dashboard""" api = DashboardApi(api_client=mock_api_client) dashboard_id = uuid4() - dashboard_data = { - "id": str(dashboard_id), - "title": "New Dashboard", - "description": "Description", - } - # Mock the API response - mock_response = mock_rest_response(data=dashboard_data, status=201) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual dashboard_id + create_mock_response.data = create_mock_response.data.replace( + b"DASHBOARD_ID_PLACEHOLDER", str(dashboard_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Call the API new_dashboard = Dashboard(title="New Dashboard", description="Description") @@ -40,14 +53,18 @@ def test_add_dashboard(self, mock_api_client, mock_rest_response): assert args[0] == "POST" assert args[1].endswith("/dashboard") - def test_delete_dashboard(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {}, "status": 200}], + indirect=True, + ) + def test_delete_dashboard(self, mock_api_client, create_mock_response): """Test case for delete_dashboard""" api = DashboardApi(api_client=mock_api_client) dashboard_id = uuid4() # Mock the API response - mock_response = mock_rest_response(status=200) - mock_api_client.call_api.return_value = mock_response + mock_api_client.call_api.return_value = create_mock_response # Call the API api.delete_dashboard(id=dashboard_id) @@ -58,18 +75,29 @@ def test_delete_dashboard(self, mock_api_client, mock_rest_response): assert args[0] == "DELETE" assert args[1].endswith(f"/dashboard/{dashboard_id}") - def test_get_dashboard(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "DASHBOARD_ID_PLACEHOLDER", + "title": "My Dashboard", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_dashboard(self, mock_api_client, create_mock_response): """Test case for get_dashboard""" api = DashboardApi(api_client=mock_api_client) dashboard_id = uuid4() - dashboard_data = { - "id": str(dashboard_id), - "title": "My Dashboard", - } - # Mock the API response - mock_response = mock_rest_response(data=dashboard_data, status=200) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual dashboard_id + create_mock_response.data = create_mock_response.data.replace( + b"DASHBOARD_ID_PLACEHOLDER", str(dashboard_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.get_dashboard(id=dashboard_id) @@ -85,21 +113,28 @@ def test_get_dashboard(self, mock_api_client, mock_rest_response): assert args[0] == "GET" assert args[1].endswith(f"/dashboard/{dashboard_id}") - def test_get_dashboard_list(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "dashboards": [ + {"id": "00000000-0000-0000-0000-000000000001", "title": "Dashboard 1"}, + {"id": "00000000-0000-0000-0000-000000000002", "title": "Dashboard 2"}, + ], + "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_dashboard_list(self, mock_api_client, create_mock_response): """Test case for get_dashboard_list""" api = DashboardApi(api_client=mock_api_client) - dashboard_list_data = { - "dashboards": [ - {"id": str(uuid4()), "title": "Dashboard 1"}, - {"id": str(uuid4()), "title": "Dashboard 2"}, - ], - "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, - } - # Mock the API response - mock_response = mock_rest_response(data=dashboard_list_data, status=200) - mock_api_client.call_api.return_value = mock_response + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.get_dashboard_list(page=1, page_size=25) @@ -121,18 +156,29 @@ def test_get_dashboard_list(self, mock_api_client, mock_rest_response): assert query_params["page"] == ["1"] assert query_params["pageSize"] == ["25"] - def test_update_dashboard(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "DASHBOARD_ID_PLACEHOLDER", + "title": "Updated Dashboard", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_update_dashboard(self, mock_api_client, create_mock_response): """Test case for update_dashboard""" api = DashboardApi(api_client=mock_api_client) dashboard_id = uuid4() - dashboard_data = { - "id": str(dashboard_id), - "title": "Updated Dashboard", - } - # Mock the API response - mock_response = mock_rest_response(data=dashboard_data, status=200) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual dashboard_id + create_mock_response.data = create_mock_response.data.replace( + b"DASHBOARD_ID_PLACEHOLDER", str(dashboard_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Call the API update_dashboard = Dashboard(title="Updated Dashboard") diff --git a/test/test_group_api.py b/test/test_group_api.py index 638f8a7..d286ac5 100644 --- a/test/test_group_api.py +++ b/test/test_group_api.py @@ -9,44 +9,280 @@ Do not edit the class manually. """ -import unittest +import pytest from ibutsu_client.api.group_api import GroupApi +from ibutsu_client.exceptions import NotFoundException, ServiceException +from ibutsu_client.models.group import Group +from ibutsu_client.models.group_list import GroupList +from test.utils import sample_group_data, sample_pagination_data -class TestGroupApi(unittest.TestCase): - """GroupApi unit test stubs""" +class TestGroupApi: + """GroupApi comprehensive tests""" - def setUp(self) -> None: - self.api = GroupApi() + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_group_data(name="engineering-team"), "status": 201}], + indirect=True, + ) + def test_add_group_success(self, mocker, create_mock_response): + """Test case for add_group - successfully create a new group""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def tearDown(self) -> None: - pass + group = Group(name="engineering-team") + result = api.add_group(group=group) - def test_add_group(self) -> None: - """Test case for add_group + assert isinstance(result, Group) + assert result.name == "engineering-team" + api.api_client.call_api.assert_called_once() - Create a new group - """ + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "unauthorized"}, "status": 401}], + indirect=True, + ) + def test_add_group_unauthorized(self, mocker, create_mock_response): + """Test case for add_group without proper authentication""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def test_get_group(self) -> None: - """Test case for get_group + group = Group(name="test-group") + with pytest.raises((ServiceException, Exception)): + api.add_group(group=group) - Get a group - """ + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "group already exists"}, "status": 409}], + indirect=True, + ) + def test_add_group_conflict(self, mocker, create_mock_response): + """Test case for add_group with existing group name""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def test_get_group_list(self) -> None: - """Test case for get_group_list + group = Group(name="existing-group") + with pytest.raises((ServiceException, Exception)): + api.add_group(group=group) - Get a list of groups - """ + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_group_data(name="new-team"), "status": 201}], + indirect=True, + ) + def test_add_group_with_http_info(self, mocker, create_mock_response): + """Test case for add_group_with_http_info""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def test_update_group(self) -> None: - """Test case for update_group + group = Group(name="new-team") + result = api.add_group_with_http_info(group=group) - Update a group - """ + assert result.status_code == 201 + assert isinstance(result.data, Group) + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_group_data(name="qa-team"), "status": 200}], + indirect=True, + ) + def test_get_group_success(self, mocker, create_mock_response): + """Test case for get_group - retrieve a single group""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) -if __name__ == "__main__": - unittest.main() + group_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_group(id=group_id) + + assert isinstance(result, Group) + assert result.name == "qa-team" + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "not found"}, "status": 404}], + indirect=True, + ) + def test_get_group_not_found(self, mocker, create_mock_response): + """Test case for get_group with non-existent group""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + group_id = "550e8400-e29b-41d4-a716-446655440000" + with pytest.raises(NotFoundException): + api.get_group(id=group_id) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_group_data(), "status": 200}], + indirect=True, + ) + def test_get_group_with_http_info(self, mocker, create_mock_response): + """Test case for get_group_with_http_info""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + group_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_group_with_http_info(id=group_id) + + assert result.status_code == 200 + assert isinstance(result.data, Group) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "groups": [ + sample_group_data(name="team-alpha"), + sample_group_data(name="team-beta"), + ], + "pagination": sample_pagination_data(total_items=2), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_group_list_success(self, mocker, create_mock_response): + """Test case for get_group_list - retrieve list of groups""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_group_list() + + assert isinstance(result, GroupList) + assert len(result.groups) == 2 + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "groups": [sample_group_data()], + "pagination": sample_pagination_data(page=2, page_size=10), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_group_list_with_pagination(self, mocker, create_mock_response): + """Test case for get_group_list with pagination parameters""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_group_list(page=2, page_size=10) + + assert isinstance(result, GroupList) + api.api_client.call_api.assert_called_once() + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "groups": [], + "pagination": sample_pagination_data(total_items=0), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_group_list_empty(self, mocker, create_mock_response): + """Test case for get_group_list with no groups""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_group_list() + + assert isinstance(result, GroupList) + assert len(result.groups) == 0 + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "groups": [], + "pagination": sample_pagination_data(), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_group_list_with_http_info(self, mocker, create_mock_response): + """Test case for get_group_list_with_http_info""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_group_list_with_http_info() + + assert result.status_code == 200 + assert isinstance(result.data, GroupList) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_group_data(name="updated-team-name"), "status": 200}], + indirect=True, + ) + def test_update_group_success(self, mocker, create_mock_response): + """Test case for update_group - successfully update a group""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + group_id = "550e8400-e29b-41d4-a716-446655440000" + group = Group(name="updated-team-name") + result = api.update_group(id=group_id, group=group) + + assert isinstance(result, Group) + assert result.name == "updated-team-name" + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "not found"}, "status": 404}], + indirect=True, + ) + def test_update_group_not_found(self, mocker, create_mock_response): + """Test case for update_group with non-existent group""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + group_id = "550e8400-e29b-41d4-a716-446655440000" + group = Group(name="test-group") + with pytest.raises(NotFoundException): + api.update_group(id=group_id, group=group) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_group_data(), "status": 200}], + indirect=True, + ) + def test_update_group_with_http_info(self, mocker, create_mock_response): + """Test case for update_group_with_http_info""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + group_id = "550e8400-e29b-41d4-a716-446655440000" + group = Group(name="test-group") + result = api.update_group_with_http_info(id=group_id, group=group) + + assert result.status_code == 200 + assert isinstance(result.data, Group) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "internal error"}, "status": 500}], + indirect=True, + ) + def test_update_group_server_error(self, mocker, create_mock_response): + """Test case for update_group with server error""" + api = GroupApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + group_id = "550e8400-e29b-41d4-a716-446655440000" + group = Group(name="test-group") + with pytest.raises(ServiceException): + api.update_group(id=group_id, group=group) diff --git a/test/test_health_api.py b/test/test_health_api.py index f8a8a31..0094771 100644 --- a/test/test_health_api.py +++ b/test/test_health_api.py @@ -15,26 +15,26 @@ from ibutsu_client.exceptions import ServiceException from ibutsu_client.models.health import Health from ibutsu_client.models.health_info import HealthInfo -from test.conftest import create_mock_response class TestHealthApi: """HealthApi unit tests""" - def test_get_database_health(self, mocker): + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"status": "ok", "message": "Database is healthy"}, "status": 200}], + indirect=True, + ) + def test_get_database_health(self, mocker, create_mock_response): """Test case for get_database_health Get a health report for the database """ - # Mock response data - response_data = {"status": "ok", "message": "Database is healthy"} - # Create API instance api = HealthApi() # Mock the call_api method - mock_response = create_mock_response(response_data, status=200) - mocker.patch.object(api.api_client, "call_api", return_value=mock_response) + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) # Call the method result = api.get_database_health() @@ -47,13 +47,15 @@ def test_get_database_health(self, mocker): # Verify call_api was called api.api_client.call_api.assert_called_once() - def test_get_database_health_error(self, mocker): + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"status": "error", "message": "Database connection failed"}, "status": 500}], + indirect=True, + ) + def test_get_database_health_error(self, mocker, create_mock_response): """Test case for get_database_health with error response""" - response_data = {"status": "error", "message": "Database connection failed"} - api = HealthApi() - mock_response = create_mock_response(response_data, status=500) - mocker.patch.object(api.api_client, "call_api", return_value=mock_response) + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) # 500 errors raise ServiceException with pytest.raises(ServiceException) as exc_info: @@ -62,16 +64,18 @@ def test_get_database_health_error(self, mocker): assert exc_info.value.status == 500 assert "error" in str(exc_info.value.body).lower() - def test_get_health(self, mocker): + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"status": "ok", "message": "Service is healthy"}, "status": 200}], + indirect=True, + ) + def test_get_health(self, mocker, create_mock_response): """Test case for get_health Get a general health report """ - response_data = {"status": "ok", "message": "Service is healthy"} - api = HealthApi() - mock_response = create_mock_response(response_data, status=200) - mocker.patch.object(api.api_client, "call_api", return_value=mock_response) + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) result = api.get_health() @@ -79,20 +83,27 @@ def test_get_health(self, mocker): assert result.status == "ok" assert result.message == "Service is healthy" - def test_get_health_info(self, mocker): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "frontend": "https://ibutsu.example.com", + "backend": "https://api.ibutsu.example.com", + "api_ui": "https://api.ibutsu.example.com/docs", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_health_info(self, mocker, create_mock_response): """Test case for get_health_info Get information about the server """ - response_data = { - "frontend": "https://ibutsu.example.com", - "backend": "https://api.ibutsu.example.com", - "api_ui": "https://api.ibutsu.example.com/docs", - } - api = HealthApi() - mock_response = create_mock_response(response_data, status=200) - mocker.patch.object(api.api_client, "call_api", return_value=mock_response) + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) result = api.get_health_info() @@ -101,17 +112,24 @@ def test_get_health_info(self, mocker): assert result.backend == "https://api.ibutsu.example.com" assert result.api_ui == "https://api.ibutsu.example.com/docs" - def test_get_health_info_with_http_info(self, mocker): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "frontend": "https://ibutsu.example.com", + "backend": "https://api.ibutsu.example.com", + "api_ui": "https://api.ibutsu.example.com/docs", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_health_info_with_http_info(self, mocker, create_mock_response): """Test case for get_health_info_with_http_info""" - response_data = { - "frontend": "https://ibutsu.example.com", - "backend": "https://api.ibutsu.example.com", - "api_ui": "https://api.ibutsu.example.com/docs", - } - api = HealthApi() - mock_response = create_mock_response(response_data, status=200) - mocker.patch.object(api.api_client, "call_api", return_value=mock_response) + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) result = api.get_health_info_with_http_info() diff --git a/test/test_import_api.py b/test/test_import_api.py index 4bd70fd..a6f3edf 100644 --- a/test/test_import_api.py +++ b/test/test_import_api.py @@ -9,32 +9,283 @@ Do not edit the class manually. """ -import unittest +import pytest from ibutsu_client.api.import_api import ImportApi +from ibutsu_client.exceptions import NotFoundException, ServiceException +from ibutsu_client.models.model_import import ModelImport -class TestImportApi(unittest.TestCase): - """ImportApi unit test stubs""" +class TestImportApi: + """ImportApi comprehensive tests""" - def setUp(self) -> None: - self.api = ImportApi() + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "filename": "test_results.xml", + "format": "junit", + "status": "pending", + }, + "status": 201, + } + ], + indirect=True, + ) + def test_add_import_success(self, mocker, create_mock_response): + """Test case for add_import - successfully import a file""" + api = ImportApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def tearDown(self) -> None: - pass + # Mock file upload - import_file as tuple (filename, content) + result = api.add_import( + import_file=("test_results.xml", b"test content"), + ) - def test_add_import(self) -> None: - """Test case for add_import + assert isinstance(result, ModelImport) + assert result.filename == "test_results.xml" + assert result.format == "junit" + api.api_client.call_api.assert_called_once() - Import a file into Ibutsu. This can be either a JUnit XML file, or an Ibutsu archive - """ + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "filename": "results.xml", + "format": "junit", + "project": "test-project", + "status": "pending", + }, + "status": 201, + } + ], + indirect=True, + ) + def test_add_import_with_project(self, mocker, create_mock_response): + """Test case for add_import with project parameter""" + api = ImportApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def test_get_import(self) -> None: - """Test case for get_import + result = api.add_import( + import_file=("results.xml", b"test"), + project="test-project", + ) - Get the status of an import - """ + assert isinstance(result, ModelImport) + assert result.filename == "results.xml" + api.api_client.call_api.assert_called_once() + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "filename": "archive.tar.gz", + "format": "ibutsu", + "status": "pending", + }, + "status": 201, + } + ], + indirect=True, + ) + def test_add_import_archive_format(self, mocker, create_mock_response): + """Test case for add_import with Ibutsu archive format""" + api = ImportApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) -if __name__ == "__main__": - unittest.main() + result = api.add_import( + import_file=("archive.tar.gz", b"binary archive content"), + ) + + assert isinstance(result, ModelImport) + assert result.format == "ibutsu" + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "invalid file format"}, "status": 400}], + indirect=True, + ) + def test_add_import_invalid_file(self, mocker, create_mock_response): + """Test case for add_import with invalid file""" + api = ImportApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + with pytest.raises((ServiceException, Exception)): + api.add_import(import_file=("invalid.txt", b"invalid content")) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "unauthorized"}, "status": 401}], + indirect=True, + ) + def test_add_import_unauthorized(self, mocker, create_mock_response): + """Test case for add_import without authentication""" + api = ImportApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + with pytest.raises((ServiceException, Exception)): + api.add_import(import_file=("test.xml", b"content")) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "filename": "test.xml", + "status": "pending", + }, + "status": 201, + } + ], + indirect=True, + ) + def test_add_import_with_http_info(self, mocker, create_mock_response): + """Test case for add_import_with_http_info""" + api = ImportApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.add_import_with_http_info( + import_file=("test.xml", b"content"), + ) + + assert result.status_code == 201 + assert isinstance(result.data, ModelImport) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "filename": "test_results.xml", + "format": "junit", + "status": "done", + "run_id": "660e8400-e29b-41d4-a716-446655440000", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_import_success(self, mocker, create_mock_response): + """Test case for get_import - retrieve import status""" + api = ImportApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + import_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_import(id=import_id) + + assert isinstance(result, ModelImport) + assert result.status == "done" + assert result.run_id is not None + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "filename": "test.xml", + "status": "pending", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_import_pending_status(self, mocker, create_mock_response): + """Test case for get_import with pending status""" + api = ImportApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + import_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_import(id=import_id) + + assert isinstance(result, ModelImport) + assert result.status == "pending" + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "filename": "test.xml", + "status": "running", + "format": "junit", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_import_running_status(self, mocker, create_mock_response): + """Test case for get_import with running status""" + api = ImportApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + import_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_import(id=import_id) + + assert isinstance(result, ModelImport) + assert result.status == "running" + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "not found"}, "status": 404}], + indirect=True, + ) + def test_get_import_not_found(self, mocker, create_mock_response): + """Test case for get_import with non-existent import""" + api = ImportApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + import_id = "550e8400-e29b-41d4-a716-446655440000" + with pytest.raises(NotFoundException): + api.get_import(id=import_id) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "filename": "test.xml", + "status": "done", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_import_with_http_info(self, mocker, create_mock_response): + """Test case for get_import_with_http_info""" + api = ImportApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + import_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_import_with_http_info(id=import_id) + + assert result.status_code == 200 + assert isinstance(result.data, ModelImport) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "internal error"}, "status": 500}], + indirect=True, + ) + def test_get_import_server_error(self, mocker, create_mock_response): + """Test case for get_import with server error""" + api = ImportApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + import_id = "550e8400-e29b-41d4-a716-446655440000" + with pytest.raises(ServiceException): + api.get_import(id=import_id) diff --git a/test/test_login_api.py b/test/test_login_api.py index f68ef31..5a544e2 100644 --- a/test/test_login_api.py +++ b/test/test_login_api.py @@ -9,44 +9,398 @@ Do not edit the class manually. """ -import unittest +import pytest from ibutsu_client.api.login_api import LoginApi +from ibutsu_client.exceptions import NotFoundException, ServiceException +from ibutsu_client.models.login_config import LoginConfig +from ibutsu_client.models.login_support import LoginSupport +from ibutsu_client.models.login_token import LoginToken -class TestLoginApi(unittest.TestCase): - """LoginApi unit test stubs""" +class TestLoginApi: + """LoginApi comprehensive tests""" - def setUp(self) -> None: - self.api = LoginApi() + def test_activate_success(self, mocker): + """Test case for activate with successful activation""" + api = LoginApi() + from ibutsu_client.api_response import ApiResponse - def tearDown(self) -> None: - pass + # Mock response_deserialize to return ApiResponse with None data (302 redirect) + mock_api_response = ApiResponse(status_code=302, data=None, headers={}, raw_data=b"") + mocker.patch.object(api.api_client, "response_deserialize", return_value=mock_api_response) + mocker.patch.object(api.api_client, "call_api") - def test_activate(self) -> None: - """Test case for activate""" + # Should not raise exception for 302 redirect + result = api.activate(activation_code="test-activation-code") + assert result is None + api.api_client.call_api.assert_called_once() - def test_auth(self) -> None: - """Test case for auth""" + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "not found"}, "status": 404}], + indirect=True, + ) + def test_activate_not_found(self, mocker, create_mock_response): + """Test case for activate with invalid activation code""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def test_config(self) -> None: - """Test case for config""" + with pytest.raises(NotFoundException): + api.activate(activation_code="invalid-code") - def test_login(self) -> None: - """Test case for login""" + def test_activate_with_http_info(self, mocker): + """Test case for activate_with_http_info""" + api = LoginApi() + from ibutsu_client.api_response import ApiResponse - def test_recover(self) -> None: - """Test case for recover""" + # Mock response_deserialize to return ApiResponse with None data (302 redirect) + mock_api_response = ApiResponse(status_code=302, data=None, headers={}, raw_data=b"") + mocker.patch.object(api.api_client, "response_deserialize", return_value=mock_api_response) + mocker.patch.object(api.api_client, "call_api") - def test_register(self) -> None: - """Test case for register""" + result = api.activate_with_http_info(activation_code="test-code") + assert result.status_code == 302 + assert result.data is None - def test_reset_password(self) -> None: - """Test case for reset_password""" + def test_auth_success(self, mocker): + """Test case for auth - redirects to OAuth provider""" + api = LoginApi() + from ibutsu_client.api_response import ApiResponse - def test_support(self) -> None: - """Test case for support""" + # auth() returns None (302 redirect to OAuth provider) + mock_api_response = ApiResponse(status_code=302, data=None, headers={}, raw_data=b"") + mocker.patch.object(api.api_client, "response_deserialize", return_value=mock_api_response) + mocker.patch.object(api.api_client, "call_api") + result = api.auth(provider="oidc") + assert result is None + api.api_client.call_api.assert_called_once() -if __name__ == "__main__": - unittest.main() + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "invalid provider"}, "status": 400}], + indirect=True, + ) + def test_auth_unauthorized(self, mocker, create_mock_response): + """Test case for auth with invalid provider""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + with pytest.raises( + (ServiceException, Exception) + ): # Should raise appropriate auth exception + api.auth(provider="invalid") + + def test_auth_with_http_info(self, mocker): + """Test case for auth_with_http_info - redirects to OAuth provider""" + api = LoginApi() + from ibutsu_client.api_response import ApiResponse + + # auth() returns None (302 redirect to OAuth provider) + mock_api_response = ApiResponse(status_code=302, data=None, headers={}, raw_data=b"") + mocker.patch.object(api.api_client, "response_deserialize", return_value=mock_api_response) + mocker.patch.object(api.api_client, "call_api") + + result = api.auth_with_http_info(provider="oidc") + assert result.status_code == 302 + assert result.data is None + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "client_id": "test-client-id", + "redirect_uri": "https://example.com/callback", + "scope": "openid profile email", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_config_success(self, mocker, create_mock_response): + """Test case for config - get login configuration""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.config(provider="oidc") + assert isinstance(result, LoginConfig) + assert result.client_id == "test-client-id" + assert result.redirect_uri == "https://example.com/callback" + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"client_id": "test-client"}, "status": 200}], + indirect=True, + ) + def test_config_with_http_info(self, mocker, create_mock_response): + """Test case for config_with_http_info""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.config_with_http_info(provider="oidc") + assert result.status_code == 200 + assert isinstance(result.data, LoginConfig) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "token": "jwt-token-here", + "refresh_token": "refresh-token-here", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_login_success(self, mocker, create_mock_response): + """Test case for login with valid credentials""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + from ibutsu_client.models.credentials import Credentials + + credentials = Credentials(email="test@example.com", password="password123") + result = api.login(credentials=credentials) + assert isinstance(result, LoginToken) + assert result.token == "jwt-token-here" + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "invalid credentials"}, "status": 401}], + indirect=True, + ) + def test_login_invalid_credentials(self, mocker, create_mock_response): + """Test case for login with invalid credentials""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + from ibutsu_client.models.credentials import Credentials + + credentials = Credentials(email="wrong@example.com", password="wrongpass") + with pytest.raises((ServiceException, Exception)): + api.login(credentials=credentials) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"token": "test-token"}, "status": 200}], + indirect=True, + ) + def test_login_with_http_info(self, mocker, create_mock_response): + """Test case for login_with_http_info""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + from ibutsu_client.models.credentials import Credentials + + credentials = Credentials(email="test@example.com", password="pass") + result = api.login_with_http_info(credentials=credentials) + assert result.status_code == 200 + assert isinstance(result.data, LoginToken) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {}, "status": 200}], + indirect=True, + ) + def test_recover_success(self, mocker, create_mock_response): + """Test case for recover - initiate password recovery""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + from ibutsu_client.models.account_recovery import AccountRecovery + + recovery_data = AccountRecovery(email="test@example.com") + api.recover(account_recovery=recovery_data) + # Method should complete without raising exception + api.api_client.call_api.assert_called_once() + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "user not found"}, "status": 404}], + indirect=True, + ) + def test_recover_not_found(self, mocker, create_mock_response): + """Test case for recover with non-existent email""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + from ibutsu_client.models.account_recovery import AccountRecovery + + recovery_data = AccountRecovery(email="nonexistent@example.com") + with pytest.raises(NotFoundException): + api.recover(account_recovery=recovery_data) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {}, "status": 200}], + indirect=True, + ) + def test_recover_with_http_info(self, mocker, create_mock_response): + """Test case for recover_with_http_info""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + from ibutsu_client.models.account_recovery import AccountRecovery + + recovery_data = AccountRecovery(email="test@example.com") + result = api.recover_with_http_info(account_recovery=recovery_data) + assert result.status_code == 200 + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"message": "Registration successful"}, "status": 201}], + indirect=True, + ) + def test_register_success(self, mocker, create_mock_response): + """Test case for register with valid registration data""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + from ibutsu_client.models.account_registration import AccountRegistration + + registration = AccountRegistration( + email="newuser@example.com", password="securepass123", name="New User" + ) + api.register(account_registration=registration) + api.api_client.call_api.assert_called_once() + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "email already exists"}, "status": 409}], + indirect=True, + ) + def test_register_conflict(self, mocker, create_mock_response): + """Test case for register with existing email""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + from ibutsu_client.models.account_registration import AccountRegistration + + registration = AccountRegistration( + email="existing@example.com", password="pass123", name="User" + ) + with pytest.raises((ServiceException, Exception)): # Should raise conflict exception + api.register(account_registration=registration) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"message": "success"}, "status": 201}], + indirect=True, + ) + def test_register_with_http_info(self, mocker, create_mock_response): + """Test case for register_with_http_info""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + from ibutsu_client.models.account_registration import AccountRegistration + + registration = AccountRegistration(email="test@example.com", password="pass", name="Test") + result = api.register_with_http_info(account_registration=registration) + assert result.status_code == 201 + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {}, "status": 200}], + indirect=True, + ) + def test_reset_password_success(self, mocker, create_mock_response): + """Test case for reset_password with valid reset data""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + from ibutsu_client.models.account_reset import AccountReset + + reset_data = AccountReset(activation_code="reset-code-123", password="newpass123") + api.reset_password(account_reset=reset_data) + api.api_client.call_api.assert_called_once() + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "invalid reset code"}, "status": 400}], + indirect=True, + ) + def test_reset_password_invalid_code(self, mocker, create_mock_response): + """Test case for reset_password with invalid reset code""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + from ibutsu_client.models.account_reset import AccountReset + + reset_data = AccountReset(activation_code="invalid-code", password="newpass") + with pytest.raises((ServiceException, Exception)): + api.reset_password(account_reset=reset_data) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {}, "status": 200}], + indirect=True, + ) + def test_reset_password_with_http_info(self, mocker, create_mock_response): + """Test case for reset_password_with_http_info""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + from ibutsu_client.models.account_reset import AccountReset + + reset_data = AccountReset(activation_code="code", password="newpass") + result = api.reset_password_with_http_info(account_reset=reset_data) + assert result.status_code == 200 + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "user": True, + "keycloak": True, + "google": False, + "github": False, + "facebook": False, + "gitlab": False, + }, + "status": 200, + } + ], + indirect=True, + ) + def test_support_success(self, mocker, create_mock_response): + """Test case for support - get support configuration""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.support() + assert isinstance(result, LoginSupport) + assert result.user is True + assert result.keycloak is True + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"user": True, "google": True}, "status": 200}], + indirect=True, + ) + def test_support_with_http_info(self, mocker, create_mock_response): + """Test case for support_with_http_info""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.support_with_http_info() + assert result.status_code == 200 + assert isinstance(result.data, LoginSupport) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "internal error"}, "status": 500}], + indirect=True, + ) + def test_support_server_error(self, mocker, create_mock_response): + """Test case for support with server error""" + api = LoginApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + with pytest.raises(ServiceException): + api.support() diff --git a/test/test_project_api.py b/test/test_project_api.py index 971ec31..9d05c4f 100644 --- a/test/test_project_api.py +++ b/test/test_project_api.py @@ -3,6 +3,8 @@ from urllib.parse import parse_qs, urlparse from uuid import uuid4 +import pytest + from ibutsu_client.api.project_api import ProjectApi from ibutsu_client.models.project import Project from ibutsu_client.models.project_list import ProjectList @@ -11,19 +13,30 @@ class TestProjectApi: """ProjectApi Tests""" - def test_add_project(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "PROJECT_ID_PLACEHOLDER", + "name": "test-project", + "title": "Test Project", + }, + "status": 201, + } + ], + indirect=True, + ) + def test_add_project(self, mock_api_client, create_mock_response): """Test case for add_project""" api = ProjectApi(api_client=mock_api_client) project_id = uuid4() - project_data = { - "id": str(project_id), - "name": "test-project", - "title": "Test Project", - } - # Mock the API response - mock_response = mock_rest_response(data=project_data, status=201) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual project_id + create_mock_response.data = create_mock_response.data.replace( + b"PROJECT_ID_PLACEHOLDER", str(project_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Create project object to send project_item = Project(name="test-project", title="Test Project") @@ -47,18 +60,29 @@ def test_add_project(self, mock_api_client, mock_rest_response): assert args[3]["name"] == "test-project" assert args[3]["title"] == "Test Project" - def test_get_project(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "PROJECT_ID_PLACEHOLDER", + "name": "test-project", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_project(self, mock_api_client, create_mock_response): """Test case for get_project""" api = ProjectApi(api_client=mock_api_client) project_id = uuid4() - project_data = { - "id": str(project_id), - "name": "test-project", - } - # Mock the API response - mock_response = mock_rest_response(data=project_data, status=200) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual project_id + create_mock_response.data = create_mock_response.data.replace( + b"PROJECT_ID_PLACEHOLDER", str(project_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.get_project(id=str(project_id)) @@ -74,21 +98,28 @@ def test_get_project(self, mock_api_client, mock_rest_response): assert args[0] == "GET" assert args[1].endswith(f"/project/{project_id}") - def test_get_project_list(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "projects": [ + {"id": "00000000-0000-0000-0000-000000000001", "name": "project1"}, + {"id": "00000000-0000-0000-0000-000000000002", "name": "project2"}, + ], + "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_project_list(self, mock_api_client, create_mock_response): """Test case for get_project_list""" api = ProjectApi(api_client=mock_api_client) - project_list_data = { - "projects": [ - {"id": str(uuid4()), "name": "project1"}, - {"id": str(uuid4()), "name": "project2"}, - ], - "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, - } - # Mock the API response - mock_response = mock_rest_response(data=project_list_data, status=200) - mock_api_client.call_api.return_value = mock_response + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.get_project_list(page=1, page_size=25, owner_id="user1") @@ -112,18 +143,29 @@ def test_get_project_list(self, mock_api_client, mock_rest_response): assert query_params["pageSize"] == ["25"] assert query_params["ownerId"] == ["user1"] - def test_update_project(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "PROJECT_ID_PLACEHOLDER", + "name": "updated-project", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_update_project(self, mock_api_client, create_mock_response): """Test case for update_project""" api = ProjectApi(api_client=mock_api_client) project_id = uuid4() - project_data = { - "id": str(project_id), - "name": "updated-project", - } - # Mock the API response - mock_response = mock_rest_response(data=project_data, status=200) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual project_id + create_mock_response.data = create_mock_response.data.replace( + b"PROJECT_ID_PLACEHOLDER", str(project_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Update object project_update = Project(name="updated-project") @@ -146,22 +188,30 @@ def test_update_project(self, mock_api_client, mock_rest_response): assert isinstance(args[3], dict) assert args[3]["name"] == "updated-project" - def test_get_filter_params(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": ["env", "component", "tag"], + "status": 200, + } + ], + indirect=True, + ) + def test_get_filter_params(self, mock_api_client, create_mock_response): """Test case for get_filter_params""" api = ProjectApi(api_client=mock_api_client) project_id = uuid4() - filter_params = ["env", "component", "tag"] # Mock the API response - mock_response = mock_rest_response(data=filter_params, status=200) - mock_api_client.call_api.return_value = mock_response + mock_api_client.call_api.return_value = create_mock_response # Call API response = api.get_filter_params(id=str(project_id)) # Verify result assert isinstance(response, list) - assert response == filter_params + assert response == ["env", "component", "tag"] # Verify call mock_api_client.call_api.assert_called_once() diff --git a/test/test_result_api.py b/test/test_result_api.py index a122d12..0593c49 100644 --- a/test/test_result_api.py +++ b/test/test_result_api.py @@ -3,6 +3,8 @@ from urllib.parse import parse_qs, urlparse from uuid import uuid4 +import pytest + from ibutsu_client.api.result_api import ResultApi from ibutsu_client.models.result import Result from ibutsu_client.models.result_list import ResultList @@ -11,20 +13,31 @@ class TestResultApi: """ResultApi Tests""" - def test_add_result(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "RESULT_ID_PLACEHOLDER", + "test_id": "test_case_1", + "result": "passed", + "duration": 1.5, + }, + "status": 201, + } + ], + indirect=True, + ) + def test_add_result(self, mock_api_client, create_mock_response): """Test case for add_result""" api = ResultApi(api_client=mock_api_client) result_id = uuid4() - result_data = { - "id": str(result_id), - "test_id": "test_case_1", - "result": "passed", - "duration": 1.5, - } - # Mock the API response - mock_response = mock_rest_response(data=result_data, status=201) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual result_id + create_mock_response.data = create_mock_response.data.replace( + b"RESULT_ID_PLACEHOLDER", str(result_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Create result object to send result_item = Result(test_id="test_case_1", result="passed", duration=1.5) @@ -50,19 +63,30 @@ def test_add_result(self, mock_api_client, mock_rest_response): assert args[3]["result"] == "passed" assert args[3]["duration"] == 1.5 - def test_get_result(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "RESULT_ID_PLACEHOLDER", + "test_id": "test_case_1", + "result": "passed", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_result(self, mock_api_client, create_mock_response): """Test case for get_result""" api = ResultApi(api_client=mock_api_client) result_id = uuid4() - result_data = { - "id": str(result_id), - "test_id": "test_case_1", - "result": "passed", - } - # Mock the API response - mock_response = mock_rest_response(data=result_data, status=200) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual result_id + create_mock_response.data = create_mock_response.data.replace( + b"RESULT_ID_PLACEHOLDER", str(result_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.get_result(id=result_id) @@ -78,21 +102,36 @@ def test_get_result(self, mock_api_client, mock_rest_response): assert args[0] == "GET" assert args[1].endswith(f"/result/{result_id}") - def test_get_result_list(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "results": [ + { + "id": "00000000-0000-0000-0000-000000000001", + "test_id": "test_1", + "result": "passed", + }, + { + "id": "00000000-0000-0000-0000-000000000002", + "test_id": "test_2", + "result": "failed", + }, + ], + "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_result_list(self, mock_api_client, create_mock_response): """Test case for get_result_list""" api = ResultApi(api_client=mock_api_client) - result_list_data = { - "results": [ - {"id": str(uuid4()), "test_id": "test_1", "result": "passed"}, - {"id": str(uuid4()), "test_id": "test_2", "result": "failed"}, - ], - "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, - } - # Mock the API response - mock_response = mock_rest_response(data=result_list_data, status=200) - mock_api_client.call_api.return_value = mock_response + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.get_result_list(page=1, page_size=25, filter=["result=passed"]) @@ -116,19 +155,30 @@ def test_get_result_list(self, mock_api_client, mock_rest_response): assert query_params["pageSize"] == ["25"] assert query_params["filter"] == ["result=passed"] - def test_update_result(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "RESULT_ID_PLACEHOLDER", + "test_id": "test_case_1", + "result": "failed", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_update_result(self, mock_api_client, create_mock_response): """Test case for update_result""" api = ResultApi(api_client=mock_api_client) result_id = uuid4() - result_data = { - "id": str(result_id), - "test_id": "test_case_1", - "result": "failed", # Updated result - } - # Mock the API response - mock_response = mock_rest_response(data=result_data, status=200) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual result_id + create_mock_response.data = create_mock_response.data.replace( + b"RESULT_ID_PLACEHOLDER", str(result_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Update object result_update = Result(result="failed") diff --git a/test/test_run_api.py b/test/test_run_api.py index 22ace4e..0ecde65 100644 --- a/test/test_run_api.py +++ b/test/test_run_api.py @@ -3,6 +3,8 @@ from urllib.parse import parse_qs, urlparse from uuid import uuid4 +import pytest + from ibutsu_client.api.run_api import RunApi from ibutsu_client.models.run import Run from ibutsu_client.models.run_list import RunList @@ -12,19 +14,30 @@ class TestRunApi: """RunApi Tests""" - def test_add_run(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "RUN_ID_PLACEHOLDER", + "component": "test-component", + "env": "ci", + }, + "status": 201, + } + ], + indirect=True, + ) + def test_add_run(self, mock_api_client, create_mock_response): """Test case for add_run""" api = RunApi(api_client=mock_api_client) run_id = uuid4() - run_data = { - "id": str(run_id), - "component": "test-component", - "env": "ci", - } - # Mock the API response - mock_response = mock_rest_response(data=run_data, status=201) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual run_id + create_mock_response.data = create_mock_response.data.replace( + b"RUN_ID_PLACEHOLDER", str(run_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Create run object to send run_item = Run(component="test-component", env="ci") @@ -48,18 +61,29 @@ def test_add_run(self, mock_api_client, mock_rest_response): assert args[3]["component"] == "test-component" assert args[3]["env"] == "ci" - def test_get_run(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "RUN_ID_PLACEHOLDER", + "component": "test-component", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_run(self, mock_api_client, create_mock_response): """Test case for get_run""" api = RunApi(api_client=mock_api_client) run_id = uuid4() - run_data = { - "id": str(run_id), - "component": "test-component", - } - # Mock the API response - mock_response = mock_rest_response(data=run_data, status=200) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual run_id + create_mock_response.data = create_mock_response.data.replace( + b"RUN_ID_PLACEHOLDER", str(run_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.get_run(id=run_id) @@ -75,21 +99,28 @@ def test_get_run(self, mock_api_client, mock_rest_response): assert args[0] == "GET" assert args[1].endswith(f"/run/{run_id}") - def test_get_run_list(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "runs": [ + {"id": "00000000-0000-0000-0000-000000000001", "component": "comp1"}, + {"id": "00000000-0000-0000-0000-000000000002", "component": "comp2"}, + ], + "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_run_list(self, mock_api_client, create_mock_response): """Test case for get_run_list""" api = RunApi(api_client=mock_api_client) - run_list_data = { - "runs": [ - {"id": str(uuid4()), "component": "comp1"}, - {"id": str(uuid4()), "component": "comp2"}, - ], - "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, - } - # Mock the API response - mock_response = mock_rest_response(data=run_list_data, status=200) - mock_api_client.call_api.return_value = mock_response + mock_api_client.call_api.return_value = create_mock_response # Call the API response = api.get_run_list(page=1, page_size=25, filter=["env=ci"]) @@ -113,18 +144,29 @@ def test_get_run_list(self, mock_api_client, mock_rest_response): assert query_params["pageSize"] == ["25"] assert query_params["filter"] == ["env=ci"] - def test_update_run(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "RUN_ID_PLACEHOLDER", + "component": "updated-component", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_update_run(self, mock_api_client, create_mock_response): """Test case for update_run""" api = RunApi(api_client=mock_api_client) run_id = uuid4() - run_data = { - "id": str(run_id), - "component": "updated-component", - } - # Mock the API response - mock_response = mock_rest_response(data=run_data, status=200) - mock_api_client.call_api.return_value = mock_response + # Update the mock response with the actual run_id + create_mock_response.data = create_mock_response.data.replace( + b"RUN_ID_PLACEHOLDER", str(run_id).encode() + ) + mock_api_client.call_api.return_value = create_mock_response # Update object run_update = Run(component="updated-component") @@ -147,21 +189,36 @@ def test_update_run(self, mock_api_client, mock_rest_response): assert isinstance(args[3], dict) assert args[3]["component"] == "updated-component" - def test_bulk_update(self, mock_api_client, mock_rest_response): + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "runs": [ + { + "id": "00000000-0000-0000-0000-000000000001", + "component": "comp1", + "metadata": {"new": "val"}, + }, + { + "id": "00000000-0000-0000-0000-000000000002", + "component": "comp2", + "metadata": {"new": "val"}, + }, + ], + "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, + }, + "status": 200, + } + ], + indirect=True, + ) + def test_bulk_update(self, mock_api_client, create_mock_response): """Test case for bulk_update""" api = RunApi(api_client=mock_api_client) - run_list_data = { - "runs": [ - {"id": str(uuid4()), "component": "comp1", "metadata": {"new": "val"}}, - {"id": str(uuid4()), "component": "comp2", "metadata": {"new": "val"}}, - ], - "pagination": {"page": 1, "pageSize": 25, "totalItems": 2, "totalPages": 1}, - } - # Mock the API response - mock_response = mock_rest_response(data=run_list_data, status=200) - mock_api_client.call_api.return_value = mock_response + mock_api_client.call_api.return_value = create_mock_response # Update object update_data = UpdateRun(metadata={"new": "val"}) diff --git a/test/test_task_api.py b/test/test_task_api.py index 31d589f..558c837 100644 --- a/test/test_task_api.py +++ b/test/test_task_api.py @@ -9,26 +9,245 @@ Do not edit the class manually. """ -import unittest +import pytest from ibutsu_client.api.task_api import TaskApi +from ibutsu_client.exceptions import NotFoundException, ServiceException -class TestTaskApi(unittest.TestCase): - """TaskApi unit test stubs""" +class TestTaskApi: + """TaskApi comprehensive tests""" - def setUp(self) -> None: - self.api = TaskApi() + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "pending", + "task_type": "export", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_task_pending(self, mocker, create_mock_response): + """Test case for get_task with pending status""" + api = TaskApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def tearDown(self) -> None: - pass + task_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_task(id=task_id) - def test_get_task(self) -> None: - """Test case for get_task + assert result is not None + assert result["status"] == "pending" + assert result["task_type"] == "export" + api.api_client.call_api.assert_called_once() - Get the status or result of a task - """ + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "running", + "task_type": "bulk_update", + "progress": 45, + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_task_running(self, mocker, create_mock_response): + """Test case for get_task with running status""" + api = TaskApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + task_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_task(id=task_id) -if __name__ == "__main__": - unittest.main() + assert result is not None + assert result["status"] == "running" + assert result["progress"] == 45 + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "completed", + "task_type": "export", + "result": { + "file_url": "https://example.com/exports/results.tar.gz", + "file_size": 1024000, + }, + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_task_completed(self, mocker, create_mock_response): + """Test case for get_task with completed status""" + api = TaskApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + task_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_task(id=task_id) + + assert result is not None + assert result["status"] == "completed" + assert result["result"]["file_url"] == "https://example.com/exports/results.tar.gz" + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "failed", + "task_type": "bulk_update", + "error": "Database connection timeout", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_task_failed(self, mocker, create_mock_response): + """Test case for get_task with failed status""" + api = TaskApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + task_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_task(id=task_id) + + assert result is not None + assert result["status"] == "failed" + assert result["error"] == "Database connection timeout" + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "task not found"}, "status": 404}], + indirect=True, + ) + def test_get_task_not_found(self, mocker, create_mock_response): + """Test case for get_task with non-existent task""" + api = TaskApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + task_id = "550e8400-e29b-41d4-a716-446655440000" + with pytest.raises(NotFoundException): + api.get_task(id=task_id) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "completed", + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_task_with_http_info(self, mocker, create_mock_response): + """Test case for get_task_with_http_info""" + api = TaskApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + task_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_task_with_http_info(id=task_id) + + assert result.status_code == 200 + assert result.data is not None + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "unauthorized"}, "status": 401}], + indirect=True, + ) + def test_get_task_unauthorized(self, mocker, create_mock_response): + """Test case for get_task without authentication""" + api = TaskApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + task_id = "550e8400-e29b-41d4-a716-446655440000" + with pytest.raises((ServiceException, Exception)): + api.get_task(id=task_id) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "internal error"}, "status": 500}], + indirect=True, + ) + def test_get_task_server_error(self, mocker, create_mock_response): + """Test case for get_task with server error""" + api = TaskApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + task_id = "550e8400-e29b-41d4-a716-446655440000" + with pytest.raises(ServiceException): + api.get_task(id=task_id) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "completed", + "task_type": "export", + "result": { + "format": "json", + "records_exported": 1000, + }, + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_task_export_type(self, mocker, create_mock_response): + """Test case for get_task with export task type""" + api = TaskApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + task_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_task(id=task_id) + + assert result["task_type"] == "export" + assert result["result"]["records_exported"] == 1000 + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "completed", + "task_type": "bulk_update", + "result": { + "updated_count": 150, + }, + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_task_bulk_update_type(self, mocker, create_mock_response): + """Test case for get_task with bulk_update task type""" + api = TaskApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + task_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_task(id=task_id) + + assert result["task_type"] == "bulk_update" + assert result["result"]["updated_count"] == 150 diff --git a/test/test_user_api.py b/test/test_user_api.py index d43a303..5207938 100644 --- a/test/test_user_api.py +++ b/test/test_user_api.py @@ -9,56 +9,338 @@ Do not edit the class manually. """ -import unittest +import pytest from ibutsu_client.api.user_api import UserApi +from ibutsu_client.exceptions import NotFoundException, ServiceException +from ibutsu_client.models.create_token import CreateToken +from ibutsu_client.models.token import Token +from ibutsu_client.models.token_list import TokenList +from ibutsu_client.models.user import User +from test.utils import sample_pagination_data, sample_token_data, sample_user_data -class TestUserApi(unittest.TestCase): - """UserApi unit test stubs""" +class TestUserApi: + """UserApi comprehensive tests""" - def setUp(self) -> None: - self.api = UserApi() + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_token_data(name="api-token", expires="2025-12-31"), "status": 201}], + indirect=True, + ) + def test_add_token_success(self, mocker, create_mock_response): + """Test case for add_token - successfully create a token""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def tearDown(self) -> None: - pass + create_token = CreateToken(name="api-token", expires="2025-12-31") + result = api.add_token(create_token=create_token) - def test_add_token(self) -> None: - """Test case for add_token + assert isinstance(result, Token) + assert result.name == "api-token" + assert result.expires == "2025-12-31" + api.api_client.call_api.assert_called_once() - Create a token for the current user - """ + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "unauthorized"}, "status": 401}], + indirect=True, + ) + def test_add_token_unauthorized(self, mocker, create_mock_response): + """Test case for add_token with no authentication""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def test_delete_token(self) -> None: - """Test case for delete_token + create_token = CreateToken(name="test-token", expires="2025-12-31") + with pytest.raises((ServiceException, Exception)): # Should raise unauthorized exception + api.add_token(create_token=create_token) - Delete the token - """ + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_token_data(name="test-token"), "status": 201}], + indirect=True, + ) + def test_add_token_with_http_info(self, mocker, create_mock_response): + """Test case for add_token_with_http_info""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def test_get_current_user(self) -> None: - """Test case for get_current_user + create_token = CreateToken(name="test-token", expires="2025-12-31") + result = api.add_token_with_http_info(create_token=create_token) - Return the user details for the current user - """ + assert result.status_code == 201 + assert isinstance(result.data, Token) - def test_get_token(self) -> None: - """Test case for get_token + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {}, "status": 204}], + indirect=True, + ) + def test_delete_token_success(self, mocker, create_mock_response): + """Test case for delete_token - successfully delete a token""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - Retrieve a single token for the current user - """ + token_id = "550e8400-e29b-41d4-a716-446655440000" + api.delete_token(id=token_id) - def test_get_token_list(self) -> None: - """Test case for get_token_list + # 204 No Content typically returns None + api.api_client.call_api.assert_called_once() - Return the tokens for the user - """ + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "not found"}, "status": 404}], + indirect=True, + ) + def test_delete_token_not_found(self, mocker, create_mock_response): + """Test case for delete_token with non-existent token""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def test_update_current_user(self) -> None: - """Test case for update_current_user + token_id = "550e8400-e29b-41d4-a716-446655440000" + with pytest.raises(NotFoundException): + api.delete_token(id=token_id) - Return the user details for the current user - """ + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {}, "status": 204}], + indirect=True, + ) + def test_delete_token_with_http_info(self, mocker, create_mock_response): + """Test case for delete_token_with_http_info""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + token_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.delete_token_with_http_info(id=token_id) -if __name__ == "__main__": - unittest.main() + assert result.status_code == 204 + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": sample_user_data(email="current@example.com", name="Current User"), + "status": 200, + } + ], + indirect=True, + ) + def test_get_current_user_success(self, mocker, create_mock_response): + """Test case for get_current_user - retrieve current user details""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_current_user() + + assert isinstance(result, User) + assert result.email == "current@example.com" + assert result.name == "Current User" + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "unauthorized"}, "status": 401}], + indirect=True, + ) + def test_get_current_user_unauthorized(self, mocker, create_mock_response): + """Test case for get_current_user without authentication""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + with pytest.raises((ServiceException, Exception)): + api.get_current_user() + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_user_data(), "status": 200}], + indirect=True, + ) + def test_get_current_user_with_http_info(self, mocker, create_mock_response): + """Test case for get_current_user_with_http_info""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_current_user_with_http_info() + + assert result.status_code == 200 + assert isinstance(result.data, User) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_token_data(name="specific-token"), "status": 200}], + indirect=True, + ) + def test_get_token_success(self, mocker, create_mock_response): + """Test case for get_token - retrieve a single token""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + token_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_token(id=token_id) + + assert isinstance(result, Token) + assert result.name == "specific-token" + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "not found"}, "status": 404}], + indirect=True, + ) + def test_get_token_not_found(self, mocker, create_mock_response): + """Test case for get_token with non-existent token""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + token_id = "550e8400-e29b-41d4-a716-446655440000" + with pytest.raises(NotFoundException): + api.get_token(id=token_id) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_token_data(), "status": 200}], + indirect=True, + ) + def test_get_token_with_http_info(self, mocker, create_mock_response): + """Test case for get_token_with_http_info""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + token_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_token_with_http_info(id=token_id) + + assert result.status_code == 200 + assert isinstance(result.data, Token) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "tokens": [ + sample_token_data(name="token1"), + sample_token_data(name="token2"), + ], + "pagination": sample_pagination_data(page=1, page_size=25, total_items=2), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_token_list_success(self, mocker, create_mock_response): + """Test case for get_token_list - retrieve list of tokens""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_token_list() + + assert isinstance(result, TokenList) + assert len(result.tokens) == 2 + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "tokens": [sample_token_data()], + "pagination": sample_pagination_data(page=2, page_size=10), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_token_list_with_pagination(self, mocker, create_mock_response): + """Test case for get_token_list with pagination parameters""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_token_list(page=2, page_size=10) + + assert isinstance(result, TokenList) + api.api_client.call_api.assert_called_once() + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "tokens": [], + "pagination": sample_pagination_data(), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_token_list_with_http_info(self, mocker, create_mock_response): + """Test case for get_token_list_with_http_info""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_token_list_with_http_info() + + assert result.status_code == 200 + assert isinstance(result.data, TokenList) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": sample_user_data(email="current@example.com", name="Current User"), + "status": 200, + } + ], + indirect=True, + ) + def test_update_current_user_success(self, mocker, create_mock_response): + """Test case for update_current_user - get current user details""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.update_current_user() + + assert isinstance(result, User) + assert result.email == "current@example.com" + assert result.name == "Current User" + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "unauthorized"}, "status": 401}], + indirect=True, + ) + def test_update_current_user_unauthorized(self, mocker, create_mock_response): + """Test case for update_current_user without authentication""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + with pytest.raises((ServiceException, Exception)): + api.update_current_user() + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_user_data(), "status": 200}], + indirect=True, + ) + def test_update_current_user_with_http_info(self, mocker, create_mock_response): + """Test case for update_current_user_with_http_info""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.update_current_user_with_http_info() + + assert result.status_code == 200 + assert isinstance(result.data, User) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "internal error"}, "status": 500}], + indirect=True, + ) + def test_update_current_user_server_error(self, mocker, create_mock_response): + """Test case for update_current_user with server error""" + api = UserApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + with pytest.raises(ServiceException): + api.update_current_user() diff --git a/test/test_widget_api.py b/test/test_widget_api.py index 345f8cb..7fb7145 100644 --- a/test/test_widget_api.py +++ b/test/test_widget_api.py @@ -9,32 +9,198 @@ Do not edit the class manually. """ -import unittest +import pytest from ibutsu_client.api.widget_api import WidgetApi +from ibutsu_client.exceptions import NotFoundException, ServiceException +from ibutsu_client.models.widget_type_list import WidgetTypeList -class TestWidgetApi(unittest.TestCase): - """WidgetApi unit test stubs""" +class TestWidgetApi: + """WidgetApi comprehensive tests""" - def setUp(self) -> None: - self.api = WidgetApi() + # Parametrized tests for get_widget with various scenarios + @pytest.mark.parametrize( + "create_mock_response,widget_params,expected_type,expected_exception", + [ + pytest.param( + { + "data": { + "type": "result-summary", + "data": {"passed": 100, "failed": 5, "skipped": 2, "error": 0}, + }, + "status": 200, + }, + {}, + "result-summary", + None, + id="success_basic", + ), + pytest.param( + { + "data": {"type": "jenkins-heatmap", "data": {"rows": [], "columns": []}}, + "status": 200, + }, + {"params": {"project": "test-project", "env": "production"}}, + "jenkins-heatmap", + None, + id="success_with_filters", + ), + pytest.param( + { + "data": {"type": "result-aggregation", "data": {"aggregations": []}}, + "status": 200, + }, + {"params": {"group_by": "component", "limit": 10}}, + "result-aggregation", + None, + id="success_with_params", + ), + pytest.param( + {"data": {"error": "widget not found"}, "status": 404}, + {}, + None, + NotFoundException, + id="not_found", + ), + pytest.param( + {"data": {"error": "internal error"}, "status": 500}, + {}, + None, + ServiceException, + id="server_error", + ), + ], + indirect=["create_mock_response"], + ) + def test_get_widget( + self, mocker, create_mock_response, widget_params, expected_type, expected_exception + ): + """Test get_widget with various response scenarios.""" + api = WidgetApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def tearDown(self) -> None: - pass + widget_id = "550e8400-e29b-41d4-a716-446655440000" - def test_get_widget(self) -> None: - """Test case for get_widget + if expected_exception: + with pytest.raises(expected_exception): + api.get_widget(id=widget_id, **widget_params) + else: + result = api.get_widget(id=widget_id, **widget_params) + assert result is not None + assert result["type"] == expected_type + api.api_client.call_api.assert_called_once() - Generate data for a dashboard widget - """ + @pytest.mark.parametrize( + "create_mock_response", + [ + pytest.param( + {"data": {"type": "test-widget", "data": {}}, "status": 200}, + id="http_info_success", + ), + ], + indirect=True, + ) + def test_get_widget_with_http_info(self, mocker, create_mock_response): + """Test get_widget_with_http_info.""" + api = WidgetApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def test_get_widget_types(self) -> None: - """Test case for get_widget_types + widget_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_widget_with_http_info(id=widget_id) - Get a list of widget types - """ + assert result.status_code == 200 + assert result.data is not None + # Parametrized tests for get_widget_types + @pytest.mark.parametrize( + "create_mock_response,expected_count,expected_exception", + [ + pytest.param( + { + "data": { + "types": [ + { + "name": "result-summary", + "description": "Summary of test results", + "params": [], + }, + { + "name": "jenkins-heatmap", + "description": "Jenkins build heatmap", + "params": [], + }, + { + "name": "result-aggregation", + "description": "Aggregated test results", + "params": [], + }, + ] + }, + "status": 200, + }, + 3, + None, + id="success_multiple_types", + ), + pytest.param( + {"data": {"types": []}, "status": 200}, + 0, + None, + id="success_empty", + ), + pytest.param( + {"data": {"error": "internal error"}, "status": 500}, + None, + ServiceException, + id="server_error", + ), + ], + indirect=["create_mock_response"], + ) + def test_get_widget_types( + self, mocker, create_mock_response, expected_count, expected_exception + ): + """Test get_widget_types with various response scenarios.""" + api = WidgetApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) -if __name__ == "__main__": - unittest.main() + if expected_exception: + with pytest.raises(expected_exception): + api.get_widget_types() + else: + result = api.get_widget_types() + assert isinstance(result, WidgetTypeList) + assert len(result.types) == expected_count + api.api_client.call_api.assert_called_once() + + @pytest.mark.parametrize( + "create_mock_response", + [ + pytest.param( + { + "data": { + "types": [ + { + "name": "result-summary", + "description": "Summary", + "params": [], + } + ] + }, + "status": 200, + }, + id="http_info_success", + ), + ], + indirect=True, + ) + def test_get_widget_types_with_http_info(self, mocker, create_mock_response): + """Test get_widget_types_with_http_info.""" + api = WidgetApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_widget_types_with_http_info() + + assert result.status_code == 200 + assert isinstance(result.data, WidgetTypeList) diff --git a/test/test_widget_config_api.py b/test/test_widget_config_api.py index 486e106..e568c52 100644 --- a/test/test_widget_config_api.py +++ b/test/test_widget_config_api.py @@ -9,50 +9,355 @@ Do not edit the class manually. """ -import unittest +import pytest from ibutsu_client.api.widget_config_api import WidgetConfigApi +from ibutsu_client.exceptions import NotFoundException, ServiceException +from ibutsu_client.models.widget_config import WidgetConfig +from ibutsu_client.models.widget_config_list import WidgetConfigList +from test.utils import sample_pagination_data, sample_widget_config_data -class TestWidgetConfigApi(unittest.TestCase): - """WidgetConfigApi unit test stubs""" +class TestWidgetConfigApi: + """WidgetConfigApi comprehensive tests""" - def setUp(self) -> None: - self.api = WidgetConfigApi() + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": sample_widget_config_data(widget="result-summary", weight=0), + "status": 201, + } + ], + indirect=True, + ) + def test_add_widget_config_success(self, mocker, create_mock_response): + """Test case for add_widget_config - successfully create a widget config""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def tearDown(self) -> None: - pass + widget_config = WidgetConfig(type="widget", widget="result-summary", weight=0, params={}) + result = api.add_widget_config(widget_config=widget_config) - def test_add_widget_config(self) -> None: - """Test case for add_widget_config + assert isinstance(result, WidgetConfig) + assert result.widget == "result-summary" + assert result.weight == 0 + api.api_client.call_api.assert_called_once() - Create a widget configuration - """ + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": sample_widget_config_data( + widget="result-aggregation", + weight=5, + params={"filter": "result:passed", "chart_type": "bar"}, + ), + "status": 201, + } + ], + indirect=True, + ) + def test_add_widget_config_with_params(self, mocker, create_mock_response): + """Test case for add_widget_config with widget parameters""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - def test_delete_widget_config(self) -> None: - """Test case for delete_widget_config + params = {"filter": "result:passed", "chart_type": "bar"} + widget_config = WidgetConfig( + type="widget", widget="result-aggregation", weight=5, params=params + ) + result = api.add_widget_config(widget_config=widget_config) - Delete a widget configuration - """ + assert isinstance(result, WidgetConfig) + assert result.params == params - def test_get_widget_config(self) -> None: - """Test case for get_widget_config + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "unauthorized"}, "status": 401}], + indirect=True, + ) + def test_add_widget_config_unauthorized(self, mocker, create_mock_response): + """Test case for add_widget_config without authentication""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - Get a single widget configuration - """ + widget_config = WidgetConfig(type="widget", widget="test", weight=0) + with pytest.raises((ServiceException, Exception)): + api.add_widget_config(widget_config=widget_config) - def test_get_widget_config_list(self) -> None: - """Test case for get_widget_config_list + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_widget_config_data(), "status": 201}], + indirect=True, + ) + def test_add_widget_config_with_http_info(self, mocker, create_mock_response): + """Test case for add_widget_config_with_http_info""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) - Get the list of widget configurations - """ + widget_config = WidgetConfig(type="widget", widget="test", weight=0) + result = api.add_widget_config_with_http_info(widget_config=widget_config) - def test_update_widget_config(self) -> None: - """Test case for update_widget_config + assert result.status_code == 201 + assert isinstance(result.data, WidgetConfig) - Updates a single widget configuration - """ + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {}, "status": 204}], + indirect=True, + ) + def test_delete_widget_config_success(self, mocker, create_mock_response): + """Test case for delete_widget_config - successfully delete a widget""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + widget_id = "550e8400-e29b-41d4-a716-446655440000" + api.delete_widget_config(id=widget_id) -if __name__ == "__main__": - unittest.main() + # 204 No Content typically returns None + api.api_client.call_api.assert_called_once() + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "not found"}, "status": 404}], + indirect=True, + ) + def test_delete_widget_config_not_found(self, mocker, create_mock_response): + """Test case for delete_widget_config with non-existent widget""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + widget_id = "550e8400-e29b-41d4-a716-446655440000" + with pytest.raises(NotFoundException): + api.delete_widget_config(id=widget_id) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {}, "status": 204}], + indirect=True, + ) + def test_delete_widget_config_with_http_info(self, mocker, create_mock_response): + """Test case for delete_widget_config_with_http_info""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + widget_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.delete_widget_config_with_http_info(id=widget_id) + + assert result.status_code == 204 + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": sample_widget_config_data(widget="jenkins-heatmap"), + "status": 200, + } + ], + indirect=True, + ) + def test_get_widget_config_success(self, mocker, create_mock_response): + """Test case for get_widget_config - retrieve a single widget config""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + widget_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_widget_config(id=widget_id) + + assert isinstance(result, WidgetConfig) + assert result.widget == "jenkins-heatmap" + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "not found"}, "status": 404}], + indirect=True, + ) + def test_get_widget_config_not_found(self, mocker, create_mock_response): + """Test case for get_widget_config with non-existent widget""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + widget_id = "550e8400-e29b-41d4-a716-446655440000" + with pytest.raises(NotFoundException): + api.get_widget_config(id=widget_id) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_widget_config_data(), "status": 200}], + indirect=True, + ) + def test_get_widget_config_with_http_info(self, mocker, create_mock_response): + """Test case for get_widget_config_with_http_info""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + widget_id = "550e8400-e29b-41d4-a716-446655440000" + result = api.get_widget_config_with_http_info(id=widget_id) + + assert result.status_code == 200 + assert isinstance(result.data, WidgetConfig) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "widgets": [ + sample_widget_config_data(widget="result-summary", weight=0), + sample_widget_config_data(widget="jenkins-heatmap", weight=1), + ], + "pagination": sample_pagination_data(total_items=2), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_widget_config_list_success(self, mocker, create_mock_response): + """Test case for get_widget_config_list - retrieve list of widget configs""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_widget_config_list() + + assert isinstance(result, WidgetConfigList) + assert len(result.widgets) == 2 + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "widgets": [sample_widget_config_data()], + "pagination": sample_pagination_data(total_items=1), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_widget_config_list_with_filters(self, mocker, create_mock_response): + """Test case for get_widget_config_list with filter parameters""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_widget_config_list(filter=["widget_type=result-summary"]) + + assert isinstance(result, WidgetConfigList) + api.api_client.call_api.assert_called_once() + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "widgets": [], + "pagination": sample_pagination_data(total_items=0), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_widget_config_list_empty(self, mocker, create_mock_response): + """Test case for get_widget_config_list with no widgets""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_widget_config_list() + + assert isinstance(result, WidgetConfigList) + assert len(result.widgets) == 0 + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": { + "widgets": [], + "pagination": sample_pagination_data(), + }, + "status": 200, + } + ], + indirect=True, + ) + def test_get_widget_config_list_with_http_info(self, mocker, create_mock_response): + """Test case for get_widget_config_list_with_http_info""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + result = api.get_widget_config_list_with_http_info() + + assert result.status_code == 200 + assert isinstance(result.data, WidgetConfigList) + + @pytest.mark.parametrize( + "create_mock_response", + [ + { + "data": sample_widget_config_data(widget="result-summary", weight=10), + "status": 200, + } + ], + indirect=True, + ) + def test_update_widget_config_success(self, mocker, create_mock_response): + """Test case for update_widget_config - successfully update a widget config""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + widget_id = "550e8400-e29b-41d4-a716-446655440000" + widget_config = WidgetConfig(type="widget", widget="result-summary", weight=10) + result = api.update_widget_config(id=widget_id, widget_config=widget_config) + + assert isinstance(result, WidgetConfig) + assert result.weight == 10 + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "not found"}, "status": 404}], + indirect=True, + ) + def test_update_widget_config_not_found(self, mocker, create_mock_response): + """Test case for update_widget_config with non-existent widget""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + widget_id = "550e8400-e29b-41d4-a716-446655440000" + widget_config = WidgetConfig(type="widget", widget="test", weight=0) + with pytest.raises(NotFoundException): + api.update_widget_config(id=widget_id, widget_config=widget_config) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": sample_widget_config_data(), "status": 200}], + indirect=True, + ) + def test_update_widget_config_with_http_info(self, mocker, create_mock_response): + """Test case for update_widget_config_with_http_info""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + widget_id = "550e8400-e29b-41d4-a716-446655440000" + widget_config = WidgetConfig(type="widget", widget="test", weight=5) + result = api.update_widget_config_with_http_info(id=widget_id, widget_config=widget_config) + + assert result.status_code == 200 + assert isinstance(result.data, WidgetConfig) + + @pytest.mark.parametrize( + "create_mock_response", + [{"data": {"error": "internal error"}, "status": 500}], + indirect=True, + ) + def test_update_widget_config_server_error(self, mocker, create_mock_response): + """Test case for update_widget_config with server error""" + api = WidgetConfigApi() + mocker.patch.object(api.api_client, "call_api", return_value=create_mock_response) + + widget_id = "550e8400-e29b-41d4-a716-446655440000" + widget_config = WidgetConfig(type="widget", widget="test", weight=0) + with pytest.raises(ServiceException): + api.update_widget_config(id=widget_id, widget_config=widget_config) diff --git a/test/utils.py b/test/utils.py new file mode 100644 index 0000000..f32e4f5 --- /dev/null +++ b/test/utils.py @@ -0,0 +1,372 @@ +"""Test data factory functions for ibutsu_client tests.""" + +import uuid +from typing import Any + + +def sample_project_data( + project_id: str | None = None, + name: str = "test-project", + title: str = "Test Project", + owner_id: str | None = None, + group_id: str | None = None, +) -> dict[str, Any]: + """Factory function to create sample project data. + + Args: + project_id: Project UUID (generated if not provided) + name: Machine name of the project + title: Human-readable title + owner_id: Owner UUID + group_id: Group UUID + + Returns: + Dictionary with project data + """ + if project_id is None: + project_id = str(uuid.uuid4()) + if owner_id is None: + owner_id = str(uuid.uuid4()) + if group_id is None: + group_id = str(uuid.uuid4()) + + return { + "id": project_id, + "name": name, + "title": title, + "owner_id": owner_id, + "group_id": group_id, + } + + +def sample_run_data( + run_id: str | None = None, + project_id: str | None = None, + created: str = "2024-01-15T10:00:00", + start_time: str = "2024-01-15T10:00:00", + duration: float = 120.5, + source: str = "pytest", + component: str = "api", + env: str = "test", + summary: dict[str, Any] | None = None, + metadata: dict[str, Any] | None = None, +) -> dict[str, Any]: + """Factory function to create sample test run data. + + Args: + run_id: Run UUID (generated if not provided) + project_id: Project UUID (generated if not provided) + created: ISO timestamp of creation + start_time: ISO timestamp of run start + duration: Duration in seconds + source: Source system identifier + component: Component under test + env: Test environment + summary: Summary statistics + metadata: Additional metadata + + Returns: + Dictionary with run data + """ + if run_id is None: + run_id = str(uuid.uuid4()) + if project_id is None: + project_id = str(uuid.uuid4()) + if summary is None: + summary = {"passed": 10, "failed": 2, "skipped": 1, "errors": 0, "xfailed": 0} + if metadata is None: + metadata = {"jenkins_build": "123", "branch": "main"} + + return { + "id": run_id, + "project_id": project_id, + "created": created, + "start_time": start_time, + "duration": duration, + "source": source, + "component": component, + "env": env, + "summary": summary, + "metadata": metadata, + } + + +def sample_result_data( + result_id: str | None = None, + run_id: str | None = None, + project_id: str | None = None, + test_id: str = "test_example.py::TestClass::test_method", + start_time: str = "2024-01-15T10:00:00", + duration: float = 1.5, + result: str = "passed", + component: str = "api", + env: str = "test", + source: str = "pytest", + metadata: dict[str, Any] | None = None, + params: dict[str, Any] | None = None, +) -> dict[str, Any]: + """Factory function to create sample test result data. + + Args: + result_id: Result UUID (generated if not provided) + run_id: Associated run UUID (generated if not provided) + project_id: Project UUID (generated if not provided) + test_id: Test identifier + start_time: ISO timestamp + duration: Duration in seconds + result: Test result status (passed, failed, error, skipped, etc.) + component: Component under test + env: Test environment + source: Source system identifier + metadata: Additional metadata + params: Test parameters + + Returns: + Dictionary with result data + """ + if result_id is None: + result_id = str(uuid.uuid4()) + if run_id is None: + run_id = str(uuid.uuid4()) + if project_id is None: + project_id = str(uuid.uuid4()) + if metadata is None: + metadata = {"test_file": "test_example.py", "line_number": 42} + if params is None: + params = {} + + return { + "id": result_id, + "run_id": run_id, + "project_id": project_id, + "test_id": test_id, + "start_time": start_time, + "duration": duration, + "result": result, + "component": component, + "env": env, + "source": source, + "metadata": metadata, + "params": params, + } + + +def sample_artifact_data( + artifact_id: str | None = None, + filename: str = "test_log.txt", + result_id: str | None = None, + run_id: str | None = None, + project_id: str | None = None, +) -> dict[str, Any]: + """Factory function to create sample artifact data. + + Args: + artifact_id: Artifact UUID (generated if not provided) + filename: Artifact filename + result_id: Associated result UUID + run_id: Associated run UUID + project_id: Project UUID + + Returns: + Dictionary with artifact data + """ + if artifact_id is None: + artifact_id = str(uuid.uuid4()) + if result_id is None: + result_id = str(uuid.uuid4()) + if run_id is None: + run_id = str(uuid.uuid4()) + if project_id is None: + project_id = str(uuid.uuid4()) + + return { + "id": artifact_id, + "filename": filename, + "result_id": result_id, + "run_id": run_id, + "project_id": project_id, + } + + +def sample_pagination_data( + page: int = 1, + page_size: int = 25, + total_items: int = 100, + total_pages: int = 4, +) -> dict[str, Any]: + """Factory function to create sample pagination data. + + Args: + page: Current page number + page_size: Number of items per page + total_items: Total number of items + total_pages: Total number of pages + + Returns: + Dictionary with pagination data + """ + return { + "page": page, + "pageSize": page_size, + "totalItems": total_items, + "totalPages": total_pages, + } + + +def sample_user_data( + user_id: str | None = None, + email: str = "test@example.com", + name: str = "Test User", + is_superadmin: bool = False, + is_active: bool = True, +) -> dict[str, Any]: + """Factory function to create sample user data. + + Args: + user_id: User UUID (generated if not provided) + email: User email address + name: User full name + is_superadmin: Whether user is a superadmin + is_active: Whether user account is active + + Returns: + Dictionary with user data + """ + if user_id is None: + user_id = str(uuid.uuid4()) + + return { + "id": user_id, + "email": email, + "name": name, + "is_superadmin": is_superadmin, + "is_active": is_active, + } + + +def sample_dashboard_data( + dashboard_id: str | None = None, + title: str = "Test Dashboard", + project_id: str | None = None, + description: str | None = None, + filters: str | None = None, +) -> dict[str, Any]: + """Factory function to create sample dashboard data. + + Args: + dashboard_id: Dashboard UUID (generated if not provided) + title: Dashboard title + project_id: Project UUID (generated if not provided) + description: Dashboard description + filters: Dashboard filters + + Returns: + Dictionary with dashboard data + """ + if dashboard_id is None: + dashboard_id = str(uuid.uuid4()) + if project_id is None: + project_id = str(uuid.uuid4()) + + data = { + "id": dashboard_id, + "title": title, + "project_id": project_id, + } + if description is not None: + data["description"] = description + if filters is not None: + data["filters"] = filters + + return data + + +def sample_widget_config_data( + widget_id: str | None = None, + widget: str = "result-summary", + config_type: str = "widget", + weight: int = 0, + params: dict[str, Any] | None = None, + title: str | None = None, +) -> dict[str, Any]: + """Factory function to create sample widget configuration data. + + Args: + widget_id: Widget UUID (generated if not provided) + widget: Widget name to render + config_type: Type of config ("widget" or "view") + weight: Widget display weight/order + params: Widget parameters + title: Widget title + + Returns: + Dictionary with widget config data + """ + if widget_id is None: + widget_id = str(uuid.uuid4()) + if params is None: + params = {} + + return { + "id": widget_id, + "type": config_type, + "widget": widget, + "weight": weight, + "params": params, + "title": title, + } + + +def sample_group_data( + group_id: str | None = None, + name: str = "test-group", +) -> dict[str, Any]: + """Factory function to create sample group data. + + Args: + group_id: Group UUID (generated if not provided) + name: Group name + + Returns: + Dictionary with group data + """ + if group_id is None: + group_id = str(uuid.uuid4()) + + return { + "id": group_id, + "name": name, + } + + +def sample_token_data( + token_id: str | None = None, + user_id: str | None = None, + name: str = "test-token", + token: str = "test-token-value", + expires: str | None = "2025-12-31", +) -> dict[str, Any]: + """Factory function to create sample token data. + + Args: + token_id: Token UUID (generated if not provided) + user_id: User UUID (generated if not provided) + name: Token name/identifier + token: The actual token string + expires: Expiration date + + Returns: + Dictionary with token data + """ + if token_id is None: + token_id = str(uuid.uuid4()) + if user_id is None: + user_id = str(uuid.uuid4()) + + return { + "id": token_id, + "user_id": user_id, + "name": name, + "token": token, + "expires": expires, + }