From e71efb14c7212f5080e748e6af81d7f468f74d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Ho=C5=A1ek?= Date: Fri, 17 Jan 2025 22:30:17 +0100 Subject: [PATCH] [RSPEED-427] Add systems endpoint (#14) Add endpoint for returning RHEL systems start/end dates --- app/data/systems.py | 40 ++++++++++++++ app/main.py | 2 + app/tests/lifecycle/__init__.py | 0 app/tests/lifecycle/systems/__init__.py | 0 app/tests/lifecycle/systems/test_systems.py | 59 +++++++++++++++++++++ app/v1/lifecycle/__init__.py | 0 app/v1/lifecycle/router.py | 7 +++ app/v1/lifecycle/systems/__init__.py | 0 app/v1/lifecycle/systems/endpoints.py | 40 ++++++++++++++ 9 files changed, 148 insertions(+) create mode 100644 app/data/systems.py create mode 100644 app/tests/lifecycle/__init__.py create mode 100644 app/tests/lifecycle/systems/__init__.py create mode 100644 app/tests/lifecycle/systems/test_systems.py create mode 100644 app/v1/lifecycle/__init__.py create mode 100644 app/v1/lifecycle/router.py create mode 100644 app/v1/lifecycle/systems/__init__.py create mode 100644 app/v1/lifecycle/systems/endpoints.py diff --git a/app/data/systems.py b/app/data/systems.py new file mode 100644 index 0000000..1d47c81 --- /dev/null +++ b/app/data/systems.py @@ -0,0 +1,40 @@ +from datetime import date + +OS_DATA_MOCKED = [ + { + "name": "RHEL", + "major": 9, + "minor": 2, + "release_date": date(2023, 5, 1), + "retirement_date": date(2023, 11, 1), + "systems": 5, + "lifecycle_type": "mainline", + }, + { + "name": "RHEL", + "major": 8, + "minor": 3, + "release_date": date(2020, 11, 1), + "retirement_date": date(2021, 5, 1), + "systems": 50, + "lifecycle_type": "eus", + }, + { + "name": "RHEL", + "major": 8, + "minor": 7, + "release_date": date(2023, 5, 1), + "retirement_date": date(2023, 5, 1), + "systems": 12, + "lifecycle_type": "e4s", + }, + { + "name": "RHEL", + "major": 9, + "minor": 0, + "release_date": date(2022, 5, 18), + "retirement_date": date(2032, 5, 1), + "systems": 45, + "lifecycle_type": "mainline", + }, +] diff --git a/app/main.py b/app/main.py index 91516d2..45af24c 100644 --- a/app/main.py +++ b/app/main.py @@ -1,5 +1,6 @@ from fastapi import APIRouter, FastAPI +from app.v1.lifecycle.router import v1_router as lifecycle_v1_router from app.v1.released.endpoints import v1_router as released_v1_router from app.v1.upcoming.endpoints import v1_router as upcoming_v1_router @@ -12,6 +13,7 @@ # Include individual service routers under the main API router api_router.include_router(released_v1_router, prefix="/v1/release-notes", tags=["release-notes"]) api_router.include_router(upcoming_v1_router, prefix="/v1/upcoming-changes", tags=["upcoming-changes"]) +api_router.include_router(lifecycle_v1_router, prefix="/v1/lifecycle") # tag provided in app/v1/lifecycle/router.py @api_router.get("/v1/ping") diff --git a/app/tests/lifecycle/__init__.py b/app/tests/lifecycle/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/tests/lifecycle/systems/__init__.py b/app/tests/lifecycle/systems/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/tests/lifecycle/systems/test_systems.py b/app/tests/lifecycle/systems/test_systems.py new file mode 100644 index 0000000..017dd14 --- /dev/null +++ b/app/tests/lifecycle/systems/test_systems.py @@ -0,0 +1,59 @@ +import pytest +from fastapi.testclient import TestClient + +import app +from app.main import app as application + +client = TestClient(application) + + +@pytest.mark.parametrize( + ("source_data", "path", "response"), + ( + ( + [{"major": 8, "minor": 3, "data": "data"}, {"major": 8, "minor": 4, "data": "data"}], + "/8/3", + [{"major": 8, "minor": 3, "data": "data"}], + ), + ( + [{"major": 8, "minor": 3, "data": "data"}, {"major": 9, "minor": 0, "data": "data"}], + "/9/0", + [{"major": 9, "minor": 0, "data": "data"}], + ), + ([{"major": 8, "minor": 3, "data": "data"}, {"major": 9, "minor": 0, "data": "data"}], "/9/20", []), + ([], "/9/20", []), + ( + [ + {"major": 8, "minor": 3, "data": "data"}, + {"major": 9, "minor": 0, "data": "data"}, + {"major": 8, "minor": 7, "data": "data"}, + {"major": 9, "minor": 2, "data": "data"}, + ], + "/9", + [ + {"major": 9, "minor": 0, "data": "data"}, + {"major": 9, "minor": 2, "data": "data"}, + ], + ), + ( + [ + {"major": 8, "minor": 3, "data": "data"}, + {"major": 9, "minor": 0, "data": "data"}, + {"major": 8, "minor": 7, "data": "data"}, + {"major": 9, "minor": 2, "data": "data"}, + ], + "", + [ + {"major": 8, "minor": 3, "data": "data"}, + {"major": 8, "minor": 7, "data": "data"}, + {"major": 9, "minor": 0, "data": "data"}, + {"major": 9, "minor": 2, "data": "data"}, + ], + ), + ), +) +def test_system_specified(source_data, path, response, monkeypatch): + monkeypatch.setattr(app.v1.lifecycle.systems.endpoints, "OS_DATA_MOCKED", source_data) + + data = client.get(f"/api/digital-roadmap/v1/lifecycle/systems{path}") + assert data.json() == response diff --git a/app/v1/lifecycle/__init__.py b/app/v1/lifecycle/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/v1/lifecycle/router.py b/app/v1/lifecycle/router.py new file mode 100644 index 0000000..d0d85e5 --- /dev/null +++ b/app/v1/lifecycle/router.py @@ -0,0 +1,7 @@ +from fastapi import APIRouter + +from app.v1.lifecycle.systems.endpoints import v1_router as systems_v1_router + +v1_router = APIRouter() + +v1_router.include_router(systems_v1_router, tags=["lifecycle-systems"]) diff --git a/app/v1/lifecycle/systems/__init__.py b/app/v1/lifecycle/systems/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/v1/lifecycle/systems/endpoints.py b/app/v1/lifecycle/systems/endpoints.py new file mode 100644 index 0000000..a0e62d0 --- /dev/null +++ b/app/v1/lifecycle/systems/endpoints.py @@ -0,0 +1,40 @@ +from fastapi import APIRouter, Path + +from app.data.systems import OS_DATA_MOCKED + +v1_router = APIRouter() + + +@v1_router.get("/systems") +async def get_systems(): + systems = get_systems_data() + + return sorted(systems, key=lambda d: (d["major"], d["minor"])) + + +@v1_router.get("/systems/{major}") +async def get_systems_major(major: int = Path(..., description="Major version number")): + systems = get_systems_data(major) + + return sorted(systems, key=lambda d: (d["major"], d["minor"])) + + +@v1_router.get("/systems/{major}/{minor}") +async def get_systems_major_minor( + major: int = Path(..., description="Major version number"), + minor: int = Path(..., description="Minor version number"), +): + systems = get_systems_data(major, minor) + + return sorted(systems, key=lambda d: (d["major"], d["minor"])) + + +def get_systems_data(major=None, minor=None): + data = OS_DATA_MOCKED + + if major is not None: + data = [d for d in data if d["major"] == major] + if minor is not None: + data = [d for d in data if d["minor"] == minor] + + return data