Skip to content

Commit 8203173

Browse files
committed
Tests: Add software tests and CI/GHA configuration, currently CPython
1 parent 84cbbfb commit 8203173

File tree

9 files changed

+266
-1
lines changed

9 files changed

+266
-1
lines changed

.github/dependabot.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# To get started with Dependabot version updates, you'll need to specify which
2+
# package ecosystems to update and where the package manifests are located.
3+
# Please see the documentation for all configuration options:
4+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5+
6+
version: 2
7+
updates:
8+
- package-ecosystem: "pip" # See documentation for possible values
9+
directory: "/" # Location of package manifests
10+
schedule:
11+
interval: "weekly"
12+
13+
- package-ecosystem: "github-actions"
14+
directory: "/"
15+
schedule:
16+
interval: "monthly"

.github/workflows/tests.yml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: "Tests"
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request: ~
7+
workflow_dispatch:
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
15+
test-cpython:
16+
name: "
17+
CPython ${{ matrix.python-version }}
18+
"
19+
runs-on: ${{ matrix.os }}
20+
strategy:
21+
fail-fast: false
22+
matrix:
23+
os: ['ubuntu-latest']
24+
python-version: ['3.13']
25+
26+
env:
27+
OS: ${{ matrix.os }}
28+
PYTHON: ${{ matrix.python-version }}
29+
30+
services:
31+
cratedb:
32+
image: crate/crate:nightly
33+
ports:
34+
- 4200:4200
35+
36+
steps:
37+
38+
- name: Acquire sources
39+
uses: actions/checkout@v4
40+
41+
- name: Install uv
42+
uses: astral-sh/setup-uv@v3
43+
44+
- name: Set up Python ${{ matrix.python-version }}
45+
uses: actions/setup-python@v5
46+
with:
47+
python-version: ${{ matrix.python-version }}
48+
architecture: x64
49+
cache: 'pip'
50+
cache-dependency-path: |
51+
pyproject.toml
52+
requirements*.txt
53+
54+
- name: Set up project tools
55+
run: uv pip install --system --requirement=requirements.txt --requirement=requirements-dev.txt
56+
57+
- name: Run linters and software tests
58+
run: poe test
59+
60+
# https://github.com/codecov/codecov-action
61+
- name: Upload coverage results to Codecov
62+
uses: codecov/codecov-action@v4
63+
env:
64+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
65+
with:
66+
files: ./coverage.xml
67+
flags: main
68+
env_vars: OS,PYTHON
69+
name: codecov-umbrella
70+
fail_ci_if_error: false

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@
55
.env
66
.idea
77
__pycache__
8+
.coverage*
9+
coverage.xml

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# micropython-cratedb - A CrateDB Driver for MicroPython
22

