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

DM-44386: Test every page endpoint for loading success #206

Merged
merged 5 commits into from
Sep 3, 2024
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
16 changes: 7 additions & 9 deletions python/lsst/ts/rubintv/handlers/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
from lsst.ts.rubintv.background.historicaldata import HistoricalPoller
from lsst.ts.rubintv.config import rubintv_logger
from lsst.ts.rubintv.handlers.handlers_helpers import (
date_validation,
get_camera_current_data,
get_camera_events_for_date,
get_current_night_report_payload,
)
from lsst.ts.rubintv.models.models import Camera, Event, Location, NightReport
from lsst.ts.rubintv.models.models_helpers import date_str_to_date, find_first
from lsst.ts.rubintv.models.models_helpers import find_first

api_router = APIRouter()
"""FastAPI router for all external handlers."""
Expand Down Expand Up @@ -109,10 +110,9 @@ async def get_camera_events_for_date_api(
location_name: str, camera_name: str, date_str: str, request: Request
) -> dict:
location, camera = await get_location_camera(location_name, camera_name, request)
try:
day_obs = date_str_to_date(date_str)
except ValueError:
raise HTTPException(status_code=404, detail="Invalid date.")

day_obs = date_validation(date_str)

data = await get_camera_events_for_date(location, camera, day_obs, request)
if data:
channel_data, per_day, metadata, nr_exists = data
Expand Down Expand Up @@ -200,10 +200,8 @@ async def get_night_report_for_date(
location_name: str, camera_name: str, date_str: str, request: Request
) -> NightReport:
location, camera = await get_location_camera(location_name, camera_name, request)
try:
day_obs = date_str_to_date(date_str)
except ValueError:
raise HTTPException(status_code=404, detail="Invalid date.")

day_obs = date_validation(date_str)

historical: HistoricalPoller = request.app.state.historical
if await historical.is_busy():
Expand Down
9 changes: 9 additions & 0 deletions python/lsst/ts/rubintv/handlers/handlers_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
NightReport,
get_current_day_obs,
)
from lsst.ts.rubintv.models.models_helpers import date_str_to_date
from starlette.requests import HTTPConnection

logger = rubintv_logger()
Expand Down Expand Up @@ -131,3 +132,11 @@ async def get_prev_next_event(
raise HTTPException(423, "Historical data is being processed")
nxt, prv = await hp.get_next_prev_event(location, camera, event)
return {"next": nxt, "prev": prv}


def date_validation(date_str: str) -> date:
try:
day_obs = date_str_to_date(date_str)
except ValueError:
raise HTTPException(status_code=404, detail="Invalid date.")
return day_obs
16 changes: 7 additions & 9 deletions python/lsst/ts/rubintv/handlers/pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
get_specific_channel_event,
)
from lsst.ts.rubintv.handlers.handlers_helpers import (
date_validation,
get_camera_calendar,
get_camera_current_data,
get_camera_events_for_date,
Expand All @@ -28,7 +29,7 @@
to_dict,
)
from lsst.ts.rubintv.models.models import Channel, Event, Location, NightReport
from lsst.ts.rubintv.models.models_helpers import date_str_to_date, find_first
from lsst.ts.rubintv.models.models_helpers import find_first
from lsst.ts.rubintv.templates_init import get_templates

