From 36526d97e8312ec3f59f445b8e3ccd903a3271f1 Mon Sep 17 00:00:00 2001 From: serramatutu Date: Tue, 18 Jun 2024 18:52:00 +0200 Subject: [PATCH] test(integration): add integration tests with a real server This commit adds integration tests that will check if the SDK works when talking to a real server. --- .changes/unreleased/Test-20240618-185102.yaml | 3 + .github/workflows/code-quality.yaml | 6 +- tests/api/graphql/test_protocol.py | 18 ------ tests/conftest.py | 46 +++++++++++++++- tests/integration/__init__.py | 0 tests/integration/test_gql.py | 55 +++++++++++++++++++ 6 files changed, 108 insertions(+), 20 deletions(-) create mode 100644 .changes/unreleased/Test-20240618-185102.yaml create mode 100644 tests/integration/__init__.py create mode 100644 tests/integration/test_gql.py diff --git a/.changes/unreleased/Test-20240618-185102.yaml b/.changes/unreleased/Test-20240618-185102.yaml new file mode 100644 index 0000000..536edaa --- /dev/null +++ b/.changes/unreleased/Test-20240618-185102.yaml @@ -0,0 +1,3 @@ +kind: Test +body: Add integration tests with a real server +time: 2024-06-18T18:51:02.089246+02:00 diff --git a/.github/workflows/code-quality.yaml b/.github/workflows/code-quality.yaml index ec67edd..f593bbe 100644 --- a/.github/workflows/code-quality.yaml +++ b/.github/workflows/code-quality.yaml @@ -19,6 +19,10 @@ jobs: - name: fetch server schema run: "hatch run dev:fetch-schema" - - name: basedpyright + - name: tests run: "hatch run test:run" + env: + SL_HOST: ${{ secrets.TEST_HOST }} + SL_ENV_ID: ${{ secrets.TEST_ENV_ID }} + SL_TOKEN: ${{ secrets.TEST_TOKEN }} diff --git a/tests/api/graphql/test_protocol.py b/tests/api/graphql/test_protocol.py index 570fedb..36ec5a0 100644 --- a/tests/api/graphql/test_protocol.py +++ b/tests/api/graphql/test_protocol.py @@ -1,7 +1,6 @@ from pytest_subtests import SubTests from dbtsl.api.graphql.protocol import GraphQLProtocol -from dbtsl.models.metric import Metric, MetricType from ...conftest import QueryValidator @@ -21,20 +20,3 @@ def test_queries_are_valid(subtests: SubTests, validate_query: QueryValidator) - with subtests.test(msg=f"GraphQLProtocol.{prop_name}"): query = prop_val.get_request_text() validate_query(query) - - -# NOTE: the following tests will validate that the client can appropriately -# parse an incoming server response. The "raw" responses were taken directly -# from an instance of metricflow-server via Postman. -def test_metrics_parses_server_respose() -> None: - raw = { - "metrics": [ - {"name": "A", "description": "a", "type": "CUMULATIVE"}, - {"name": "B", "description": "b", "type": "RATIO"}, - ] - } - parsed = GraphQLProtocol.metrics.parse_response(raw) - assert parsed == [ - Metric(name="A", description="a", type=MetricType.CUMULATIVE), - Metric(name="B", description="b", type=MetricType.RATIO), - ] diff --git a/tests/conftest.py b/tests/conftest.py index 6e1634e..d7fa4f9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,7 @@ -from typing import Callable, Union, cast +import asyncio +import os +from dataclasses import dataclass +from typing import Callable, Iterator, Union, cast import pytest from gql import Client, gql @@ -40,3 +43,44 @@ def validator(query_str: str) -> None: gql_client.validate(document=query_doc) return validator + + +@dataclass +class Credentials: + """Credentials used for integration testing.""" + + host: str + environment_id: int + token: str + + @classmethod + def from_env(cls) -> "Credentials": + """Get test credentials from environment variables. + + The following environment variables will be consumed: + - SL_HOST + - SL_TOKEN + - SL_ENV_ID + """ + return cls( + host=os.environ["SL_HOST"], + token=os.environ["SL_TOKEN"], + environment_id=int(os.environ["SL_ENV_ID"]), + ) + + +@pytest.fixture(scope="session") +def credentials() -> Credentials: + return Credentials.from_env() + + +@pytest.fixture(scope="session") +def event_loop() -> Iterator[asyncio.AbstractEventLoop]: + """Override pytest-asyncio's default `event_loop` fixture. + + We add scope='session' to make all tests share the same event loop. + This avoids concurrency issues related to opening and closing sessions. + """ + loop = asyncio.get_event_loop() + yield loop + loop.close() diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/integration/test_gql.py b/tests/integration/test_gql.py new file mode 100644 index 0000000..70902bf --- /dev/null +++ b/tests/integration/test_gql.py @@ -0,0 +1,55 @@ +from typing import AsyncIterator, Iterator + +import pytest + +from dbtsl.api.graphql.client.asyncio import AsyncGraphQLClient +from dbtsl.api.graphql.client.sync import SyncGraphQLClient + +from ..conftest import Credentials + + +@pytest.fixture(scope="session") +async def async_client(credentials: Credentials) -> AsyncIterator[AsyncGraphQLClient]: + client = AsyncGraphQLClient( + environment_id=credentials.environment_id, + auth_token=credentials.token, + server_host=credentials.host, + ) + async with client.session(): + yield client + + +@pytest.fixture(scope="session") +def sync_client(credentials: Credentials) -> Iterator[SyncGraphQLClient]: + client = SyncGraphQLClient( + environment_id=credentials.environment_id, + auth_token=credentials.token, + server_host=credentials.host, + ) + with client.session(): + yield client + + +def test_sync_client_lists_metrics_and_dimensions(sync_client: SyncGraphQLClient) -> None: + metrics = sync_client.metrics() + assert len(metrics) > 0 + dims = sync_client.dimensions(metrics=[metrics[0].name]) + assert len(dims) > 0 + + +async def test_async_client_lists_metrics_and_dimensions(async_client: AsyncGraphQLClient) -> None: + metrics = await async_client.metrics() + assert len(metrics) > 0 + dims = await async_client.dimensions(metrics=[metrics[0].name]) + assert len(dims) > 0 + + +async def test_async_client_query_works(async_client: AsyncGraphQLClient) -> None: + metrics = await async_client.metrics() + assert len(metrics) > 0 + table = await async_client.query( + metrics=[metrics[0].name], + group_by=["metric_time"], + limit=1, + ) + assert len(table) > 0