Skip to content

Commit 71cd74d

Browse files
authored
test hygiene: null-deref guards in 2 endpoints, drop 2 dead schema fields, add CONTRIBUTING.md (#114)
1 parent 43ea98e commit 71cd74d

7 files changed

Lines changed: 29 additions & 7 deletions

File tree

CONTRIBUTING.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Contributing
2+
3+
## Prod-first principle
4+
5+
When prod code and the test suite disagree, the default assumption is **prod is the spec, tests are not**.
6+
7+
In practice:
8+
9+
1. **Don't modify prod to fit the test suite.** Follow good practice in prod code. If a test depends on prod doing something it shouldn't (e.g. the test expects a free-coin grant that prod no longer issues), the test is wrong — fix the test, not prod.
10+
11+
2. **A prod change that breaks a test is not automatically a regression.** Analyze before reacting:
12+
- Does the test exercise behavior the spec actually requires?
13+
- Or was the test written against the old shape of prod code that no longer exists?
14+
15+
If the latter, rewrite or delete the test. Old tests are not contracts.
16+
17+
This shapes how we land refactors: a refactor PR that rewrites or deletes affected tests is healthy. A refactor PR that leaves prod uglier to keep old tests green is not.

chafan_core/app/api/api_v1/endpoints/answers.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ def bump_views_counter(
168168
cached_layer: CachedLayer = Depends(deps.get_cached_layer),
169169
) -> Any:
170170
answer = crud.answer.get_by_uuid(cached_layer.get_db(), uuid=uuid)
171+
if answer is None:
172+
raise HTTPException_(
173+
status_code=400,
174+
detail="The answer doesn't exist in the system.",
175+
)
171176
view_counters.add_view_async(cached_layer, "answer", answer.id)
172177
return schemas.GenericResponse()
173178

chafan_core/app/api/api_v1/endpoints/questions.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ def get_question(
9090
Get question in one of current_user's belonging sites.
9191
"""
9292
question = cached_layer.get_question_by_uuid(uuid)
93+
if question is None:
94+
raise HTTPException_(
95+
status_code=404,
96+
detail="The question doesn't exist in the system.",
97+
)
9398
if question.is_hidden:
9499
raise HTTPException_(
95100
status_code=403,

chafan_core/app/cached_layer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ def get_question_model_http(self, uuid: str) -> models.Question:
656656
)
657657
return question
658658

659-
def get_question_by_uuid(self, uuid: str, current_user_id:Optional[int]=None) -> models.Question:
659+
def get_question_by_uuid(self, uuid: str, current_user_id:Optional[int]=None) -> Optional[models.Question]:
660660
question = crud.question.get_by_uuid(self.get_db(), uuid=uuid)
661661
if question is None:
662662
return None

chafan_core/app/schemas/article_archive.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
import datetime
2-
from typing import List
32

43
from pydantic import BaseModel
54

65
from chafan_core.app.schemas.richtext import RichText
7-
from chafan_core.app.schemas.topic import Topic
86
from chafan_core.utils.constants import editor_T
97

108

119
class ArticleArchiveInDB(BaseModel):
1210
id: int
1311
title: str
14-
topics: List[Topic] = []
1512
created_at: datetime.datetime
1613

1714
# TODO: deprecate

chafan_core/app/schemas/user.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ class UserInDBBase(UserBase):
115115
about: Optional[str] = None
116116
created_at: datetime.datetime
117117
residency_topics: List[Topic]
118-
profession_topic: Optional[Topic] = None
119118
remaining_coins: int
120119
personal_introduction: Optional[str] = None
121120
github_username: Optional[str] = None

chafan_core/tests/app/api/api_v1/test_questions.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ def test_get_question_success(
182182
assert db_question.uuid == response_data["uuid"]
183183

184184

185-
@pytest.mark.skip(reason="TODO: get_question endpoint doesn't handle None question before accessing is_hidden")
186185
def test_get_question_nonexistent(
187186
client: TestClient,
188187
db: Session,
@@ -193,7 +192,7 @@ def test_get_question_nonexistent(
193192
f"{settings.API_V1_STR}/questions/invalid-uuid",
194193
headers=normal_user_token_headers,
195194
)
196-
assert r.status_code == 400
195+
assert r.status_code == 404
197196

198197
# Verify it doesn't exist in database
199198
db_question = crud.question.get_by_uuid(db, uuid="invalid-uuid")

0 commit comments

Comments
 (0)