Skip to content

Commit 467cb33

Browse files
committed
API v1 initial tests.
1 parent ab3abb2 commit 467cb33

File tree

3 files changed

+207
-0
lines changed

3 files changed

+207
-0
lines changed

.github/workflows/ci.yaml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,53 @@ jobs:
3333

3434
- name: Run djhtml
3535
run: djhtml pgcommitfest/*/templates/*.html pgcommitfest/*/templates/*.inc --tabwidth=1 --check
36+
37+
test:
38+
runs-on: ubuntu-24.04
39+
name: "Django Tests"
40+
41+
services:
42+
postgres:
43+
image: postgres:14
44+
env:
45+
POSTGRES_USER: postgres
46+
POSTGRES_PASSWORD: postgres
47+
options: >-
48+
--health-cmd pg_isready
49+
--health-interval 10s
50+
--health-timeout 5s
51+
--health-retries 5
52+
ports:
53+
- 5432:5432
54+
55+
steps:
56+
- name: Checkout code
57+
uses: actions/checkout@v4
58+
59+
- name: Set up Python with uv
60+
uses: astral-sh/setup-uv@v4
61+
62+
- name: Create CI settings
63+
run: |
64+
cat > pgcommitfest/local_settings.py << 'EOF'
65+
# CI test settings
66+
DATABASES = {
67+
"default": {
68+
"ENGINE": "django.db.backends.postgresql_psycopg2",
69+
"NAME": "pgcommitfest",
70+
"USER": "postgres",
71+
"PASSWORD": "postgres",
72+
"HOST": "localhost",
73+
"PORT": "5432",
74+
}
75+
}
76+
77+
# Enable debug for better error messages in CI
78+
DEBUG = True
79+
EOF
80+
81+
- name: Install dependencies
82+
run: uv sync
83+
84+
- name: Run tests
85+
run: uv run manage.py test --verbosity=2
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Tests for the commitfest application
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
from django.test import Client, TestCase, override_settings
2+
3+
import json
4+
from datetime import date, timedelta
5+
6+
from pgcommitfest.commitfest.models import CommitFest
7+
8+
9+
@override_settings(AUTO_CREATE_COMMITFESTS=False)
10+
class NeedsCIEndpointTestCase(TestCase):
11+
"""Test the /api/v1/commitfests/needs_ci endpoint."""
12+
13+
@classmethod
14+
def setUpTestData(cls):
15+
today = date.today()
16+
17+
# Create test commitfests with various statuses
18+
cls.open_cf = CommitFest.objects.create(
19+
name="2025-01",
20+
status=CommitFest.STATUS_OPEN,
21+
startdate=today - timedelta(days=30),
22+
enddate=today + timedelta(days=30),
23+
draft=False,
24+
)
25+
26+
cls.in_progress_cf = CommitFest.objects.create(
27+
name="2024-11",
28+
status=CommitFest.STATUS_INPROGRESS,
29+
startdate=today - timedelta(days=60),
30+
enddate=today + timedelta(days=0),
31+
draft=False,
32+
)
33+
34+
# Previous CF that ended 3 days ago (should be included - within 7 day window)
35+
cls.recent_previous_cf = CommitFest.objects.create(
36+
name="2024-09",
37+
status=CommitFest.STATUS_CLOSED,
38+
startdate=today - timedelta(days=90),
39+
enddate=today - timedelta(days=3),
40+
draft=False,
41+
)
42+
43+
# Old previous CF that ended 10 days ago (should be excluded - outside 7 day window)
44+
cls.old_previous_cf = CommitFest.objects.create(
45+
name="2024-07",
46+
status=CommitFest.STATUS_CLOSED,
47+
startdate=today - timedelta(days=120),
48+
enddate=today - timedelta(days=10),
49+
draft=False,
50+
)
51+
52+
# Draft commitfest
53+
cls.draft_cf = CommitFest.objects.create(
54+
name="2025-03-draft",
55+
status=CommitFest.STATUS_OPEN,
56+
startdate=today + timedelta(days=60),
57+
enddate=today + timedelta(days=120),
58+
draft=True,
59+
)
60+
61+
def setUp(self):
62+
self.client = Client()
63+
64+
def test_endpoint_returns_200(self):
65+
"""Test that the endpoint returns HTTP 200 OK."""
66+
response = self.client.get("/api/v1/commitfests/needs_ci")
67+
self.assertEqual(response.status_code, 200)
68+
69+
def test_response_is_valid_json(self):
70+
"""Test that the response is valid JSON."""
71+
response = self.client.get("/api/v1/commitfests/needs_ci")
72+
try:
73+
data = json.loads(response.content)
74+
except json.JSONDecodeError:
75+
self.fail("Response is not valid JSON")
76+
77+
self.assertIn("commitfests", data)
78+
self.assertIsInstance(data["commitfests"], dict)
79+
80+
def test_response_content_type(self):
81+
"""Test that the response has correct Content-Type header."""
82+
response = self.client.get("/api/v1/commitfests/needs_ci")
83+
self.assertEqual(response["Content-Type"], "application/json")
84+
85+
def test_cors_header_present(self):
86+
"""Test that CORS header is present for API access."""
87+
response = self.client.get("/api/v1/commitfests/needs_ci")
88+
self.assertEqual(response["Access-Control-Allow-Origin"], "*")
89+
90+
def test_includes_open_commitfest(self):
91+
"""Test that open commitfests are included in response."""
92+
response = self.client.get("/api/v1/commitfests/needs_ci")
93+
data = json.loads(response.content)
94+
commitfests = data["commitfests"]
95+
96+
# Should include the open commitfest
97+
self.assertIn("open", commitfests)
98+
self.assertEqual(commitfests["open"]["name"], self.open_cf.name)
99+
100+
def test_includes_in_progress_commitfest(self):
101+
"""Test that in-progress commitfests are included in response."""
102+
response = self.client.get("/api/v1/commitfests/needs_ci")
103+
data = json.loads(response.content)
104+
commitfests = data["commitfests"]
105+
106+
# Should include the in-progress commitfest
107+
self.assertEqual(commitfests["in_progress"]["name"], self.in_progress_cf.name)
108+
109+
def test_includes_recent_previous_commitfest(self):
110+
"""Test that recently ended commitfests are included (within 7 days)."""
111+
response = self.client.get("/api/v1/commitfests/needs_ci")
112+
data = json.loads(response.content)
113+
commitfests = data["commitfests"]
114+
115+
# Should include recent previous commitfest (ended 3 days ago)
116+
self.assertIsNotNone(commitfests["previous"])
117+
118+
def test_excludes_old_previous_commitfest(self):
119+
"""Test that old commitfests are excluded (older than 7 days)."""
120+
response = self.client.get("/api/v1/commitfests/needs_ci")
121+
data = json.loads(response.content)
122+
commitfests = data["commitfests"]
123+
124+
# Should not include old previous commitfest (ended 10 days ago)
125+
self.assertNotEqual(
126+
commitfests["previous"]["name"],
127+
self.old_previous_cf.name,
128+
"Old previous commitfest should be excluded",
129+
)
130+
131+
def test_excludes_next_open_and_final(self):
132+
"""Test that next_open and final are excluded from response."""
133+
response = self.client.get("/api/v1/commitfests/needs_ci")
134+
data = json.loads(response.content)
135+
commitfests = data["commitfests"]
136+
137+
# These keys should not be present in the response
138+
self.assertNotIn("next_open", commitfests)
139+
self.assertNotIn("final", commitfests)
140+
141+
def test_response_structure(self):
142+
"""Test that response has expected structure."""
143+
response = self.client.get("/api/v1/commitfests/needs_ci")
144+
data = json.loads(response.content)
145+
146+
# Top-level structure
147+
self.assertIn("commitfests", data)
148+
self.assertIsInstance(data["commitfests"], dict)
149+
150+
# Check that commitfest objects have expected fields
151+
commitfests = data["commitfests"]
152+
for key, cf_data in commitfests.items():
153+
if cf_data: # Some keys might have null values
154+
self.assertIsInstance(cf_data, dict)
155+
# Basic fields that should be present
156+
self.assertIn("name", cf_data)

0 commit comments

Comments
 (0)