Skip to content

Commit d3854b1

Browse files
authored
Merge pull request #85 from leozqin/unit-test
Add Unit Tests and Async-ify about and health check endpoints
2 parents 1ff7112 + 576182e commit d3854b1

22 files changed

+510
-79
lines changed

.coveragerc

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[run]
2+
source=app

.github/workflows/integration_test.yml .github/workflows/full_test.yml

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Integration Test
1+
name: Full Test
22
on:
33
workflow_call:
44
inputs:
@@ -14,16 +14,16 @@ on:
1414

1515
env:
1616
IMAGE_NAME: precis
17-
#
17+
1818
jobs:
19-
integration_test:
19+
test:
2020
runs-on: ubuntu-latest
2121
permissions:
2222
contents: read
2323
env:
2424
PRECIS_STORAGE_HANDLER: ${{ inputs.storage_handler }}
2525
CONFIG_DIR: ${{ github.workspace }}/tests/integration/config
26-
DATA_DIR: ${{ github.workspace }}
26+
DATA_DIR: ${{ github.workspace }}/data
2727
RSS_BASE_URL: http://localhost:8000
2828
steps:
2929
- name: checkout
@@ -33,7 +33,12 @@ jobs:
3333
pip install uv && uv venv
3434
source .venv/bin/activate
3535
make install-ci
36-
- name: test
36+
- name: unit_test
37+
run: |
38+
source .venv/bin/activate
39+
pytest -vvv -cov
40+
make clean
41+
- name: integration_test
3742
run: |
3843
source .venv/bin/activate
3944
mv tests/integration/config/settings-${{ inputs.content_retrieval_handler }}-${{ inputs.llm_handler}}.yml tests/integration/config/settings.yml

.github/workflows/test.yml

+12-12
Original file line numberDiff line numberDiff line change
@@ -6,73 +6,73 @@ on:
66

77
jobs:
88
integration-test-tinydb-playwright-null:
9-
uses: ./.github/workflows/integration_test.yml
9+
uses: ./.github/workflows/full_test.yml
1010
with:
1111
storage_handler: tinydb
1212
content_retrieval_handler: playwright
1313
llm_handler: "null"
1414
integration-test-lmdb-playwright-null:
15-
uses: ./.github/workflows/integration_test.yml
15+
uses: ./.github/workflows/full_test.yml
1616
with:
1717
storage_handler: lmdb
1818
content_retrieval_handler: playwright
1919
llm_handler: "null"
2020
integration-test-hybrid-playwright-null:
21-
uses: ./.github/workflows/integration_test.yml
21+
uses: ./.github/workflows/full_test.yml
2222
with:
2323
storage_handler: hybrid
2424
content_retrieval_handler: playwright
2525
llm_handler: "null"
2626
integration-test-tinydb-requests-null:
27-
uses: ./.github/workflows/integration_test.yml
27+
uses: ./.github/workflows/full_test.yml
2828
with:
2929
storage_handler: tinydb
3030
content_retrieval_handler: requests
3131
llm_handler: "null"
3232
integration-test-lmdb-requests-null:
33-
uses: ./.github/workflows/integration_test.yml
33+
uses: ./.github/workflows/full_test.yml
3434
with:
3535
storage_handler: lmdb
3636
content_retrieval_handler: requests
3737
llm_handler: "null"
3838
integration-test-hybrid-requests-null:
39-
uses: ./.github/workflows/integration_test.yml
39+
uses: ./.github/workflows/full_test.yml
4040
with:
4141
storage_handler: hybrid
4242
content_retrieval_handler: requests
4343
llm_handler: "null"
4444
integration-test-tinydb-playwright-dummy:
45-
uses: ./.github/workflows/integration_test.yml
45+
uses: ./.github/workflows/full_test.yml
4646
with:
4747
storage_handler: tinydb
4848
content_retrieval_handler: playwright
4949
llm_handler: dummy
5050
integration-test-lmdb-playwright-dummy:
51-
uses: ./.github/workflows/integration_test.yml
51+
uses: ./.github/workflows/full_test.yml
5252
with:
5353
storage_handler: lmdb
5454
content_retrieval_handler: playwright
5555
llm_handler: dummy
5656
integration-test-hybrid-playwright-dummy:
57-
uses: ./.github/workflows/integration_test.yml
57+
uses: ./.github/workflows/full_test.yml
5858
with:
5959
storage_handler: hybrid
6060
content_retrieval_handler: playwright
6161
llm_handler: dummy
6262
integration-test-tinydb-requests-dummy:
63-
uses: ./.github/workflows/integration_test.yml
63+
uses: ./.github/workflows/full_test.yml
6464
with:
6565
storage_handler: tinydb
6666
content_retrieval_handler: requests
6767
llm_handler: dummy
6868
integration-test-lmdb-requests-dummy:
69-
uses: ./.github/workflows/integration_test.yml
69+
uses: ./.github/workflows/full_test.yml
7070
with:
7171
storage_handler: lmdb
7272
content_retrieval_handler: requests
7373
llm_handler: dummy
7474
integration-test-hybrid-requests-dummy:
75-
uses: ./.github/workflows/integration_test.yml
75+
uses: ./.github/workflows/full_test.yml
7676
with:
7777
storage_handler: hybrid
7878
content_retrieval_handler: requests

