|
21 | 21 |
|
22 | 22 | from __future__ import annotations |
23 | 23 |
|
| 24 | +import sys |
24 | 25 | from uuid import uuid4 |
25 | 26 |
|
26 | 27 | import pytest |
|
34 | 35 | ServerOperationError, |
35 | 36 | ) |
36 | 37 |
|
37 | | -# Skip the whole module unless the kernel wheel is genuinely installed. |
38 | | -# ``pytest.importorskip`` alone isn't enough: the kernel unit tests inject a |
39 | | -# fake ``databricks_sql_kernel`` ModuleType into ``sys.modules`` so the |
40 | | -# connector's import-time ``import databricks_sql_kernel`` succeeds without |
41 | | -# the Rust extension. In the same pytest session that fake module is still |
42 | | -# in ``sys.modules`` when this e2e file is collected, and importorskip |
43 | | -# happily returns it. A real wheel exposes ``__file__`` (the compiled |
44 | | -# extension on disk); the fake ModuleType does not. |
45 | | -_kernel_mod = pytest.importorskip( |
46 | | - "databricks_sql_kernel", |
47 | | - reason="use_kernel=True requires the databricks-sql-kernel package", |
48 | | -) |
49 | | -if not getattr(_kernel_mod, "__file__", None): |
| 38 | +# These tests must run against the REAL databricks-sql-kernel wheel and |
| 39 | +# must NOT silently pass when it's absent or shadowed. We distinguish |
| 40 | +# three states explicitly so a misconfigured CI job can't look green: |
| 41 | +# |
| 42 | +# 1. Wheel genuinely not installed -> legitimate skip. |
| 43 | +# 2. Wheel installed in the env but ``sys.modules`` currently holds a |
| 44 | +# stub (the kernel UNIT tests inject a fake ``databricks_sql_kernel`` |
| 45 | +# ModuleType; in a shared ``pytest tests/unit tests/e2e`` session |
| 46 | +# that fake can still be resident when this file is collected) -> |
| 47 | +# FAIL loudly. Silently skipping here is what made the coverage job |
| 48 | +# look like it exercised the kernel when it didn't. |
| 49 | +# 3. Wheel installed and importable for real -> run. |
| 50 | +# |
| 51 | +# "Installed in the env" is decided via importlib.metadata (the dist |
| 52 | +# database on disk), which a ``sys.modules`` stub can't fake. The |
| 53 | +# ``__file__`` check then tells a real compiled extension from a stub |
| 54 | +# ModuleType. |
| 55 | +import importlib.metadata as _ilm |
| 56 | + |
| 57 | +try: |
| 58 | + _ilm.version("databricks-sql-kernel") |
| 59 | + _kernel_installed = True |
| 60 | +except _ilm.PackageNotFoundError: |
| 61 | + _kernel_installed = False |
| 62 | + |
| 63 | +_kernel_mod = sys.modules.get("databricks_sql_kernel") |
| 64 | +if _kernel_mod is None: |
| 65 | + try: |
| 66 | + import databricks_sql_kernel as _kernel_mod # type: ignore[import-not-found] |
| 67 | + except ImportError: |
| 68 | + _kernel_mod = None |
| 69 | + |
| 70 | +_kernel_is_real = _kernel_mod is not None and getattr(_kernel_mod, "__file__", None) |
| 71 | + |
| 72 | +if not _kernel_installed: |
| 73 | + # State 1: nothing to test against. |
50 | 74 | pytest.skip( |
51 | | - "databricks_sql_kernel is a test stub (no __file__); " |
52 | | - "install the real wheel to run kernel e2e tests", |
| 75 | + "databricks-sql-kernel is not installed; " |
| 76 | + "install the real wheel (pip install 'databricks-sql-connector[kernel]') " |
| 77 | + "to run kernel e2e tests", |
53 | 78 | allow_module_level=True, |
54 | 79 | ) |
| 80 | +elif not _kernel_is_real: |
| 81 | + # State 2: the wheel IS installed but a stub is shadowing it. Do NOT |
| 82 | + # skip — that would hide the fact that the kernel path never ran. |
| 83 | + raise RuntimeError( |
| 84 | + "databricks-sql-kernel is installed in this environment but " |
| 85 | + "sys.modules holds a stub (no __file__) — the kernel e2e tests " |
| 86 | + "would not actually exercise the real wheel. This usually means a " |
| 87 | + "unit test's fake databricks_sql_kernel module is shadowing the " |
| 88 | + "real one in a shared pytest session. Run the kernel e2e tests in " |
| 89 | + "isolation (separate pytest invocation) so the real wheel loads." |
| 90 | + ) |
55 | 91 |
|
56 | 92 |
|
57 | 93 | @pytest.fixture(scope="module") |
@@ -80,9 +116,21 @@ def kernel_conn_params(connection_details): |
80 | 116 | @pytest.fixture |
81 | 117 | def conn(kernel_conn_params): |
82 | 118 | """One-shot connection per test (the simple_test pattern the |
83 | | - existing e2e suite uses for cursor-level tests).""" |
| 119 | + existing e2e suite uses for cursor-level tests). |
| 120 | +
|
| 121 | + Asserts the connection actually routed through the kernel backend — |
| 122 | + if ``use_kernel=True`` silently fell back to Thrift (e.g. a wiring |
| 123 | + regression), these tests must fail rather than pass against the |
| 124 | + wrong backend. |
| 125 | + """ |
| 126 | + from databricks.sql.backend.kernel.client import KernelDatabricksClient |
| 127 | + |
84 | 128 | c = sql.connect(**kernel_conn_params) |
85 | 129 | try: |
| 130 | + assert isinstance(c.session.backend, KernelDatabricksClient), ( |
| 131 | + "use_kernel=True did not route through KernelDatabricksClient; " |
| 132 | + f"got {type(c.session.backend).__name__}" |
| 133 | + ) |
86 | 134 | yield c |
87 | 135 | finally: |
88 | 136 | c.close() |
|
0 commit comments