Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: hainenber <dotronghai96@gmail.com> Signed-off-by: Gabriel Torres Ruiz <gabo2595@gmail.com> Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Superset Dev <dev@superset.apache.org> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Milad Rashidikhah <mrashidikhah32@gmail.com> Co-authored-by: bucketbase26 <singhayush062006@gmail.com> Co-authored-by: Joe Li <joe@preset.io> Co-authored-by: Viktor Högberg <119532259+vhogberg@users.noreply.github.com> Co-authored-by: joey <97154801+chkang83@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Chandan P <95340276+NoiceHax@users.noreply.github.com> Co-authored-by: Mafi <matt.fitzgerald@gmail.com> Co-authored-by: Matt Fitzgerald <matt.fitzgerald@preset.io> Co-authored-by: Enzo Martellucci <52219496+EnxDev@users.noreply.github.com> Co-authored-by: Alexandru Soare <37236580+alexandrusoare@users.noreply.github.com> Co-authored-by: Mehmet Salih Yavuz <salih.yavuz@proton.me> Co-authored-by: Sanmitra Nagaraj <48400413+s1ny1998@users.noreply.github.com> Co-authored-by: Lalith Kothuru <lalith.kothuru@gmail.com> Co-authored-by: shaurya <shauryajaiswal.dev@gmail.com> Co-authored-by: Shaurya <19599684+no-hup@users.noreply.github.com> Co-authored-by: Đỗ Trọng Hải <41283691+hainenber@users.noreply.github.com> Co-authored-by: rlei <242280117+rlei-odes@users.noreply.github.com> Co-authored-by: Ville Brofeldt <33317356+villebro@users.noreply.github.com> Co-authored-by: Gabriel Torres Ruiz <gabo2595@gmail.com> Co-authored-by: hainenber <dotronghai96@gmail.com> Co-authored-by: ʈᵃᵢ <tai@apache.org> Co-authored-by: Mike Bridge <michael.bridge@preset.io> Co-authored-by: Elizabeth Thompson <eschutho@gmail.com> Co-authored-by: Francesco.Castaldi <info@francescocastaldi.it> Co-authored-by: FrancescoCastaldi <francesco.castaldi@mapsgroup.it> Co-authored-by: Abdul Rehman <76230556+Abdulrehman-PIAIC80387@users.noreply.github.com> Co-authored-by: Sepuri Sai Krishna <saik20533@gmail.com> Co-authored-by: Mallikarjuna Reddy Nimmakayala <mallikarjunareddy.nimmakayala@gmail.com> Co-authored-by: PRATHAMESH HUKKERI <prathamhukkeri04@gmail.com> Co-authored-by: Prathamesh Hukkeri <prathamesh04@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: SBIN2010 <Sbin2010@mail.ru>
118 lines
4.4 KiB
Python
118 lines
4.4 KiB
Python
# Licensed to the Apache Software Foundation (ASF) under one
|
|
# or more contributor license agreements. See the NOTICE file
|
|
# distributed with this work for additional information
|
|
# regarding copyright ownership. The ASF licenses this file
|
|
# to you under the Apache License, Version 2.0 (the
|
|
# "License"); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing,
|
|
# software distributed under the License is distributed on an
|
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
# KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations
|
|
# under the License.
|
|
"""
|
|
Tests db_engine_specs.mysql against a real MySQL instance, spun up on
|
|
demand via testcontainers. Run via .github/workflows/testcontainers.yml.
|
|
|
|
Plain MySQL itself was never covered by this suite: MariaDB and StarRocks
|
|
both reuse `MySQLEngineSpec`'s plain "mysql" dialect via mysqlclient, but
|
|
neither stands in for vanilla MySQL server's own dialect quirks.
|
|
|
|
Could not be verified locally in this environment: mysqlclient (MySQLdb)
|
|
has a pre-existing, unrelated native-library linking issue against this
|
|
machine's Homebrew-installed libmysqlclient. CI installs it via apt on
|
|
Linux, where this does not occur.
|
|
"""
|
|
|
|
from collections.abc import Iterator
|
|
|
|
import pytest
|
|
from sqlalchemy import (
|
|
Column,
|
|
create_engine,
|
|
inspect,
|
|
Integer,
|
|
MetaData,
|
|
Table as SATable,
|
|
)
|
|
from sqlalchemy.engine import Engine
|
|
|
|
from superset.db_engine_specs.mysql import MySQLEngineSpec
|
|
from superset.sql.parse import Table
|
|
from superset.utils.core import GenericDataType
|
|
|
|
pytestmark = pytest.mark.testcontainers
|
|
|
|
from ._driver import require_driver # noqa: E402
|
|
|
|
require_driver("testcontainers.community.mysql")
|
|
|
|
from testcontainers.community.mysql import MySqlContainer # noqa: E402
|
|
|
|
from ._pagination import ( # noqa: E402
|
|
assert_paginated_query_returns_correct_rows_in_order,
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def engine() -> Iterator[Engine]:
|
|
with MySqlContainer("mysql:8.0") as container:
|
|
# get_connection_url() has no host override and defaults to
|
|
# get_container_host_ip(), which is the literal string "localhost"
|
|
# on native Linux Docker (e.g. GitHub Actions runners). MySQLdb
|
|
# (mysqlclient) treats a "localhost" host specially and attempts a
|
|
# Unix socket connection instead of TCP, which fails since there's
|
|
# no local MySQL socket -- the container is reached over the
|
|
# network. Only rewrite that specific local case to 127.0.0.1; a
|
|
# remote Docker daemon reports its own real host/IP here, which
|
|
# must be preserved so the suite can still reach it.
|
|
host = container.get_container_host_ip()
|
|
if host == "localhost":
|
|
host = "127.0.0.1"
|
|
port = container.get_exposed_port(container.port)
|
|
yield create_engine(
|
|
f"mysql://{container.username}:{container.password}"
|
|
f"@{host}:{port}/{container.dbname}"
|
|
)
|
|
|
|
|
|
def test_paginated_query_returns_correct_rows_in_order(engine: Engine) -> None:
|
|
"""
|
|
A plain SQLAlchemy Core LIMIT/OFFSET query, compiled and executed against
|
|
a real instance. Mocked tests cannot catch a dialect compiling this
|
|
incorrectly (see apache/superset#42899, where Trino emitted OFFSET
|
|
before LIMIT) -- only real execution can.
|
|
"""
|
|
assert_paginated_query_returns_correct_rows_in_order(engine)
|
|
|
|
|
|
def test_get_columns_maps_native_types(engine: Engine) -> None:
|
|
"""
|
|
MySQLEngineSpec.get_columns wraps a real SQLAlchemy Inspector; this
|
|
exercises that against actual server-reported column metadata rather
|
|
than a mocked Inspector.
|
|
"""
|
|
metadata = MetaData()
|
|
SATable(
|
|
"pilot_types",
|
|
metadata,
|
|
Column("id", Integer, primary_key=True),
|
|
Column("amount", Integer),
|
|
)
|
|
metadata.create_all(engine)
|
|
|
|
inspector = inspect(engine)
|
|
columns = MySQLEngineSpec.get_columns(inspector, Table("pilot_types"))
|
|
|
|
by_name = {col["column_name"]: col for col in columns}
|
|
assert set(by_name) == {"id", "amount"}
|
|
for col in by_name.values():
|
|
spec = MySQLEngineSpec.get_column_spec(str(col["type"]))
|
|
assert spec is not None
|
|
assert spec.generic_type == GenericDataType.NUMERIC
|
|
assert isinstance(spec.sqla_type, Integer)
|