.pre-commit-config.yaml

+23-12
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,26 @@ repos:
55
- id: isort
66
name: isort (python)
77
args: ["--profile", "black"]
8-
- repo: https://github.com/pre-commit/pre-commit-hooks
9-
rev: v2.3.0
10-
hooks:
11-
- id: check-yaml
12-
- id: end-of-file-fixer
13-
- id: trailing-whitespace
14-
- id: check-added-large-files
15-
- id: detect-private-key
16-
- repo: https://github.com/psf/black
17-
rev: 22.10.0
18-
hooks:
19-
- id: black
8+
- repo: https://github.com/pre-commit/pre-commit-hooks
9+
rev: v2.3.0
10+
hooks:
11+
- id: check-yaml
12+
- id: end-of-file-fixer
13+
- id: trailing-whitespace
14+
- id: check-added-large-files
15+
- id: detect-private-key
16+
- repo: local
17+
hooks:
18+
# Run the linter.
19+
- id: ruff
20+
name: lint
21+
language: python
22+
types_or: [python, pyi, jupyter]
23+
entry: ruff check --force-exclude
24+
args: [ --fix ]
25+
# Run the formatter.
26+
- id: ruff-format
27+
name: format
28+
language: python
29+
types_or: [python, pyi, jupyter]
30+
entry: ruff format --force-exclude

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ build:
3333

3434
.PHONY: clean
3535
clean:
36-
rm *.mdb db.json
36+
rm -r ${DATA_DIR}
3737

3838
.PHONY: test
3939
test:

app/app.py

+2-20
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,9 @@ async def favicon():
7272

7373
@app.get("/", response_class=HTMLResponse)
7474
async def root(request: Request):
75-
7675
settings = await bk.get_settings()
7776