3+
[![Tests](https://github.com/crate/micropython-cratedb/actions/workflows/tests.yml/badge.svg)](https://github.com/crate/micropython-cratedb/actions/workflows/tests.yml)
4+
35
## Introduction
46

57
micropython-cratedb is a [CrateDB](https://cratedb.com) driver for the [MicroPython](https://micropython.org) language. It connects to CrateDB using the [HTTP Endpoint](https://cratedb.com/docs/crate/reference/en/latest/interfaces/http.html).

examples/picow_demo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
)
8989

9090
if response["rowcount"] == 1:
91-
print(f"Average temperature over last 24hrs: {response["rows"][0][0]}")
91+
print(f"Average temperature over last 24hrs: {response['rows'][0][0]}")
9292
num_iterations = 0
9393

9494
time.sleep(10)

pyproject.toml

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
[tool.ruff]
2+
line-length = 100
3+
4+
extend-exclude = [
5+
]
6+
7+
lint.select = [
8+
# Builtins
9+
"A",
10+
# Bugbear
11+
"B",
12+
# comprehensions
13+
"C4",
14+
# Pycodestyle
15+
"E",
16+
# eradicate
17+
"ERA",
18+
# Pyflakes
19+
"F",
20+
# isort
21+
"I",
22+
# return
23+
"RET",
24+
# Bandit
25+
"S",
26+
# print
27+
"T20",
28+
"W",
29+
# flake8-2020
30+
"YTT",
31+
]
32+
33+
lint.extend-ignore = [
34+
# Unnecessary `elif` after `return` statement
35+
"RET505",
36+
# Probable insecure usage of temporary file or directory
37+
"S108",
38+
# Possible SQL injection vector through string-based query construction
39+
"S608",
40+
]
41+
42+
lint.per-file-ignores."examples/*" = [
43+
"ERA001", # Found commented-out code
44+
"T201", # Allow `print`
45+
]
46+
47+
lint.per-file-ignores."tests/*" = [
48+
"S101", # Allow use of `assert`
49+
]
50+
51+
[tool.pytest.ini_options]
52+
addopts = """
53+
-rfEXs -p pytester --strict-markers --verbosity=3
54+
--cov --cov-report=term-missing --cov-report=xml
55+
"""
56+
minversion = "2.0"
57+
log_level = "DEBUG"
58+
log_cli_level = "DEBUG"
59+
log_format = "%(asctime)-15s [%(name)-36s] %(levelname)-8s: %(message)s"
60+
xfail_strict = true
61+
62+
63+
[tool.coverage.paths2]
64+
source = [
65+
".",
66+
"examples",
67+
]
68+
69+
[tool.coverage.run]
70+
branch = false
71+
source = [
72+
".",
73+
"examples",
74+
]
75+
omit = [
76+
"tests/*",
77+
]
78+
79+
[tool.coverage.report]
80+
fail_under = 0
81+
show_missing = true
82+
exclude_lines = [
83+
"# pragma: no cover",
84+
"raise NotImplemented",
85+
]
86+
87+
88+
# ===================
89+
# Tasks configuration
90+
# ===================
91+
92+
[tool.poe.tasks]
93+
94+
check = [
95+
"lint",
96+
"test",
97+
]
98+
99+
format = [
100+
{ cmd = "ruff format ." },
101+
# Configure Ruff not to auto-fix (remove!):
102+
# unused imports (F401), unused variables (F841), `print` statements (T201), and commented-out code (ERA001).
103+
{ cmd = "ruff check --fix --ignore=ERA --ignore=F401 --ignore=F841 --ignore=T20 --ignore=ERA001 ." },
104+
{ cmd = "pyproject-fmt --keep-full-version pyproject.toml" },
105+
]
106+
107+
lint = [
108+
{ cmd = "ruff format --check ." },
109+
{ cmd = "ruff check ." },
110+
{ cmd = "validate-pyproject pyproject.toml" },
111+
]
112+
113+
114+
[tool.poe.tasks.test]
115+
cmd = "pytest"
116+
help = "Invoke software tests"
117+
118+
[tool.poe.tasks.test.args.expression]
119+
options = [ "-k" ]
120+
121+
[tool.poe.tasks.test.args.marker]
122+
options = [ "-m" ]

requirements-dev.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
poethepoet
2+
pyproject-fmt<3
3+
pytest<9
4+
pytest-cov<7
5+
ruff<0.8
6+
validate-pyproject<0.23

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
requests

tests/test_examples.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import os
2+
import subprocess
3+
from pathlib import Path
4+
5+
import pytest
6+
7+
8+
@pytest.fixture(autouse=True)
9+
def boot():
10+
"""
11+
Add current working dir to Python module search path.
12+
13+
This is needed to make the interpreter pick up `cratedb.py`
14+
in the top-level directory.
15+
"""
16+
os.environ["PYTHONPATH"] = str(Path.cwd())
17+
18+
19+
def test_example_usage(capfd):
20+
"""
21+
Validate `examples/example_usage.py` runs to completion.
22+
"""
23+
subprocess.check_call(["python", "examples/example_usage.py"])
24+
out, err = capfd.readouterr()
25+
assert "Create table" in out
26+
assert "Drop table" in out
27+
28+
29+
def test_object_examples(capfd):
30+
"""
31+
Validate `examples/object_examples.py` runs to completion.
32+
"""
33+
subprocess.check_call(["python", "examples/object_examples.py"])
34+
out, err = capfd.readouterr()
35+
assert "Create table" in out
36+
assert "Drop table" in out
37+
38+
39+
def test_picow_demo(capfd):
40+
"""
41+
Validate `examples/picow_demo.py` fails, because it needs real hardware.
42+
"""
43+
returncode = subprocess.call(["python", "examples/picow_demo.py"])
44+
assert returncode == 1
45+
out, err = capfd.readouterr()
46+
assert "ModuleNotFoundError: No module named 'machine'" in err

0 commit comments

Comments
 (0)