From 8f7753bff75dc87dc332ba482673ac4c539091e5 Mon Sep 17 00:00:00 2001 From: Bruce Schultz Date: Wed, 13 Mar 2024 13:20:27 +0100 Subject: [PATCH] test(kong): begin writing tests for kong --- gateway/models/kong.py | 7 +------ gateway/routers/kong.py | 38 ++++++++++++++++++++++++++++++++++---- gateway/server.py | 2 +- tests/conftest.py | 35 ++++++++++++++++++++++++++++++++++- tests/constants.py | 3 +++ tests/test_kong.py | 39 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 112 insertions(+), 12 deletions(-) create mode 100644 tests/constants.py create mode 100644 tests/test_kong.py diff --git a/gateway/models/kong.py b/gateway/models/kong.py index 7183bbc..0ee6075 100644 --- a/gateway/models/kong.py +++ b/gateway/models/kong.py @@ -13,12 +13,6 @@ class DataStoreType(Enum): FHIR: str = "fhir" -class Services(BaseModel): - """Data store list response model.""" - data: list[Service] - offset: int | None = None - - class ServiceRequest(CreateServiceRequest): """Improved version of the CreateServiceRequest with better defaults.""" protocol: str | None = "http" @@ -27,6 +21,7 @@ class ServiceRequest(CreateServiceRequest): client_certificate: CreateServiceRequestClientCertificate | None = None tls_verify: bool | None = None ca_certificates: list[str] | None = None + enabled: bool = True class LinkDataStoreProject(BaseModel): diff --git a/gateway/routers/kong.py b/gateway/routers/kong.py index 7621ab8..1f128a0 100644 --- a/gateway/routers/kong.py +++ b/gateway/routers/kong.py @@ -9,9 +9,8 @@ from kong_admin_client.rest import ApiException from starlette import status -# from gateway.auth import idp_oauth2_scheme from gateway.conf import gateway_settings -from gateway.models.kong import Services, ServiceRequest, HttpMethodCode, ProtocolCode, LinkDataStoreProject, \ +from gateway.models.kong import ServiceRequest, HttpMethodCode, ProtocolCode, LinkDataStoreProject, \ Disconnect, LinkProjectAnalysis kong_router = APIRouter( @@ -24,7 +23,7 @@ kong_admin_url = gateway_settings.KONG_ADMIN_SERVICE_URL -@kong_router.get("/datastore", response_model=Services) +@kong_router.get("/datastore", response_model=ListRoute200Response, status_code=status.HTTP_200_OK) async def list_data_stores(): """List all available data stores.""" configuration = kong_admin_client.Configuration(host=kong_admin_url) @@ -49,7 +48,7 @@ async def list_data_stores(): ) -@kong_router.get("/datastore/{project_name}", status_code=status.HTTP_200_OK, response_model=ListRoute200Response) +@kong_router.get("/datastore/{project_name}", response_model=ListRoute200Response, status_code=status.HTTP_200_OK) async def list_data_stores_by_project( project_name: Annotated[str, Path(description="Unique name of project.")] ): @@ -84,6 +83,37 @@ async def list_data_stores_by_project( ) +@kong_router.delete("/datastore/{data_store_name}", status_code=status.HTTP_200_OK) +async def delete_data_store( + data_store_name: Annotated[str, Path(description="Unique name of the data store.")] +): + """List all the data stores connected to this project.""" + configuration = kong_admin_client.Configuration(host=kong_admin_url) + + try: + with kong_admin_client.ApiClient(configuration) as api_client: + api_instance = kong_admin_client.ServicesApi(api_client) + api_instance.delete_service(service_id_or_name=data_store_name) + + logger.info(f"Data store {data_store_name} deleted") + + return status.HTTP_200_OK + + except ApiException as e: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=str(e), + headers={"WWW-Authenticate": "Bearer"}, + ) + + except Exception as e: + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail=f"Service error: {e}", + headers={"WWW-Authenticate": "Bearer"}, + ) + + @kong_router.put("/datastore", response_model=Service, status_code=status.HTTP_201_CREATED) async def create_data_store(data: Annotated[ServiceRequest, Body( description="Required information for creating a new data store.", diff --git a/gateway/server.py b/gateway/server.py index 3391555..9832e8d 100644 --- a/gateway/server.py +++ b/gateway/server.py @@ -80,4 +80,4 @@ def get_health() -> HealthCheck: ) if __name__ == "__main__": - uvicorn.run("server:app", host="127.0.0.1", port=8081, reload=True) + uvicorn.run("server:app", host="127.0.0.1", port=8081) diff --git a/tests/conftest.py b/tests/conftest.py index 8f9933b..615c882 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,7 +10,8 @@ from gateway.conf import gateway_settings from gateway.server import app -from tests.pseudo_auth import get_oid_test_jwk, BearerAuth +from tests.constants import KONG_TEST_DS, KONG_TEST_PROJECT +from tests.pseudo_auth import get_oid_test_jwk, BearerAuth, fakeauth @pytest.fixture(scope="package") @@ -57,3 +58,35 @@ def hub_token() -> BearerAuth: assert token return BearerAuth(token) + + +@pytest.fixture(scope="module") +def setup_kong(test_client): + """Setup Kong instance with test data.""" + test_datastore = { + "name": KONG_TEST_DS, + "protocol": "http", + "host": "server.fire.ly", + "port": 80, + "path": "/mydefinedpath", + } + test_project_link = { + "data_store_id": KONG_TEST_DS, + "project_id": KONG_TEST_PROJECT, + "methods": [ + "GET", + "POST", + "PUT", + "DELETE" + ], + "ds_type": "fhir", + "protocols": ["http"], + } + + test_client.put("/datastore", auth=fakeauth, json=test_datastore) + test_client.put("/datastore/project", auth=fakeauth, json=test_project_link) + + yield + + test_client.put(f"/disconnect/{KONG_TEST_PROJECT}", auth=fakeauth) + test_client.delete(f"/datastore/{KONG_TEST_DS}", auth=fakeauth) diff --git a/tests/constants.py b/tests/constants.py new file mode 100644 index 0000000..9de8921 --- /dev/null +++ b/tests/constants.py @@ -0,0 +1,3 @@ +"""String constants for tests.""" +KONG_TEST_DS = "unitTestDataStore" +KONG_TEST_PROJECT = "unitTestProject" diff --git a/tests/test_kong.py b/tests/test_kong.py new file mode 100644 index 0000000..cc8d0b0 --- /dev/null +++ b/tests/test_kong.py @@ -0,0 +1,39 @@ +"""Unit tests for the kong endpoints.""" +from starlette import status + +from tests.constants import KONG_TEST_DS, KONG_TEST_PROJECT +from tests.pseudo_auth import fakeauth + + +class TestKong: + """Kong EP tests. Dependent on having a running instance of Kong and admin URL defined in ENV.""" + + def test_list_data_stores(self, test_client, setup_kong): + """Test the list_data_stores method.""" + r = test_client.get("/datastore", auth=fakeauth) + assert r.status_code == status.HTTP_200_OK + + json_data = r.json() + data = json_data["data"] + + assert len(data) # should not be none + assert isinstance(data, list) + assert len(data) > 0 # minimum 1 + + data_store_names = [ds["name"] for ds in data] + assert KONG_TEST_DS in data_store_names + + def test_list_data_stores_by_project(self, test_client, setup_kong): + """Test the list_data_stores_by_project method.""" + r = test_client.get(f"/datastore/{KONG_TEST_PROJECT}", auth=fakeauth) + assert r.status_code == status.HTTP_200_OK + + json_data = r.json() + data = json_data["data"] + assert len(data) == 1 # should only be one named this + + data_store = data[0] + + assert data_store["protocols"] == ["http"] + assert data_store["name"] == KONG_TEST_DS + assert data_store["methods"] == ["GET", "POST", "PUT", "DELETE"]