Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: 新增所有端點可訪問的測試 #36

Merged
merged 6 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/smokeshow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Generate Coverage

on:
workflow_run:
workflows: [Test]
types: [completed]

permissions:
statuses: write

jobs:
Context:
runs-on: ubuntu-latest

steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"

Smokeshow:
if: ${{ github.event.workflow_run.event == 'push' && github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest

steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/setup-python@v4
with:
python-version: '3.11'

- run: pip install smokeshow

- uses: dawidd6/[email protected]
with:
workflow: tests.yml
commit: ${{ github.event.workflow_run.head_sha }}

- run: smokeshow upload coverage
env:
SMOKESHOW_GITHUB_STATUS_DESCRIPTION: Coverage {coverage-percentage}
SMOKESHOW_GITHUB_COVERAGE_THRESHOLD: 85
SMOKESHOW_GITHUB_CONTEXT: Coverage
SMOKESHOW_GITHUB_PR_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
SMOKESHOW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
46 changes: 46 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# test workflow from https://github.com/tiangolo/fastapi/blob/master/.github/workflows/test.yml
name: Test

on:
push:
branches:
- main
pull_request:
types:
- opened
- synchronize

jobs:
Test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11"]
fail-fast: true
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- uses: actions/cache@v3
id: cache
with:
path: ${{ env.pythonLocation }}
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('requirements-tests.txt') }}-test-v06
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: |
pip install -r requirements.txt
pip install -r requirements-tests.txt
- name: Test
run: python -m pytest -n auto tests --cov=. --cov-report=html:coverage --cov-fail-under=85
- name: Store coverage files
uses: actions/upload-artifact@v3
with:
name: coverage
path: coverage
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# NTHU-Data-API
[![CodeFactor](https://www.codefactor.io/repository/github/nthu-sa/nthu-data-api/badge)](https://www.codefactor.io/repository/github/nthu-sa/nthu-data-api) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![CodeFactor](https://www.codefactor.io/repository/github/nthu-sa/nthu-data-api/badge)](https://www.codefactor.io/repository/github/nthu-sa/nthu-data-api) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Smokeshow coverage](https://coverage-badge.samuelcolvin.workers.dev/NTHU-SA/NTHU-Data-API.svg)](https://coverage-badge.samuelcolvin.workers.dev/redirect/NTHU-SA/NTHU-Data-API)
## Introduction
This is a project for NTHU students to get data from NTHU website.

Expand Down
5 changes: 5 additions & 0 deletions requirements-tests.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Tests
pytest==7.4.3
pytest-xdist==3.4.0
pytest-cov==4.1.0
httpx==0.25.1
11 changes: 6 additions & 5 deletions src/api/models/buses.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,13 +306,14 @@ def _find_stop_from_str(self, stop_str: str) -> Optional[Stop]:
def _route_selector(
self, dep_stop: str, line: str, from_gen_2: bool = False
) -> Route:
# 這裡不用 match 的原因是因為資料中有些會多空格
# 清理資料,爬蟲抓下來的資料有些會多空格
(dep_stop, line) = map(str.strip, [dep_stop, line])
# 下山
stops_lines_map = {
("台積", "red", True): red_M5_M2,
("台積", "red", False): red_M5_M1,
("台積", "green", True): green_M5_M2,
("台積", "green", False): green_M5_M1,
("台積館", "red", True): red_M5_M2,
("台積館", "red", False): red_M5_M1,
("台積館", "green", True): green_M5_M2,
("台積館", "green", False): green_M5_M1,
("校門", "red"): red_M1_M5,
("綜二", "red"): red_M2_M5,
("校門", "green"): green_M1_M5,
Expand Down
6 changes: 3 additions & 3 deletions src/api/routers/libraries.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ def get_library_rss_data(


@router.get(
"/openinghours/{libaray_name}", response_model=schemas.resources.LibraryOpeningHour
"/openinghours/{library_name}", response_model=schemas.resources.LibraryOpeningHour
)
def get_library_opening_hours(
libaray_name: schemas.resources.LibraryName = Path(
library_name: schemas.resources.LibraryName = Path(
..., description="圖書館代號:總圖(mainlib)、人社圖書館(hslib)、南大圖書館(nandalib)"
)
):
"""
取得指定圖書館的開放時間。
"""
return library_scraper.get_opening_hours(libaray_name)
return library_scraper.get_opening_hours(library_name)


@router.get("/goods", response_model=schemas.resources.LibraryNumberOfGoods)
Expand Down
4 changes: 2 additions & 2 deletions src/utils/cached_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def get(url: str, cache=True, update=False, auto_headers=True, **kwargs) -> str:
else:
headers = None
url = validate_url(url)
response = requests.get(url, headers, **kwargs)
response = requests.get(url, headers, timeout=10, **kwargs)
status_code = response.status_code
if status_code != 200:
raise HTTPException(status_code, f"Request error: {status_code}")
Expand All @@ -86,7 +86,7 @@ def post(url: str, cache=True, update=False, **kwargs) -> str:
del ttl_cache[url]
if cache and url in ttl_cache:
return ttl_cache[url]
response = requests.post(url, **kwargs)
response = requests.post(url, timeout=10, **kwargs)
status_code = response.status_code
if status_code != 200:
raise HTTPException(status_code, f"Request error: {status_code}")
Expand Down
48 changes: 48 additions & 0 deletions tests/test_buses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import pytest
from fastapi.testclient import TestClient

from src import app
from src.api import schemas

client = TestClient(app)


@pytest.mark.parametrize(
"url, status_code",
[
("/buses/main", 200),
("/buses/main/info/toward_main_gate", 200),
("/buses/main/info/toward_tsmc_building", 200),
("/buses/main/schedules/weekday/toward_main_gate", 200),
("/buses/main/schedules/weekday/toward_tsmc_building", 200),
("/buses/main/schedules/weekend/toward_main_gate", 200),
("/buses/main/schedules/weekend/toward_tsmc_building", 200),
("/buses/nanda", 200),
("/buses/nanda/info/toward_main_campus", 200),
("/buses/nanda/info/toward_south_campus", 200),
("/buses/nanda/schedules/weekday/toward_main_campus", 200),
("/buses/nanda/schedules/weekday/toward_south_campus", 200),
("/buses/nanda/schedules/weekend/toward_main_campus", 200),
("/buses/nanda/schedules/weekend/toward_south_campus", 200),
],
)
def test_buses_endpoints(url, status_code):
response = client.get(url=url)
assert response.status_code == status_code


@pytest.mark.parametrize("stop_name", [_.value for _ in schemas.buses.StopsName])
@pytest.mark.parametrize("bus_type", [_.value for _ in schemas.buses.BusType])
@pytest.mark.parametrize("day", [_.value for _ in schemas.buses.BusDay])
@pytest.mark.parametrize("direction", [_.value for _ in schemas.buses.BusDirection])
def test_buses_stops(stop_name, bus_type, day, direction):
response = client.get(url=f"/buses/stops/{stop_name}/{bus_type}/{day}/{direction}")
assert response.status_code == 200


@pytest.mark.parametrize("bus_type", [_.value for _ in schemas.buses.BusType])
@pytest.mark.parametrize("day", [_.value for _ in schemas.buses.BusDay])
@pytest.mark.parametrize("direction", [_.value for _ in schemas.buses.BusDirection])
def test_buses_detailed(bus_type, day, direction):
response = client.get(url=f"/buses/detailed/{bus_type}/{day}/{direction}")
assert response.status_code == 200
10 changes: 10 additions & 0 deletions tests/test_careers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from fastapi.testclient import TestClient

from src import app

client = TestClient(app)


def test_careers():
response = client.get(url="/resources/careers/bulletin/recruitment")
assert response.status_code == 200
36 changes: 36 additions & 0 deletions tests/test_contacts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import pytest
from fastapi.testclient import TestClient

from src import app

client = TestClient(app)
id_list = [
"7e00db83-b407-4320-af55-0a1b1f5734ad",
"8dfa4f30-2339-4ec2-aee9-0da58e78fdde",
"ed3ac738-8102-43fb-844c-3abbd5f493d8",
"4955571d-ec87-4c8f-bc39-c3b39142558c",
]
name_list = ["清華學院", "理學院", "主計"]


def test_contacts():
response = client.get(url=f"/contacts")
assert response.status_code == 200


@pytest.mark.parametrize("id", id_list)
def test_contacts_id(id):
response = client.get(url=f"/contacts/{id}")
assert response.status_code == 200


@pytest.mark.parametrize("name", name_list)
def test_contacts_name(name):
response = client.get(url=f"/contacts/searches/{name}")
assert response.status_code == 200


@pytest.mark.parametrize("name", name_list)
def test_contacts_name_post(name):
response = client.post(url="/contacts/searches/", json={"name": name})
assert response.status_code == 200
62 changes: 62 additions & 0 deletions tests/test_courses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import pytest
from fastapi.testclient import TestClient

from src import app
from src.api import schemas

client = TestClient(app)


@pytest.mark.parametrize(
"url, status_code",
[
("/courses/", 200),
("/courses/fields/info", 200),
("/courses/lists/16weeks", 200),
("/courses/lists/microcredits", 200),
("/courses/lists/xclass", 200),
],
)
def test_courses_endpoints(url, status_code):
response = client.get(url=url)
assert response.status_code == status_code


@pytest.mark.parametrize(
"field_name", [_.value for _ in schemas.courses.CourseFieldName]
)
def test_courses_fields(field_name):
response = client.get(url=f"/courses/fields/{field_name}")
assert response.status_code == 200


@pytest.mark.parametrize(
"field_name", [_.value for _ in schemas.courses.CourseFieldName]
)
@pytest.mark.parametrize("value", ["testing"])
def test_courses_fields(field_name, value):
response = client.get(url=f"/courses/fields/{field_name}/{value}")
assert response.status_code == 200


@pytest.mark.parametrize(
"field_name", [_.value for _ in schemas.courses.CourseFieldName]
)
@pytest.mark.parametrize("value", ["testing"])
def test_courses_search(field_name, value):
response = client.get(url=f"/courses/searches?field={field_name}&value={value}")
assert response.status_code == 200


@pytest.mark.parametrize("path", ["id", "classroom", "time", "teacher"])
@pytest.mark.parametrize("value", ["testing"])
def test_courses_search_extension(path, value):
response = client.get(url=f"/courses/searches/{path}/{value}")
assert response.status_code == 404


@pytest.mark.parametrize("path", ["credits"])
@pytest.mark.parametrize("op", ["gt", "lt", "gte", "lte"])
def test_courses_search_credits(path, op):
response = client.get(url=f"/courses/searches/{path}/3?op={op}")
assert response.status_code == 200
18 changes: 18 additions & 0 deletions tests/test_default.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import pytest
from fastapi.testclient import TestClient

from src import app

client = TestClient(app)


@pytest.mark.parametrize(
"url, status_code",
[
("/", 200),
("/ping", 200),
],
)
def test_default_endpoints(url, status_code):
response = client.get(url=url)
assert response.status_code == status_code
Loading