You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by be...@apache.org on 2023/08/08 16:51:46 UTC

[superset] 06/11: WIP

This is an automated email from the ASF dual-hosted git repository.

beto pushed a commit to branch db-diagnostics
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 7c80412604e674f37b4654de8be5681fa973527f
Author: Beto Dealmeida <ro...@dealmeida.net>
AuthorDate: Tue Jul 25 16:55:55 2023 -0700

    WIP
---
 superset/cli/test_db.py | 159 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 155 insertions(+), 4 deletions(-)

diff --git a/superset/cli/test_db.py b/superset/cli/test_db.py
index 30be55bcb9..d1442fc198 100644
--- a/superset/cli/test_db.py
+++ b/superset/cli/test_db.py
@@ -18,12 +18,25 @@
 from __future__ import annotations
 
 import sys
-from typing import Any, Dict, Type
+from collections import defaultdict
+from datetime import datetime
+from typing import Any, Callable, Dict, Type
 
 import click
 import yaml
 from rich.console import Console
-from sqlalchemy import create_engine
+from sqlalchemy import (
+    Column,
+    create_engine,
+    DateTime,
+    ForeignKey,
+    insert,
+    Integer,
+    MetaData,
+    select,
+    String,
+    Table,
+)
 from sqlalchemy.engine import Engine
 from sqlalchemy.engine.url import make_url
 from sqlalchemy.exc import NoSuchModuleError
@@ -80,6 +93,85 @@ ADVANCED_FEATURES = {
     "Supports validating SQL before running query": "sql_validation",
 }
 
+metadata_obj = MetaData()
+
+user = Table(
+    "user",
+    metadata_obj,
+    Column("user_id", Integer, primary_key=True),
+    Column("user_name", String(16), nullable=False),
+    Column("email_address", String(60), key="email"),
+    Column("nickname", String(50), nullable=False),
+)
+
+user_prefs = Table(
+    "user_prefs",
+    metadata_obj,
+    Column("pref_id", Integer, primary_key=True),
+    Column("user_id", Integer, ForeignKey("user.user_id"), nullable=False),
+    Column("pref_name", String(40), nullable=False),
+    Column("pref_value", String(100)),
+)
+
+
+TestType = Callable[[Console, Engine], None]
+
+
+class TestRegistry:
+    def __init__(self) -> None:
+        self.tests: Dict[str, Any] = defaultdict(list)
+
+    def add(self, *dialects: str) -> Callable[[TestType], TestType]:
+        def decorator(func: TestType) -> TestType:
+            for dialect in dialects:
+                self.tests[dialect].append(func)
+
+            return func
+
+        return decorator
+
+    def get_tests(self, dialect: str) -> list[TestType]:
+        return self.tests[dialect]
+
+
+registry = TestRegistry()
+
+
+@registry.add("sqlite", "postgresql")
+def test_datetime(console: Console, engine: Engine) -> None:
+    """
+    Create a table with a timestamp column.
+    """
+    console.print("[bold]Testing datetime support...")
+
+    md = MetaData()
+    table = Table(
+        "test",
+        md,
+        Column("ts", DateTime),
+    )
+
+    try:
+        console.print("Creating a table with a timestamp column...")
+        md.create_all(engine)
+        console.print("[green]Table created!")
+
+        now = datetime.now()
+
+        console.print("Inserting timestamp value...")
+        stmt = insert(table).values(ts=now)
+        engine.execute(stmt)
+
+        console.print("Reading timestamp value...")
+        stmt = select(table)
+        row = engine.execute(stmt).fetchone()
+        assert row[0] == now
+        console.print(":thumbs_up: [green]Succcess!")
+    except Exception as ex:  # pylint: disable=broad-except
+        console.print(f"[red]Test failed: {ex}")
+        console.print("[bold]Exiting...")
+        sys.exit(1)
+
 
 @click.command()
 @click.argument("sqlalchemy_uri")
@@ -300,5 +392,64 @@ def test_database_connectivity(console: Console, engine: Engine) -> None:
     color = "green" if result == 1 else "red"
     console.print(f"[{color}]> {result}")
 
-    # TODO(betodealmeida): create tables with different types and test them
-    # TODO(betodealmeida): run DB-specific tests
+    console.print("[bold]Checking that we can create tables...")
+    try:
+        metadata_obj.create_all(engine)
+        console.print("[green]Tables created!")
+    except Exception as ex:  # pylint: disable=broad-except
+        console.print(f"[red]Unable to create tables: {ex}")
+        console.print("[bold]Exiting...")
+        sys.exit(1)
+
+    console.print("[bold]Checking that we can insert data...")
+    stmt = insert(user).values(
+        user_name="beto",
+        email="beto@example.org",
+        nickname="Beto",
+    )
+    try:
+        console.print(
+            "sql>",
+            stmt.compile(
+                dialect=engine.dialect,
+                compile_kwargs={"literal_binds": True},
+            ),
+        )
+        engine.execute(stmt)
+    except Exception as ex:  # pylint: disable=broad-except
+        console.print(f"[red]Unable to insert data: {ex}")
+        console.print("[bold]Exiting...")
+        sys.exit(1)
+
+    console.print("[bold]Checking that we can read data...")
+    stmt = select(user).where(user.c.user_name == "beto")
+    try:
+        console.print(
+            "sql>",
+            stmt.compile(
+                dialect=engine.dialect,
+                compile_kwargs={"literal_binds": True},
+            ),
+        )
+        result = engine.execute(stmt).fetchall()
+        console.print(f"[green]> {result}")
+    except Exception as ex:  # pylint: disable=broad-except
+        console.print(f"[red]Unable to read data: {ex}")
+        console.print("[bold]Exiting...")
+        sys.exit(1)
+
+    console.print("[bold]Checking that we can drop tables...")
+    try:
+        metadata_obj.drop_all(engine)
+        console.print("[green]Done!")
+    except Exception as ex:  # pylint: disable=broad-except
+        console.print(f"[red]Unable to drop tables: {ex}")
+        console.print("[bold]Exiting...")
+        sys.exit(1)
+
+    # run engine-specific tests
+    tests = registry.get_tests(engine.dialect.name)
+    if tests:
+        console.print("[bold]Running engine-specific tests...")
+        for test in tests:
+            test(console, engine)