From 9203433ef054642399cade06265b5006be0765de Mon Sep 17 00:00:00 2001 From: tycho garen Date: Mon, 4 Mar 2024 22:59:06 -0500 Subject: [PATCH 1/3] chore: pytest path cleanup and port management --- justfile | 2 +- tests/fixtures/dbt_project/profiles.yml | 4 +- tests/fixtures/glaredb.py | 27 ++++++++--- tests/test_bson.py | 6 +-- tests/test_dbt.py | 60 +++++++++++++------------ tests/test_functions.py | 2 +- tests/test_json.py | 2 +- tests/test_lance.py | 3 +- tests/test_smoke.py | 19 ++++---- 9 files changed, 68 insertions(+), 57 deletions(-) diff --git a/justfile b/justfile index 494178dc4..249e3b3e2 100644 --- a/justfile +++ b/justfile @@ -128,7 +128,7 @@ venv: pytest *args: {{VENV_BIN}}/poetry -C tests install --no-root {{VENV_BIN}}/poetry -C tests lock --no-update - {{VENV_BIN}}/poetry -C tests run pytest --rootdir={{invocation_directory()}}/tests {{ if args == "" {'tests'} else {args} }} + {{VENV_BIN}}/poetry -C tests run pytest -n auto -v --rootdir={{invocation_directory()}}/tests {{ if args == "" {'tests'} else {args} }} # private helpers below # --------------------- diff --git a/tests/fixtures/dbt_project/profiles.yml b/tests/fixtures/dbt_project/profiles.yml index fe9591e0a..a806ed851 100644 --- a/tests/fixtures/dbt_project/profiles.yml +++ b/tests/fixtures/dbt_project/profiles.yml @@ -4,9 +4,9 @@ glaredb_dbt_test: dbname: default host: 127.0.0.1 pass: "" - port: 5432 + port: "{{ env_var('GLAREDB_PORT') | as_number }}" schema: public threads: 1 type: postgres user: "{{ env_var('DBT_USER') }}" - target: test_target \ No newline at end of file + target: test_target diff --git a/tests/fixtures/glaredb.py b/tests/fixtures/glaredb.py index b9cdfbc8c..65aaf9ef4 100644 --- a/tests/fixtures/glaredb.py +++ b/tests/fixtures/glaredb.py @@ -1,34 +1,47 @@ +import socket +import contextlib import pathlib import time import subprocess import sys +import logging import pytest import psycopg2 import tests +logger = logging.getLogger("fixtures") + @pytest.fixture -def release_path() -> pathlib.Path: - return tests.PKG_DIRECTORY.joinpath("target", "release", "glaredb") +def glaredb_path() -> list[pathlib.Path]: + return [ + tests.PKG_DIRECTORY.joinpath("target", "release", "glaredb"), + tests.PKG_DIRECTORY.joinpath("target", "debug", "glaredb"), + ] @pytest.fixture -def debug_path() -> pathlib.Path: - return tests.PKG_DIRECTORY.joinpath("target", "debug", "glaredb") +def binary_path(glaredb_path: list[pathlib.Path]) -> pathlib.Path: + return glaredb_path[0] if glaredb_path[0].exists() else glaredb_path[1] @pytest.fixture def glaredb_connection( - debug_path: pathlib.Path, + binary_path: list[pathlib.Path], tmp_path_factory: pytest.TempPathFactory, ) -> psycopg2.extensions.connection: - addr = ("127.0.0.1", "5432") + with contextlib.closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: + s.bind(("", 0)) + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + addr = ("127.0.0.1", str(s.getsockname()[1])) + + logger.info(f"starting glaredb on port {addr[0]}") with subprocess.Popen( [ - debug_path.absolute(), + binary_path.absolute(), "--verbose", "server", "--data-dir", diff --git a/tests/test_bson.py b/tests/test_bson.py index bc898125b..6f9822766 100644 --- a/tests/test_bson.py +++ b/tests/test_bson.py @@ -9,13 +9,13 @@ import psycopg2.extras import pytest -from tests.fixtures.glaredb import glaredb_connection, debug_path +from tests.fixtures.glaredb import glaredb_connection, glaredb_path, binary_path import tests.tools def test_bson_copy_to( glaredb_connection: psycopg2.extensions.connection, - debug_path: pathlib.Path, + binary_path: pathlib.Path, tmp_path_factory: pytest.TempPathFactory, ): curr = glaredb_connection.cursor() @@ -48,7 +48,7 @@ def test_bson_copy_to( with tests.tools.cd(output_dir): out = subprocess.run( [ - f"{debug_path}", + f"{binary_path}", "--query", f"select count(*) as count from '{output_fn}'", "--mode", diff --git a/tests/test_dbt.py b/tests/test_dbt.py index 4cef6a204..742d579e8 100644 --- a/tests/test_dbt.py +++ b/tests/test_dbt.py @@ -7,7 +7,7 @@ import pytest import tests.tools -from tests.fixtures.glaredb import glaredb_connection, debug_path +from tests.fixtures.glaredb import glaredb_connection, glaredb_path, binary_path @pytest.fixture @@ -37,20 +37,21 @@ def test_dbt_glaredb( curr.execute("SELECT * FROM public.dbt_test") a = curr.fetchall() - with tests.tools.env("DBT_USER", glaredb_connection.info.user): - res: dbtRunnerResult = dbtRunner().invoke( - [ - "run", - "--project-dir", - dbt_project_path, - "--profiles-dir", - dbt_project_path, - "-m", - model_name, - ] - ) - - assert res.success is run_success + with tests.tools.env("GLAREDB_PORT", str(glaredb_connection.info.port)): + with tests.tools.env("DBT_USER", glaredb_connection.info.user): + res: dbtRunnerResult = dbtRunner().invoke( + [ + "run", + "--project-dir", + dbt_project_path, + "--profiles-dir", + dbt_project_path, + "-m", + model_name, + ] + ) + + assert res.success is run_success with glaredb_connection.cursor() as curr: curr.execute(f"select count(*) from {model_name}") @@ -80,20 +81,21 @@ def test_dbt_glaredb_external_postgres( """ ) - with tests.tools.env("DBT_USER", glaredb_connection.info.user): - res: dbtRunnerResult = dbtRunner().invoke( - [ - "run", - "--project-dir", - dbt_project_path, - "--profiles-dir", - dbt_project_path, - "-m", - model_name, - ] - ) - - assert res.success is True + with tests.tools.env("GLAREDB_PORT", str(glaredb_connection.info.port)): + with tests.tools.env("DBT_USER", glaredb_connection.info.user): + res: dbtRunnerResult = dbtRunner().invoke( + [ + "run", + "--project-dir", + dbt_project_path, + "--profiles-dir", + dbt_project_path, + "-m", + model_name, + ] + ) + + assert res.success is True with glaredb_connection.cursor() as curr: curr.execute(f"select count(*) from {model_name}") diff --git a/tests/test_functions.py b/tests/test_functions.py index 5373e0f10..ecec2cc8b 100644 --- a/tests/test_functions.py +++ b/tests/test_functions.py @@ -1,6 +1,6 @@ import psycopg2 -from tests.fixtures.glaredb import glaredb_connection, debug_path +from tests.fixtures.glaredb import glaredb_connection, glaredb_path, binary_path def test_scalar_parsing( diff --git a/tests/test_json.py b/tests/test_json.py index d5f54813c..ff7fd5a77 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -6,7 +6,7 @@ import psycopg2.extras import pytest -from tests.fixtures.glaredb import glaredb_connection, debug_path +from tests.fixtures.glaredb import glaredb_connection, glaredb_path, binary_path @pytest.fixture diff --git a/tests/test_lance.py b/tests/test_lance.py index 3de44a3be..310d82b63 100644 --- a/tests/test_lance.py +++ b/tests/test_lance.py @@ -7,9 +7,8 @@ import psycopg2.extras import pytest - import tests.tools -from tests.fixtures.glaredb import glaredb_connection, debug_path +from tests.fixtures.glaredb import glaredb_connection, glaredb_path, binary_path def test_sanity_check( diff --git a/tests/test_smoke.py b/tests/test_smoke.py index 644a605a2..86a43cd19 100644 --- a/tests/test_smoke.py +++ b/tests/test_smoke.py @@ -5,20 +5,17 @@ import pytest import psycopg2 -from tests.fixtures.glaredb import glaredb_connection, release_path, debug_path +from tests.fixtures.glaredb import glaredb_connection, glaredb_path, binary_path -def test_release_exists(release_path: pathlib.Path): - assert not release_path.exists() # the release binary does not exist +def test_binary_exists(glaredb_path: list[pathlib.Path]): + assert len(glaredb_path) == 2 + assert glaredb_path[0].exists() or glaredb_path[1].exists() -def test_debug_exists(debug_path: pathlib.Path): - assert debug_path.exists() # the debug binary exists - - -def test_debug_executes(debug_path: pathlib.Path): +def test_binary_executes(binary_path: list[pathlib.Path]): # run the binary and see if it returns: - assert subprocess.check_call([debug_path.absolute(), "-q", "SELECT 1;"]) == 0 + assert subprocess.check_call([binary_path.absolute(), "-q", "SELECT 1;"]) == 0 def test_start( @@ -29,14 +26,14 @@ def test_start( @pytest.mark.skipif(not sys.platform.startswith("linux"), reason="linux version of the test") -def test_expected_linking_linux(debug_path: pathlib.Path): +def test_expected_linking_linux(binary_path: pathlib.Path): out = [ ll for cell in [ item for item in [ line.split(" ") - for line in str(subprocess.check_output(["ldd", debug_path.absolute()], text=True)) + for line in str(subprocess.check_output(["ldd", binary_path.absolute()], text=True)) .replace("\t", "") .split("\n") ] From e23af09f3f9123e21be13ce0cc5dcb228e0a37f3 Mon Sep 17 00:00:00 2001 From: tycho garen Date: Tue, 5 Mar 2024 08:16:36 -0500 Subject: [PATCH 2/3] multiwith --- tests/test_dbt.py | 64 +++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/tests/test_dbt.py b/tests/test_dbt.py index 742d579e8..fc37f2cd4 100644 --- a/tests/test_dbt.py +++ b/tests/test_dbt.py @@ -37,21 +37,23 @@ def test_dbt_glaredb( curr.execute("SELECT * FROM public.dbt_test") a = curr.fetchall() - with tests.tools.env("GLAREDB_PORT", str(glaredb_connection.info.port)): - with tests.tools.env("DBT_USER", glaredb_connection.info.user): - res: dbtRunnerResult = dbtRunner().invoke( - [ - "run", - "--project-dir", - dbt_project_path, - "--profiles-dir", - dbt_project_path, - "-m", - model_name, - ] - ) - - assert res.success is run_success + with ( + tests.tools.env("GLAREDB_PORT", str(glaredb_connection.info.port)), + tests.tools.env("DBT_USER", glaredb_connection.info.user), + ): + res: dbtRunnerResult = dbtRunner().invoke( + [ + "run", + "--project-dir", + dbt_project_path, + "--profiles-dir", + dbt_project_path, + "-m", + model_name, + ] + ) + + assert res.success is run_success with glaredb_connection.cursor() as curr: curr.execute(f"select count(*) from {model_name}") @@ -81,21 +83,23 @@ def test_dbt_glaredb_external_postgres( """ ) - with tests.tools.env("GLAREDB_PORT", str(glaredb_connection.info.port)): - with tests.tools.env("DBT_USER", glaredb_connection.info.user): - res: dbtRunnerResult = dbtRunner().invoke( - [ - "run", - "--project-dir", - dbt_project_path, - "--profiles-dir", - dbt_project_path, - "-m", - model_name, - ] - ) - - assert res.success is True + with ( + tests.tools.env("GLAREDB_PORT", str(glaredb_connection.info.port)), + tests.tools.env("DBT_USER", glaredb_connection.info.user), + ): + res: dbtRunnerResult = dbtRunner().invoke( + [ + "run", + "--project-dir", + dbt_project_path, + "--profiles-dir", + dbt_project_path, + "-m", + model_name, + ] + ) + + assert res.success is True with glaredb_connection.cursor() as curr: curr.execute(f"select count(*) from {model_name}") From 155bc4bb37eb03e84d86a5a9e98c6d4cd8158ff8 Mon Sep 17 00:00:00 2001 From: tycho garen Date: Tue, 5 Mar 2024 08:29:36 -0500 Subject: [PATCH 3/3] add xdist --- tests/poetry.lock | 36 +++++++++++++++++++++++++++++++++++- tests/pyproject.toml | 1 + 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/tests/poetry.lock b/tests/poetry.lock index c23f9d4ce..3a5ac17dd 100644 --- a/tests/poetry.lock +++ b/tests/poetry.lock @@ -385,6 +385,20 @@ idna = ["idna (>=3.6)"] trio = ["trio (>=0.23)"] wmi = ["wmi (>=1.5.1)"] +[[package]] +name = "execnet" +version = "2.0.2" +description = "execnet: rapid multi-Python deployment" +optional = false +python-versions = ">=3.7" +files = [ + {file = "execnet-2.0.2-py3-none-any.whl", hash = "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41"}, + {file = "execnet-2.0.2.tar.gz", hash = "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af"}, +] + +[package.extras] +testing = ["hatch", "pre-commit", "pytest", "tox"] + [[package]] name = "idna" version = "3.6" @@ -1265,6 +1279,26 @@ pluggy = ">=0.12,<2.0" [package.extras] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +[[package]] +name = "pytest-xdist" +version = "3.5.0" +description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-xdist-3.5.0.tar.gz", hash = "sha256:cbb36f3d67e0c478baa57fa4edc8843887e0f6cfc42d677530a36d7472b32d8a"}, + {file = "pytest_xdist-3.5.0-py3-none-any.whl", hash = "sha256:d075629c7e00b611df89f490a5063944bee7a4362a5ff11c7cc7824a03dfce24"}, +] + +[package.dependencies] +execnet = ">=1.1" +pytest = ">=6.2.0" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + [[package]] name = "python-dateutil" version = "2.8.2" @@ -1631,4 +1665,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "5e6e8cea599dfb77f6f84ab86fd54b669b91ed8493477e6543c3f73fc8205870" +content-hash = "439e63dbd47f423a004ae1c87b28b1b72b7ab53bbf38d7542a487874ccc444a7" diff --git a/tests/pyproject.toml b/tests/pyproject.toml index c97c7514e..df0040308 100644 --- a/tests/pyproject.toml +++ b/tests/pyproject.toml @@ -15,6 +15,7 @@ pylance = "^0.9.6" ruff = "0.1.14" dbt-core = "^1.7.7" dbt-postgres = "^1.7.7" +pytest-xdist = "^3.5.0" [build-system] requires = ["poetry-core"]