7877
if settings.get("finished_onboarding"):
79-
8078
return templates.TemplateResponse(
8179
"index.html",
8280
{
@@ -87,7 +85,6 @@ async def root(request: Request):
8785
)
8886

8987
else:
90-
9188
return RedirectResponse("/onboarding/")
9289

9390

@@ -99,7 +96,7 @@ async def about(
9996
"settings": await bk.get_settings(),
10097
"update_status": update_status,
10198
"update_exception": update_exception,
102-
**bk.about(),
99+
**await bk.about(),
103100
}
104101

105102
if request.headers.get("accept") == JSON:
@@ -112,8 +109,7 @@ async def about(
112109

113110
@app.get("/health", response_model=HealthCheck)
114111
async def health_check(request: Request) -> HealthCheck:
115-
116-
return bk.health_check()
112+
return await bk.health_check()
117113

118114

119115
@app.get("/onboarding/")
@@ -235,7 +231,6 @@ async def handler_settings(
235231
async def update_handler(
236232
handler: Annotated[str, Form()], config: Annotated[str, Form()], request: Request
237233
):
238-
239234
try:
240235
await bk.update_handler(handler=handler, config=config)
241236

@@ -246,7 +241,6 @@ async def update_handler(
246241
status_code=status.HTTP_303_SEE_OTHER,
247242
)
248243
except Exception as e:
249-
250244
return RedirectResponse(
251245
request.url_for("handler_settings", handler=handler).include_query_params(
252246
update_exception=e
@@ -257,7 +251,6 @@ async def update_handler(
257251

258252
@app.get("/api/refresh_feed/{feed_id}", status_code=status.HTTP_200_OK)
259253
async def refresh_feed(feed_id: str, request: Request):
260-
261254
await rss.check_feed_by_id(id=feed_id)
262255

263256
return RedirectResponse(
@@ -270,7 +263,6 @@ async def refresh_feed(feed_id: str, request: Request):
270263

271264
@app.get("/api/delete_feed/{feed_id}", status_code=status.HTTP_200_OK)
272265
async def delete_feed(feed_id: str, request: Request):
273-
274266
await bk.delete_feed(feed_id=feed_id)
275267

276268
return RedirectResponse(
@@ -315,7 +307,6 @@ async def update_settings(
315307
status_code=status.HTTP_303_SEE_OTHER,
316308
)
317309
except Exception as e:
318-
319310
return RedirectResponse(
320311
request.url_for("settings").include_query_params(update_exception=e),
321312
status_code=status.HTTP_303_SEE_OTHER,
@@ -371,23 +362,20 @@ async def update_feed(
371362

372363
@app.get("/api/export_opml/", status_code=status.HTTP_200_OK)
373364
async def export_opml(request: Request):
374-
375365
write_path, file_name = await rss.feeds_to_opml()
376366

377367
return FileResponse(path=write_path, filename=file_name)
378368

379369

380370
@app.get("/api/backup/", status_code=status.HTTP_200_OK)
381371
async def backup(request: Request):
382-
383372
write_path, file_name = await rss.backup()
384373

385374
return FileResponse(path=write_path, filename=file_name)
386375

387376

388377
@app.post("/api/restore/", status_code=status.HTTP_200_OK)
389378
async def restore(request: Request, file: UploadFile):
390-
391379
try:
392380
await rss.restore(file=file.file)
393381

@@ -404,7 +392,6 @@ async def restore(request: Request, file: UploadFile):
404392

405393
@app.post("/api/import_opml/", status_code=status.HTTP_200_OK)
406394
async def import_opml(request: Request, file: UploadFile):
407-
408395
try:
409396
await rss.opml_to_feeds(file=file.file)
410397

@@ -413,7 +400,6 @@ async def import_opml(request: Request, file: UploadFile):
413400
status_code=status.HTTP_303_SEE_OTHER,
414401
)
415402
except Exception as e:
416-
417403
return RedirectResponse(
418404
request.url_for("feeds").include_query_params(update_exception=e),
419405
status_code=status.HTTP_303_SEE_OTHER,
@@ -424,7 +410,6 @@ async def import_opml(request: Request, file: UploadFile):
424410
async def feeds(
425411
request: Request, update_status: bool = False, update_exception: str = None
426412
):
427-
428413
return templates.TemplateResponse(
429414
"feeds.html",
430415
{
@@ -477,13 +462,11 @@ async def new_feed(request: Request, update_exception: str = None):
477462

478463
@app.get("/util/list-feeds", status_code=status.HTTP_200_OK)
479464
async def list_feeds(request: Request) -> Sequence[Mapping]:
480-
481465
return bk.list_feeds()
482466

483467

484468
@app.get("/util/list-feed-entries", status_code=status.HTTP_200_OK)
485469
async def list_feed_entries(request: Request) -> Sequence[Mapping]:
486-
487470
all_feeds = bk.list_feeds()
488471

489472
entries = [list(bk.list_entries(feed["id"])) for feed in all_feeds]
@@ -493,7 +476,6 @@ async def list_feed_entries(request: Request) -> Sequence[Mapping]:
493476

494477
@app.get("/util/list-handlers", status_code=status.HTTP_200_OK)
495478
async def list_handlers(request: Request) -> Sequence[Mapping]:
496-
497479
handlers = bk.get_handlers()
498480

499481
# config might have secrets so we only return if its configured

0 commit comments

Comments
 (0)