__all__ = ["get_home", "pages_router", "templates"]
Expand Down Expand Up @@ -162,10 +163,9 @@ async def get_camera_for_date_page(
location, camera = await get_location_camera(location_name, camera_name, request)
if not camera.online:
raise HTTPException(404, "Camera not online.")
try:
day_obs = date_str_to_date(date_str)
except ValueError:
raise HTTPException(status_code=404, detail="Invalid date.")

day_obs = date_validation(date_str)

historical_busy = False
nr_exists = False
metadata: dict = {}
Expand Down Expand Up @@ -326,10 +326,8 @@ async def get_historical_night_report_page(
request: Request,
) -> Response:
location, camera = await get_location_camera(location_name, camera_name, request)
try:
day_obs = date_str_to_date(date_str)
except ValueError:
raise HTTPException(status_code=404, detail="Invalid date.")

day_obs = date_validation(date_str)

night_report: NightReport
night_report, historical_busy = await try_historical_call(
Expand Down
98 changes: 93 additions & 5 deletions tests/handlers/external_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@
from fastapi import FastAPI
from httpx import AsyncClient
from lsst.ts.rubintv.background.currentpoller import CurrentPoller
from lsst.ts.rubintv.models.models import Location
from lsst.ts.rubintv.background.historicaldata import HistoricalPoller
from lsst.ts.rubintv.config import config
from lsst.ts.rubintv.models.models import Camera, Location, get_current_day_obs
from lsst.ts.rubintv.models.models_helpers import find_first
from lsst.ts.rubintv.models.models_init import ModelsInitiator

from ..mockdata import RubinDataMocker

m = ModelsInitiator()
app_name = config.name
day_obs = get_current_day_obs().isoformat()


@pytest.mark.asyncio
Expand All @@ -25,7 +29,7 @@ async def test_get_home(
) -> None:
"""Test that home page has links to every location"""
client, app, mocker = mocked_client
response = await client.get("/rubintv/")
response = await client.get(f"/{app_name}/")
html = await response.aread()
parsed = BeautifulSoup(html, "html.parser")
locations = m.locations
Expand All @@ -51,7 +55,7 @@ async def test_get_location(

groups = location.camera_groups.values()
camera_names = list(chain(*groups))
response = await client.get(f"/rubintv/{location_name}")
response = await client.get(f"/{app_name}/{location_name}")
html = await response.aread()

parsed = BeautifulSoup(html, "html.parser")
Expand All @@ -78,11 +82,12 @@ async def test_current_channels(
loc_cam = f"{location.name}/{camera.name}"
for seq_chan in camera.seq_channels():
url = (
f"/rubintv/{location.name}/{camera.name}"
f"/{app_name}/{location.name}/{camera.name}"
f"/current/{seq_chan.name}"
)
response = await client.get(url)
assert response.status_code == 200
assert response.is_success

html = await response.aread()
parsed = BeautifulSoup(html, "html.parser")
if mocker.empty_channel[loc_cam] == seq_chan.name:
Expand All @@ -91,3 +96,86 @@ async def test_current_channels(
else:
assert parsed.select(".event-info")
assert not parsed.select(".event-error")


@pytest.mark.asyncio
async def test_all_endpoints(
mocked_client: tuple[AsyncClient, FastAPI, RubinDataMocker]
) -> None:

client, app, mocker = mocked_client

locations = [loc.name for loc in m.locations]
summit: Location = find_first(m.locations, "name", "summit-usdf")
assert isinstance(summit, Location)

all_cams = [f"{summit.name}/{cam.name}" for cam in summit.cameras]
online_cams = [f"{summit.name}/{cam.name}" for cam in summit.cameras if cam.online]
camera_historical = [f"{cam}/historical" for cam in online_cams]
camera_dates = [f"{cam}/date/{day_obs}" for cam in online_cams]
nr_current = [f"{cam}/night_report" for cam in online_cams]
nr_dates = [f"{cam}/night_report/{day_obs}" for cam in online_cams]

auxtel: Camera = find_first(summit.cameras, "name", "auxtel")
assert isinstance(auxtel, Camera)

channels = [
f"{summit.name}/{auxtel.name}/current/{chan.name}"
for chan in auxtel.seq_channels()
]

page_rel_urls = [
"",
"admin",
*all_cams,
*locations,
*camera_dates,
*camera_historical,
*nr_current,
*nr_dates,
*channels,
]

hp: HistoricalPoller = app.state.historical
while hp._have_downloaded is False:
await asyncio.sleep(0.1)

for url_frag in page_rel_urls:
url = f"/{app_name}/{url_frag}"
res = await client.get(url)
assert res.is_success


@pytest.mark.asyncio
async def test_request_invalid_dates(
mocked_client: tuple[AsyncClient, FastAPI, RubinDataMocker]
) -> None:

client, app, mocker = mocked_client

summit: Location = find_first(m.locations, "name", "summit-usdf")
assert isinstance(summit, Location)

online_cams = [f"{summit.name}/{cam.name}" for cam in summit.cameras if cam.online]
cam_date_words = [f"{cam}/date/not-a-date" for cam in online_cams if cam]
cam_invalid_day = [f"{cam}/date/2000-49-10" for cam in online_cams if cam]
cam_invalid_month = [f"{cam}/date/2000-27-13" for cam in online_cams if cam]
cam_invalid_year = [f"{cam}/date/20001-27-12" for cam in online_cams if cam]
cam_empty_year = [f"{cam}/date/1969-01-01" for cam in online_cams if cam]

invalid_urls = [
*cam_date_words,
*cam_invalid_day,
*cam_invalid_month,
*cam_invalid_year,
]

for url_frag in invalid_urls:
url = f"/{app_name}/{url_frag}"
res = await client.get(url)
assert res.is_error

for url_frag in cam_empty_year:
url = f"/{app_name}/{url_frag}"
res = await client.get(url)
assert res.is_success