Skip to content

Commit b4ae83d

Browse files
authored
Merge branch 'main' into plan-dedup-snapshot-state-read
2 parents 2a8c7a8 + fc2976a commit b4ae83d

7 files changed

Lines changed: 35 additions & 20 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ dev = [
7878
"google-auth",
7979
"google-cloud-bigquery",
8080
"google-cloud-bigquery-storage",
81-
"httpx",
81+
"httpx2",
8282
"mypy~=1.13.0",
8383
"numpy",
8484
"pandas-stubs",

tests/core/engine_adapter/integration/test_integration_athena.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,21 @@ def s3_list_objects(s3: t.Any, location: str, **list_objects_kwargs: t.Any) -> t
4848
return lst
4949

5050

51+
def s3_delete_objects(s3: t.Any, location: str) -> None:
52+
# The S3 location for a given test is stable across pytest-rerunfailures retries within the same
53+
# test session (it's derived from the session's testrun_uid + the test's name), so a prior failed
54+
# attempt can leave objects behind that a subsequent retry would otherwise trip over. Proactively
55+
# clearing the prefix makes these tests self-healing instead of just asserting it's already empty.
56+
bucket, prefix = parse_s3_uri(location)
57+
for page in s3.get_paginator("list_objects_v2").paginate(Bucket=bucket, Prefix=prefix):
58+
objects = [{"Key": o["Key"]} for o in page.get("Contents", [])]
59+
if objects:
60+
s3.delete_objects(Bucket=bucket, Delete={"Objects": objects})
61+
62+
5163
def test_clear_partition_data(ctx: TestContext, engine_adapter: AthenaEngineAdapter, s3: t.Any):
5264
base_uri = engine_adapter.s3_warehouse_location_or_raise
65+
s3_delete_objects(s3, base_uri)
5366
assert len(s3_list_objects(s3, base_uri)) == 0
5467

5568
src_table = ctx.table("src_table")
@@ -239,6 +252,7 @@ def test_hive_truncate_table(ctx: TestContext, engine_adapter: AthenaEngineAdapt
239252
]
240253
)
241254

255+
s3_delete_objects(s3, base_uri)
242256
assert len(s3_list_objects(s3, base_uri)) == 0
243257

244258
engine_adapter.ctas(table_name=table_1, query_or_df=base_data)

tests/core/engine_adapter/integration/test_integration_bigquery.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from unittest import mock
33

44
import pytest
5-
import time_machine
65
from pathlib import Path
76
from sqlglot import exp
87
from sqlglot.optimizer.qualify_columns import quote_identifiers
@@ -474,7 +473,6 @@ def test_plan_correlation_id_in_job_labels(ctx: TestContext):
474473
assert labels == {correlation_id.job_type.value.lower(): correlation_id.job_id}
475474

476475

477-
@time_machine.travel("2023-01-08 15:00:00 UTC")
478476
def test_run_correlation_id_in_job_labels(ctx: TestContext):
479477
run_id = "test_run_id"
480478
model_name = ctx.table("run_test")
@@ -497,7 +495,7 @@ def test_run_correlation_id_in_job_labels(ctx: TestContext):
497495
)
498496
)
499497
)
500-
sqlmesh.plan(auto_apply=True, no_prompts=True)
498+
sqlmesh.plan(auto_apply=True, no_prompts=True, execution_time="2023-01-08 15:00:00")
501499

