Skip to content

Commit a4d4104

Browse files
committed
Testing: Demonstrate Python test layer implementations
The patch demonstrates the whole matrix of building test harnesses with Python, using both unittest and pytest, with and without "Testcontainers for Python". It only exercises basic features of the corresponding test adapters. Demonstrating advanced features like test layer parameterization can be added on behalf of subsequent iterations.
1 parent cf2bf38 commit a4d4104

File tree

15 files changed

+334
-0
lines changed

15 files changed

+334
-0
lines changed

.github/dependabot.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,13 @@ updates:
103103
package-ecosystem: "gradle"
104104
schedule:
105105
interval: "weekly"
106+
107+
- directory: "/testing/testcontainers/python-pytest"
108+
package-ecosystem: "pip"
109+
schedule:
110+
interval: "weekly"
111+
112+
- directory: "/testing/testcontainers/python-unittest"
113+
package-ecosystem: "pip"
114+
schedule:
115+
interval: "weekly"
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: Native Testing with Python
2+
3+
on:
4+
pull_request:
5+
branches: ~
6+
paths:
7+
- '.github/workflows/testing-native-python.yml'
8+
- 'testing/native/python**'
9+
- 'requirements.txt'
10+
push:
11+
branches: [ main ]
12+
paths:
13+
- '.github/workflows/testing-native-python.yml'
14+
- 'testing/native/python**'
15+
- 'requirements.txt'
16+
17+
# Allow job to be triggered manually.
18+
workflow_dispatch:
19+
20+
# Run job each night after CrateDB nightly has been published.
21+
schedule:
22+
- cron: '0 3 * * *'
23+
24+
# Cancel in-progress jobs when pushing to the same branch.
25+
concurrency:
26+
cancel-in-progress: true
27+
group: ${{ github.workflow }}-${{ github.ref }}
28+
29+
jobs:
30+
test:
31+
name: "
32+
Python: ${{ matrix.python-version }}
33+
CrateDB: ${{ matrix.cratedb-version }}
34+
on ${{ matrix.os }}"
35+
runs-on: ${{ matrix.os }}
36+
strategy:
37+
fail-fast: false
38+
matrix:
39+
os: [ 'ubuntu-latest', 'macos-latest' ]
40+
python-version: [ '3.7', '3.11' ]
41+
cratedb-version: [ 'nightly' ]
42+
43+
steps:
44+
45+
- name: Acquire sources
46+
uses: actions/checkout@v4
47+
48+
- name: Set up Python
49+
uses: actions/setup-python@v5
50+
with:
51+
python-version: ${{ matrix.python-version }}
52+
architecture: x64
53+
cache: 'pip'
54+
cache-dependency-path: |
55+
requirements.txt
56+
testing/native/python-pytest/requirements.txt
57+
testing/native/python-unittest/requirements.txt
58+
59+
- name: Install utilities
60+
run: |
61+
pip install -r requirements.txt
62+
63+
- name: Validate testing/native/python-{pytest,unittest}
64+
run: |
65+
ngr test --accept-no-venv testing/native/python-pytest
66+
ngr test --accept-no-venv testing/native/python-unittest
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: Testcontainers for Python
2+
3+
on:
4+
pull_request:
5+
branches: ~
6+
paths:
7+
- '.github/workflows/testing-testcontainers-python.yml'
8+
- 'testing/testcontainers/python**'
9+
- 'requirements.txt'
10+
push:
11+
branches: [ main ]
12+
paths:
13+
- '.github/workflows/testing-testcontainers-python.yml'
14+
- 'testing/testcontainers/python**'
15+
- 'requirements.txt'
16+
17+
# Allow job to be triggered manually.
18+
workflow_dispatch:
19+
20+
# Run job each night after CrateDB nightly has been published.
21+
schedule:
22+
- cron: '0 3 * * *'
23+
24+
# Cancel in-progress jobs when pushing to the same branch.
25+
concurrency:
26+
cancel-in-progress: true
27+
group: ${{ github.workflow }}-${{ github.ref }}
28+
29+
jobs:
30+
test:
31+
name: "
32+
Python: ${{ matrix.python-version }}
33+
CrateDB: ${{ matrix.cratedb-version }}
34+
on ${{ matrix.os }}"
35+
runs-on: ${{ matrix.os }}
36+
strategy:
37+
fail-fast: false
38+
matrix:
39+
os: [ 'ubuntu-latest' ]
40+
python-version: [ '3.7', '3.12' ]
41+
cratedb-version: [ 'nightly' ]
42+
43+
steps:
44+
45+
- name: Acquire sources
46+
uses: actions/checkout@v4
47+
48+
- name: Set up Python
49+
uses: actions/setup-python@v5
50+
with:
51+
python-version: ${{ matrix.python-version }}
52+
architecture: x64
53+
cache: 'pip'
54+
cache-dependency-path: |
55+
requirements.txt
56+
testing/testcontainers/python-pytest/requirements.txt
57+
testing/testcontainers/python-unittest/requirements.txt
58+
59+
- name: Install utilities
60+
run: |
61+
pip install -r requirements.txt
62+
63+
- name: Validate testing/testcontainers/python-{pytest,unittest}
64+
run: |
65+
ngr test --accept-no-venv testing/testcontainers/python-pytest
66+
ngr test --accept-no-venv testing/testcontainers/python-unittest
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[tool.pytest.ini_options]
2+
minversion = "2.0"
3+
addopts = """
4+
-rsfEX -p pytester --strict-markers --verbosity=3
5+
--capture=no
6+
"""
7+
log_level = "DEBUG"
8+
log_cli_level = "DEBUG"
9+
testpaths = ["*.py"]
10+
xfail_strict = true
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
crash==0.31.2
2+
pytest<9
3+
pytest-crate==0.3.0
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""
2+
Using "pytest-crate" with CrateDB and pytest
3+
4+
Build test harnesses around CrateDB using the `crate` pytest fixture
5+
exported by `pytest-crate`. In turn, this is using `CrateNode`
6+
exported by `cr8`.
7+
8+
https://pypi.org/project/pytest-crate/
9+
https://pypi.org/project/cr8/
10+
"""
11+
import subprocess
12+
13+
SQL_STATEMENT = "SELECT * FROM sys.summits ORDER BY height DESC LIMIT 3;"
14+
15+
16+
def test_crash(crate):
17+
"""
18+
After provisioning a test instance of CrateDB, invoke `crash`.
19+
"""
20+
http_url = crate.dsn()
21+
command = f"time crash --hosts '{http_url}' --command 'SELECT * FROM sys.summits ORDER BY height DESC LIMIT 3;'"
22+
subprocess.check_call(command, shell=True)
23+
24+
25+
def test_crate(crate):
26+
assert crate.dsn().startswith("http://127.0.0.1:42")
27+
assert "http" in crate.addresses
28+
assert crate.addresses["http"].host == "127.0.0.1"
29+
assert 4300 > crate.addresses["http"].port >= 4200
30+
assert "psql" in crate.addresses
31+
assert crate.addresses["psql"].host == "127.0.0.1"
32+
assert 5500 > crate.addresses["psql"].port >= 5432
33+
assert "transport" in crate.addresses
34+
assert crate.addresses["transport"].host == "127.0.0.1"
35+
assert 4400 > crate.addresses["transport"].port >= 4300
36+
37+
38+
def test_cursor(crate_cursor):
39+
crate_cursor.execute("SELECT 1")
40+
assert crate_cursor.fetchone() == [1]
41+
42+
43+
def test_execute(crate_execute, crate_cursor):
44+
for stmt in [
45+
"CREATE TABLE pytest (name STRING, version INT)",
46+
"INSERT INTO pytest (name, version) VALUES ('test_execute', 1)",
47+
"REFRESH TABLE pytest",
48+
]:
49+
crate_execute(stmt)
50+
crate_cursor.execute("SELECT name, version FROM pytest")
51+
assert crate_cursor.fetchall() == [["test_execute", 1]]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
python-unittest
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
cr8==0.25.0
2+
crash==0.31.2
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""
2+
Using "cr8" with CrateDB and unittest
3+
4+
Build test harnesses around CrateDB using the `create_node`
5+
primitive exported by `cr8`.
6+
7+
https://pypi.org/project/cr8/
8+
"""
9+
import subprocess
10+
from unittest import TestCase
11+
12+
from cr8.run_crate import create_node
13+
14+
# Run a testing instance of CrateDB.
15+
# TODO: How to select a nightly release?
16+
cratedb_layer = create_node(version="latest-testing")
17+
18+
SQL_STATEMENT = "SELECT * FROM sys.summits ORDER BY height DESC LIMIT 3;"
19+
20+
21+
def setUpModule():
22+
cratedb_layer.start()
23+
24+
25+
def tearDownModule():
26+
cratedb_layer.stop()
27+
28+
29+
class CrashTest(TestCase):
30+
31+
def test_crash(self):
32+
"""
33+
After provisioning a test instance of CrateDB, invoke `crash`.
34+
"""
35+
http_url = cratedb_layer.http_url
36+
command = f"time crash --hosts '{http_url}' --command '{SQL_STATEMENT}'"
37+
subprocess.check_call(command, shell=True)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[tool.pytest.ini_options]
2+
minversion = "2.0"
3+
addopts = """
4+
-rsfEX -p pytester --strict-markers --verbosity=3
5+
--capture=no
6+
"""
7+
log_level = "DEBUG"
8+
log_cli_level = "DEBUG"
9+
testpaths = ["*.py"]
10+
xfail_strict = true
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
crash==0.31.2
2+
cratedb-toolkit[testing]==0.0.4
3+
pytest<9
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""
2+
Using "Testcontainers for Python" with CrateDB and pytest
3+
4+
Build test harnesses around CrateDB using the `cratedb_service`
5+
pytest fixture exported by `cratedb-toolkit`.
6+
7+
https://pypi.org/project/cratedb-toolkit/
8+
"""
9+
import subprocess
10+
from pprint import pprint
11+
12+
SQL_STATEMENT = "SELECT * FROM sys.summits ORDER BY height DESC LIMIT 3;"
13+
14+
15+
def test_crash(cratedb_service):
16+
"""
17+
After provisioning a test instance of CrateDB, invoke `crash`.
18+
"""
19+
http_url = cratedb_service.get_http_url()
20+
command = f"time crash --hosts '{http_url}' --command '{SQL_STATEMENT}'"
21+
subprocess.check_call(command, shell=True)
22+
23+
24+
def test_sql(cratedb_service):
25+
"""
26+
After provisioning a test instance of CrateDB, invoke an SQL statement.
27+
"""
28+
results = cratedb_service.database.run_sql(SQL_STATEMENT, records=True)
29+
pprint(results)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
python-unittest
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
crash==0.31.2
2+
cratedb-toolkit[testing]==0.0.4
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""
2+
Using "Testcontainers for Python" with CrateDB and unittest
3+
4+
Build test harnesses around CrateDB using the `CrateDBTestAdapter`
5+
exported by `cratedb-toolkit`.
6+
7+
https://pypi.org/project/cratedb-toolkit/
8+
"""
9+
import subprocess
10+
from pprint import pprint
11+
from unittest import TestCase
12+
13+
from cratedb_toolkit.testing.testcontainers.cratedb import CrateDBTestAdapter
14+
15+
cratedb_layer = CrateDBTestAdapter()
16+
17+
SQL_STATEMENT = "SELECT * FROM sys.summits ORDER BY height DESC LIMIT 3;"
18+
19+
20+
def setUpModule():
21+
cratedb_layer.start()
22+
23+
24+
def tearDownModule():
25+
cratedb_layer.stop()
26+
27+
28+
class CrashTest(TestCase):
29+
30+
def test_crash(self):
31+
"""
32+
After provisioning a test instance of CrateDB, invoke `crash`.
33+
"""
34+
http_url = cratedb_layer.get_http_url()
35+
command = f"time crash --hosts '{http_url}' --command '{SQL_STATEMENT}'"
36+
subprocess.check_call(command, shell=True)
37+
38+
def test_sql(self):
39+
"""
40+
After provisioning a test instance of CrateDB, invoke an SQL statement.
41+
"""
42+
results = cratedb_layer.database.run_sql(SQL_STATEMENT, records=True)
43+
pprint(results)

0 commit comments

Comments
 (0)