Skip to content

Commit fee21e0

Browse files
authored
test(integration): scope query tests to a database id (#92)
* test(integration): scope query tests to a database id * test(integration): scope execute_saved_query to a database id
1 parent 279f970 commit fee21e0

4 files changed

Lines changed: 43 additions & 4 deletions

File tree

tests/integration/conftest.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,24 @@
1515

1616
from hotdata import ApiClient, Configuration
1717
from hotdata.api.connections_api import ConnectionsApi
18+
from hotdata.api.databases_api import DatabasesApi
1819
from hotdata.api.datasets_api import DatasetsApi
1920
from hotdata.api.indexes_api import IndexesApi
2021
from hotdata.api.saved_queries_api import SavedQueriesApi
2122
from hotdata.api.secrets_api import SecretsApi
2223
from hotdata.api.workspaces_api import WorkspacesApi
24+
from hotdata.models.create_database_request import CreateDatabaseRequest
2325

2426

2527
REQUIRED_ENV = ("HOTDATA_SDK_TEST_API_KEY", "HOTDATA_SDK_TEST_WORKSPACE_ID")
2628
DEFAULT_API_URL = "https://api.hotdata.dev"
2729

30+
# Queries are scoped to a database via the X-Database-Id header. Databases no
31+
# longer auto-expire, so rather than create one per run (which would leak),
32+
# tests find-or-create a single stable database by name and reuse it — same
33+
# pattern as the e2e suite. Name is not unique server-side; we key off it.
34+
SHARED_DATABASE_NAME = "sdkci-shared"
35+
2836

2937
@dataclass(frozen=True)
3038
class TestEnv:
@@ -79,6 +87,23 @@ def connection_id(env: TestEnv) -> str:
7987
return env.connection_id
8088

8189

90+
@pytest.fixture(scope="session")
91+
def database_id(api_client: ApiClient) -> str:
92+
"""Id of the shared `sdkci-shared` database, creating it if absent.
93+
94+
Queries require an `X-Database-Id` scope; databases persist (no auto-expiry)
95+
so we reuse one across runs instead of creating-and-deleting per session.
96+
"""
97+
databases_api = DatabasesApi(api_client)
98+
for db in databases_api.list_databases().databases:
99+
if db.name == SHARED_DATABASE_NAME:
100+
return db.id
101+
created = databases_api.create_database(
102+
CreateDatabaseRequest(name=SHARED_DATABASE_NAME)
103+
)
104+
return created.id
105+
106+
82107
@pytest.fixture
83108
def sdkci_name() -> "callable[[str], str]":
84109
"""Returns `sdkci-<scenario>-<uuid8>` so orphans are identifiable.
@@ -109,6 +134,11 @@ def connections_api(api_client: ApiClient) -> ConnectionsApi:
109134
return ConnectionsApi(api_client)
110135

111136

137+
@pytest.fixture
138+
def databases_api(api_client: ApiClient) -> DatabasesApi:
139+
return DatabasesApi(api_client)
140+
141+
112142
@pytest.fixture
113143
def indexes_api(api_client: ApiClient) -> IndexesApi:
114144
return IndexesApi(api_client)

tests/integration/test_query_async_polling.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,15 @@ def test_query_async_polling(
4040
query_api: QueryApi,
4141
query_runs_api: QueryRunsApi,
4242
results_api: ResultsApi,
43+
database_id: str,
4344
) -> None:
4445
# async=True with a small async_after_ms forces the run to come back as
4546
# AsyncQueryResponse rather than synchronous. The QueryResponse / async
4647
# response variants are union-shaped on the client; we treat anything with
4748
# query_run_id as the start of the polling loop.
4849
submitted = query_api.query(
49-
QueryRequest(var_async=True, async_after_ms=1000, sql="SELECT 1 AS x")
50+
QueryRequest(var_async=True, async_after_ms=1000, sql="SELECT 1 AS x"),
51+
x_database_id=database_id,
5052
)
5153
query_run_id = submitted.query_run_id
5254
assert query_run_id

tests/integration/test_results_arrow.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,15 @@ def test_results_arrow(
4646
query_api: QueryApi,
4747
query_runs_api: QueryRunsApi,
4848
results_api: ResultsApi,
49+
database_id: str,
4950
) -> None:
5051
submitted = query_api.query(
5152
QueryRequest(
5253
var_async=True,
5354
async_after_ms=1000,
5455
sql="SELECT 1 AS x, 'hello' AS msg UNION ALL SELECT 2, 'world'",
55-
)
56+
),
57+
x_database_id=database_id,
5658
)
5759
query_run_id = submitted.query_run_id
5860
assert query_run_id

tests/integration/test_saved_query_versioning.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414

1515
def test_saved_query_versioning(
16-
saved_queries_api: SavedQueriesApi, sdkci_name
16+
saved_queries_api: SavedQueriesApi, sdkci_name, database_id: str
1717
) -> None:
1818
name = sdkci_name("savedq-versioning")
1919
created_id: str | None = None
@@ -50,7 +50,12 @@ def test_saved_query_versioning(
5050
f"expected versions 1,2,3 in {sorted(version_numbers)}"
5151
)
5252

53-
executed = saved_queries_api.execute_saved_query(created.id)
53+
# execute_saved_query runs SQL, so it also needs the database scope.
54+
# The endpoint has no typed x_database_id param yet, so set the header
55+
# directly via the _headers override.
56+
executed = saved_queries_api.execute_saved_query(
57+
created.id, _headers={"X-Database-Id": database_id}
58+
)
5459
assert executed.row_count == 1
5560
assert executed.rows == [[3]]
5661
finally:

0 commit comments

Comments
 (0)