Skip to content

Commit

Permalink
test(integration): add integration tests with a real server
Browse files Browse the repository at this point in the history
This commit adds integration tests that will check if the SDK works when
talking to a real server.
  • Loading branch information
serramatutu committed Jun 18, 2024
1 parent a41587a commit 36526d9
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 20 deletions.
3 changes: 3 additions & 0 deletions .changes/unreleased/Test-20240618-185102.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Test
body: Add integration tests with a real server
time: 2024-06-18T18:51:02.089246+02:00
6 changes: 5 additions & 1 deletion .github/workflows/code-quality.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}

18 changes: 0 additions & 18 deletions tests/api/graphql/test_protocol.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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),
]
46 changes: 45 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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()
Empty file added tests/integration/__init__.py
Empty file.
55 changes: 55 additions & 0 deletions tests/integration/test_gql.py
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 36526d9

Please sign in to comment.