from io import BytesIO from unittest.mock import patch from django.test import override_settings from openpyxl import load_workbook from rest_framework import status from rest_framework.test import APITestCase from apps.reports.services.oauth import OAuth2ClientCredentials class GenerateReportTests(APITestCase): @patch("apps.reports.services.data_sources.ReportDataSources.fetch_user_metrics") @patch("apps.reports.services.data_sources.ReportDataSources.fetch_users") def test_generate_user_report_is_public_and_returns_excel( self, mock_fetch_users, mock_fetch_user_metrics, ): mock_fetch_users.return_value = [ { "id": 1, "full_name": "Alice Doe", "email": "alice@example.com", "status": "active", } ] mock_fetch_user_metrics.return_value = { 1: {"ticket_count": 3}, } response = self.client.post( "/api/reports/generate/", { "report_type": "user", "filters": {"status": "active"}, }, format="json", ) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual( response["Content-Type"], "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ) self.assertEqual( response["Content-Disposition"], 'attachment; filename="user-report.xlsx"', ) workbook = load_workbook(BytesIO(response.content)) worksheet = workbook.active self.assertEqual(worksheet["A1"].value, "User Report") self.assertEqual( [cell.value for cell in worksheet[2]], ["User ID", "Full Name", "Email", "Status", "Ticket Count"], ) self.assertEqual( [cell.value for cell in worksheet[3]], [1, "Alice Doe", "alice@example.com", "active", 3], ) mock_fetch_users.assert_called_once_with({"status": "active"}) @patch("apps.reports.services.data_sources.ReportDataSources.fetch_ticket_metrics") @patch("apps.reports.services.data_sources.ReportDataSources.fetch_tickets") def test_generate_tickets_report_uses_static_columns( self, mock_fetch_tickets, mock_fetch_ticket_metrics, ): mock_fetch_tickets.return_value = [ { "id": 11, "title": "Login issue", "status": "open", "priority": "high", "assignee": {"name": "Support Agent"}, "created_at": "2026-05-20T10:00:00Z", } ] mock_fetch_ticket_metrics.return_value = {} response = self.client.post( "/api/reports/generate/", {"report_type": "tickets"}, format="json", ) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual( response["Content-Disposition"], 'attachment; filename="tickets-report.xlsx"', ) workbook = load_workbook(BytesIO(response.content)) worksheet = workbook.active self.assertEqual(worksheet["A1"].value, "Tickets Report") self.assertEqual( [cell.value for cell in worksheet[2]], ["Ticket ID", "Title", "Status", "Priority", "Assignee", "Created At"], ) self.assertEqual( [cell.value for cell in worksheet[3]], [ 11, "Login issue", "open", "high", "Support Agent", "2026-05-20T10:00:00Z", ], ) def test_unknown_report_type_returns_validation_error(self): response = self.client.post( "/api/reports/generate/", {"report_type": "unknown"}, format="json", ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) class OAuth2ClientCredentialsTests(APITestCase): @override_settings( OAUTH2_PROVIDER_PRIVATE_URL="https://auth.internal", OAUTH2_CLIENT_ID="client-id", OAUTH2_CLIENT_SECRET="client-secret", OAUTH2_SCOPES="reports:read customers:read", SERVICE_REQUEST_TIMEOUT=10, ) @patch("apps.reports.services.oauth.requests.post") def test_get_access_token_uses_client_credentials(self, mock_post): mock_post.return_value.json.return_value = { "access_token": "token-value", "expires_in": 3600, } mock_post.return_value.raise_for_status.return_value = None token = OAuth2ClientCredentials().get_access_token() self.assertEqual(token, "token-value") mock_post.assert_called_once_with( "https://auth.internal/oauth2/token", data={ "grant_type": "client_credentials", "scope": "reports:read customers:read", }, auth=("client-id", "client-secret"), timeout=10, )