|
| 1 | +import uuid |
| 2 | +from functools import wraps |
| 3 | +from unittest.mock import patch |
| 4 | + |
| 5 | +from rest_framework.authentication import BasicAuthentication |
| 6 | + |
| 7 | +from django.test import SimpleTestCase, override_settings |
| 8 | +from django.urls import resolve, reverse |
| 9 | + |
| 10 | +from temba.api.v2.projects.views import GetProjectView |
| 11 | +from temba.tests import TembaTest |
| 12 | + |
| 13 | +GET_PROJECT_VIEW_PATH = "temba.api.v2.projects.views.GetProjectView" |
| 14 | + |
| 15 | + |
| 16 | +def skip_auth_and_permissions(view_path: str): |
| 17 | + """ |
| 18 | + Decorator to disable authentication and permission checks for a specific endpoint class. |
| 19 | + Use when testing view logic (status codes and payload) without auth side-effects. |
| 20 | + """ |
| 21 | + |
| 22 | + def decorator(func): |
| 23 | + @patch(f"{view_path}.authentication_classes", []) |
| 24 | + @patch(f"{view_path}.permission_classes", []) |
| 25 | + @wraps(func) |
| 26 | + def wrapper(*args, **kwargs): |
| 27 | + return func(*args, **kwargs) |
| 28 | + |
| 29 | + return wrapper |
| 30 | + |
| 31 | + return decorator |
| 32 | + |
| 33 | + |
| 34 | +class GetProjectViewTest(TembaTest): |
| 35 | + def setUp(self): |
| 36 | + super().setUp() |
| 37 | + |
| 38 | + # Ensure org has a project UUID for lookups |
| 39 | + self.org.proj_uuid = uuid.uuid4() |
| 40 | + self.org.save(update_fields=("proj_uuid",)) |
| 41 | + |
| 42 | + self.url = reverse("api.v2.projects") |
| 43 | + |
| 44 | + @patch(f"{GET_PROJECT_VIEW_PATH}.authentication_classes", [BasicAuthentication]) |
| 45 | + def test_requires_authentication(self): |
| 46 | + # Without authentication headers, endpoint should deny access |
| 47 | + resp = self.client.get(f"{self.url}?project_uuid={self.org.proj_uuid}") |
| 48 | + self.assertEqual(resp.status_code, 401) |
| 49 | + |
| 50 | + @skip_auth_and_permissions(GET_PROJECT_VIEW_PATH) |
| 51 | + def test_missing_project_uuid_returns_400(self): |
| 52 | + resp = self.client.get(self.url) |
| 53 | + self.assertEqual(resp.status_code, 400) |
| 54 | + self.assertEqual(resp.json(), {"error": "project_uuid is required"}) |
| 55 | + |
| 56 | + @skip_auth_and_permissions(GET_PROJECT_VIEW_PATH) |
| 57 | + def test_nonexistent_project_returns_404(self): |
| 58 | + random_proj = uuid.uuid4() |
| 59 | + resp = self.client.get(f"{self.url}?project_uuid={random_proj}") |
| 60 | + self.assertEqual(resp.status_code, 404) |
| 61 | + self.assertEqual(resp.json(), {"error": "Project not found"}) |
| 62 | + |
| 63 | + @skip_auth_and_permissions(GET_PROJECT_VIEW_PATH) |
| 64 | + def test_success_returns_project_data(self): |
| 65 | + resp = self.client.get(f"{self.url}?project_uuid={self.org.proj_uuid}") |
| 66 | + self.assertEqual(resp.status_code, 200) |
| 67 | + data = resp.json() |
| 68 | + |
| 69 | + self.assertEqual(data["project_uuid"], str(self.org.proj_uuid)) |
| 70 | + self.assertEqual(data["name"], self.org.name) |
| 71 | + self.assertEqual(data["is_active"], self.org.is_active) |
| 72 | + self.assertEqual(data["brain_on"], self.org.brain_on) |
| 73 | + |
| 74 | + |
| 75 | +@override_settings(ROOT_URLCONF="temba.api.v2.projects.urls") |
| 76 | +class ProjectsUrlsTest(SimpleTestCase): |
| 77 | + def test_projects_url_resolves_to_get_project_view(self): |
| 78 | + url = reverse("projects") |
| 79 | + self.assertEqual(url, "/projects") |
| 80 | + match = resolve(url) |
| 81 | + self.assertEqual(getattr(match.func, "view_class", None), GetProjectView) |
0 commit comments