502500
captured_evaluators: t.List = []
503501
original_scheduler = sqlmesh.scheduler
@@ -510,12 +508,9 @@ def scheduler_wrapper(
510508
captured_evaluators.append(snapshot_evaluator)
511509
return original_scheduler(environment=environment, snapshot_evaluator=snapshot_evaluator)
512510

513-
with time_machine.travel("2023-01-09 00:00:00 UTC"):
514-
with mock.patch(
515-
"sqlmesh.core.context.analytics.collector.on_run_start", return_value=run_id
516-
):
517-
with mock.patch.object(sqlmesh, "scheduler", scheduler_wrapper):
518-
sqlmesh.run()
511+
with mock.patch("sqlmesh.core.context.analytics.collector.on_run_start", return_value=run_id):
512+
with mock.patch.object(sqlmesh, "scheduler", scheduler_wrapper):
513+
sqlmesh.run(execution_time="2023-01-09 00:00:00")
519514

520515
assert captured_evaluators
521516
adapter = t.cast(BigQueryEngineAdapter, captured_evaluators[-1].adapter)

tests/core/engine_adapter/integration/test_integration_postgres.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import typing as t
2+
import uuid
23
from contextlib import contextmanager
34
import pytest
45
from pytest import FixtureRequest
@@ -53,7 +54,8 @@ def create_users(
5354
_cleanup_user(engine_adapter, user_name)
5455

5556
for role_name in role_names:
56-
user_name = f"test_{role_name}"
57+
random_suffix = uuid.uuid4().hex[:6]
58+
user_name = f"test_{role_name}_{random_suffix}"
5759
password = random_id()
5860
engine_adapter.execute(f"CREATE USER \"{user_name}\" WITH PASSWORD '{password}'")
5961
engine_adapter.execute(f'GRANT USAGE ON SCHEMA public TO "{user_name}"')
@@ -381,12 +383,14 @@ def test_grants_plan_target_layer_physical_only(
381383
with create_users(engine_adapter, "reader") as roles:
382384
(tmp_path / "models").mkdir(exist_ok=True)
383385

384-
model_def = """
386+
reader_username = roles["reader"]["username"]
387+
388+
model_def = f"""
385389
MODEL (
386390
name test_schema.physical_grants_model,
387391
kind FULL,
388392
grants (
389-
'select' = ['test_reader']
393+
'select' = ['{reader_username}']
390394
),
391395
grants_target_layer 'physical'
392396
);
@@ -421,12 +425,14 @@ def test_grants_plan_target_layer_virtual_only(
421425
with create_users(engine_adapter, "viewer") as roles:
422426
(tmp_path / "models").mkdir(exist_ok=True)
423427

424-
model_def = """
428+
viewer_username = roles["viewer"]["username"]
429+
430+
model_def = f"""
425431
MODEL (
426432
name test_schema.virtual_grants_model,
427433
kind FULL,
428434
grants (
429-
'select' = ['test_viewer']
435+
'select' = ['{viewer_username}']
430436
),
431437
grants_target_layer 'virtual'
432438
);

tests/web/test_main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import pytest
88
from fastapi import FastAPI
99
from fastapi.testclient import TestClient
10-
from httpx import ASGITransport, AsyncClient
10+
from httpx2 import ASGITransport, AsyncClient
1111
from pytest_mock.plugin import MockerFixture
1212

1313
from sqlmesh.core.context import Context

web/server/exceptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import typing as t
44

55
from fastapi import HTTPException
6-
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
6+
from starlette.status import HTTP_422_UNPROCESSABLE_CONTENT
77

88
from sqlmesh.utils.date import now_timestamp
99
from web.server.models import ApiExceptionPayload
@@ -14,7 +14,7 @@ def __init__(
1414
self,
1515
origin: str,
1616
message: str,
17-
status_code: int = HTTP_422_UNPROCESSABLE_ENTITY,
17+
status_code: int = HTTP_422_UNPROCESSABLE_CONTENT,
1818
trigger: t.Optional[str] = None,
1919
):
2020
super().__init__(status_code)

web/server/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import pyarrow as pa # type: ignore
1010
from fastapi import Depends, HTTPException
1111
from starlette.responses import StreamingResponse
12-
from starlette.status import HTTP_404_NOT_FOUND, HTTP_422_UNPROCESSABLE_ENTITY
12+
from starlette.status import HTTP_404_NOT_FOUND, HTTP_422_UNPROCESSABLE_CONTENT
1313

1414
from sqlmesh.core import constants as c
1515
from web.server.console import api_console
@@ -45,7 +45,7 @@ def func_wrapper() -> R:
4545
message="An unexpected error occurred",
4646
origin="API -> utils -> run_in_executor",
4747
trigger="An unexpected error occurred",
48-
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
48+
status_code=HTTP_422_UNPROCESSABLE_CONTENT,
4949
)
5050
)
5151
raise e

0 commit comments

Comments
 (0)