Skip to content

Commit

Permalink
Test library execution against Clickhouse engine
Browse files Browse the repository at this point in the history
There has been a couple of recent issues in which test execution failed
in certain scenarios (#48 and #53). These weren't caught by the
libraries test as it would require executing actual tests against actual
SQL queries. This commit will add a framework for running these tests
against a running database engine (Clickhouse in the first instance) to
better enable these kinds of bugs to be caught.
  • Loading branch information
smoothml committed Apr 10, 2024
1 parent ac7d079 commit f99c2e5
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 1 deletion.
10 changes: 10 additions & 0 deletions .github/workflows/test-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ jobs:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11"]
services:
clickhouse:
image: clickhouse/clickhouse-server:24.1.5.6
ports:
- 8123:8123
- 9000:9000

steps:
- uses: actions/checkout@v3
Expand All @@ -36,5 +42,9 @@ jobs:
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
poetry run flake8 . --count --exit-zero --max-complexity=10 --max-line-length=119 --statistics --ignore E203,E266,E501,W503
- name: Test with pytest
env:
SQL_MOCK_CLICKHOUSE_HOST: 127.0.0.1
SQL_MOCK_CLICKHOUSE_PORT: 8123
SQL_MOCK_CLICKHOUSE_USER: default
run: |
poetry run pytest tests/
18 changes: 18 additions & 0 deletions CONTRIBUTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,24 @@ We use [pytest](https://docs.pytest.org/en/latest/) for running tests. You can r
poetry run pytest tests/
```

There are two types of tests: those testing the internal functions and methods of the library and those testing the test execution with example queries. The latter require a running database instance to be available (either locally or remotely). Note, integration testing is currently only supported for Clickhouse. You can run internal testing only with:

```bash
poetry run pytest -m "not integration" tests/
```

Running integration tests locally requires [Docker](https://www.docker.com/) and [Docker Compose](https://docs.docker.com/compose/). First, start the local database services with:

```bash
docker compose up -d
```

Then you can run integration tests with:

```bash
poetry run pytest -m "integration" tests/
```

### 5. Environment Variables

If you're working with database-specific sections (e.g., BigQuery or ClickHouse), make sure to set the required environment variables for your chosen database. Refer to the respective "Usage" sections for details on these variables.
Expand Down
10 changes: 10 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
services:
clickhouse:
image: clickhouse/clickhouse-server:24.1.5.6
ports:
- 8123:8123
- 9000:9000
ulimits:
nofile:
soft: "262144"
hard: "262144"
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,12 @@ flake8 = "^6.1.0"
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

# Ignore Google Bigquery namespace deprecation warnings
[tool.pytest.ini_options]
# Ignore Google Bigquery namespace deprecation warnings
filterwarnings = [
"ignore:Deprecated call to `pkg_resources\\.declare_namespace\\('.*'\\):DeprecationWarning",
"ignore::DeprecationWarning:google.rpc",
]
markers = [
"integration: Integration tests requiring running database instances"
]
57 changes: 57 additions & 0 deletions tests/sql_mock/clickhouse/test_query_execution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import os

import pytest

from sql_mock.clickhouse import column_mocks as col
from sql_mock.clickhouse.table_mocks import ClickHouseTableMock
from sql_mock.table_mocks import table_meta

pytestmark = pytest.mark.integration


@pytest.fixture(autouse=True)
def set_env():
if not os.getenv("SQL_MOCK_CLICKHOUSE_HOST"):
os.environ["SQL_MOCK_CLICKHOUSE_HOST"] = "localhost"
if not os.getenv("SQL_MOCK_CLICKHOUSE_PORT"):
os.environ["SQL_MOCK_CLICKHOUSE_PORT"] = "8123"
if not os.getenv("SQL_MOCK_CLICKHOUSE_USER"):
os.environ["SQL_MOCK_CLICKHOUSE_USER"] = "default"
if not os.getenv("SQL_MOCK_CLICKHOUSE_PASSWORD"):
os.environ["SQL_MOCK_CLICKHOUSE_PASSWORD"] = ""


def test_simple_query():
query = """SELECT
user_id,
count() AS sessions
FROM sessions
GROUP BY user_id
"""

@table_meta(table_ref="sessions")
class SessionsMock(ClickHouseTableMock):
user_id = col.String(default="foo")

@table_meta(query=query)
class ResultMock(ClickHouseTableMock):
user_id = col.String(default="foo")
sessions = col.Int(default=0)

sessions_mock = SessionsMock.from_dicts(
[
{"user_id": "a"},
{"user_id": "a"},
{"user_id": "a"},
{"user_id": "b"},
],
)

result = ResultMock.from_mocks(input_data=[sessions_mock])

expected = [
{"user_id": "a", "sessions": 3},
{"user_id": "b", "sessions": 1},
]

result.assert_equal(expected)

0 comments on commit f99c2e5

Please sign in to comment.