Skip to content

Commit ac74e19

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

File tree

3 files changed

+213
-0
lines changed

3 files changed

+213
-0
lines changed

.github/workflows/ci.yaml

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

0 commit comments

Comments
 (0)