Skip to content

Commit

Permalink
Merge pull request #1 from draganbjedov/basic_itf_setup
Browse files Browse the repository at this point in the history
Basic ITF setup
  • Loading branch information
ltekieli authored Jan 29, 2025
2 parents 1456fac + 32990fe commit d70be98
Show file tree
Hide file tree
Showing 24 changed files with 329 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .bazeliskrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# BAZELISK_BASE_URL=https://github.com/aspect-build/aspect-cli/releases/download
# USE_BAZEL_VERSION=aspect/5.9.36
3 changes: 3 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
common --registry=https://bcr.bazel.build

test --test_output=errors
1 change: 1 addition & 0 deletions .bazelversion
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7.4.0
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Bazel
bazel-*
MODULE.bazel.lock
requirements_lock.txt

.ruff_cache

# Rust
rust-project.json
target

# Python creates local caches
__pycache__

# Generated documentation from venv and esbonio
/_build
Empty file added .ruff.toml
Empty file.
36 changes: 36 additions & 0 deletions BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
load("@rules_python//python:defs.bzl", "py_library")
load("@rules_python//python:pip.bzl", "compile_pip_requirements")

compile_pip_requirements(
name = "requirements",
src = "requirements.in",
requirements_txt = "requirements_lock.txt",
)

exports_files([
"main.py",
"pytest.ini",
])

py_library(
name = "itf",
srcs = [
"itf/plugins/docker.py",
],
imports = ["."],
visibility = ["//visibility:public"],
)

test_suite(
name = "format.check",
tests = ["//tools/format:format.check"],
)

alias(
name = "format.fix",
actual = "//tools/format:format.fix",
)

exports_files([
".ruff.toml",
])
54 changes: 54 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
module(
name = "dependix_itf",
version = "0.1",
compatibility_level = 0,
)

###############################################################################
#
# Python version
#
###############################################################################
bazel_dep(name = "rules_python", version = "1.0.0")

PYTHON_VERSION = "3.12"

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
is_default = True,
python_version = PYTHON_VERSION,
)
use_repo(python)

###############################################################################
#
# PIP dependencies
#
###############################################################################
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
pip.parse(
hub_name = "itf_pip",
python_version = PYTHON_VERSION,
requirements_lock = "//:requirements_lock.txt",
)
use_repo(pip, "itf_pip")

###############################################################################
#
# Buildifier dependency
# Provides formatting and linting of Bazel files.
#
###############################################################################
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0")

###############################################################################
#
# Generic linting and formatting rules
#
###############################################################################
bazel_dep(name = "aspect_rules_lint", version = "1.0.0-rc9")
git_override(
module_name = "aspect_rules_lint",
commit = "b5dfbc12754d6698c36d0aaad46183e730dac85c",
remote = "https://github.com/ltekieli/rules_lint.git",
)
48 changes: 46 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,46 @@
# itf
Integration Testing Framework repository
# ITF - Integration Testing Framework

This module implements support for running [pytest](https://docs.pytest.org/en/latest/contents.html) based tests.

## Usage
MODULE.bazel
```
bazel_dep(name = "itf", version = "0.1")
```

BUILD
```
load("@itf//:defs.bzl", "py_itf_test")
py_itf_test(
name = "test_my_first_check",
srcs = [
"test_my_first_check.py"
],
plugins = [
# Specify optional plugins, ex:
"itf.plugins.docker",
]
args = [
# Specify optional arguments, ex:
"--docker-image=alpine:latest",
]
)
```

## Development

### Regenerating pip dependencies
```
$ bazel run //:requirements.update
```

### Running test
```
$ bazel test //test/...
```

Specify additionally:
- ```--test_arg="-s"``` to get stdout/err from pytest
- ```--test_output=all``` to get stdout/err from bazel
- ```--nocache_test_results``` not to cache test runs
Empty file added WORKSPACE
Empty file.
Empty file added bazel/BUILD
Empty file.
38 changes: 38 additions & 0 deletions bazel/py_itf_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""Bazel interface for running pytest"""

load("@itf_pip//:requirements.bzl", "requirement")
load("@rules_python//python:defs.bzl", "py_test")

def py_itf_test(name, srcs, args = [], data = [], plugins = [], **kwargs):
pytest_bootstrap = Label("@dependix_itf//:main.py")
pytest_ini = Label("@dependix_itf//:pytest.ini")

plugins = ["-p %s" % plugin for plugin in plugins]

py_test(
name = name,
srcs = [
pytest_bootstrap,
] + srcs,
main = pytest_bootstrap,
args = args +
["-c $(location %s)" % pytest_ini] +
[
"-p no:cacheprovider",
"--show-capture=no",
] +
plugins +
["$(location %s)" % x for x in srcs],
deps = [
requirement("docker"),
requirement("pytest"),
"@dependix_itf//:itf",
],
data = [
pytest_ini,
] + data,
env = {
"PYTHONDONOTWRITEBYTECODE": "1",
},
**kwargs
)
3 changes: 3 additions & 0 deletions cli/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# lint:
# aspects:
# - //tools/lint:linters.bzl%ruff
5 changes: 5 additions & 0 deletions defs.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""ITF public Bazel interface"""

load("@dependix_itf//bazel:py_itf_test.bzl", local_py_itf_test = "py_itf_test")

py_itf_test = local_py_itf_test
40 changes: 40 additions & 0 deletions itf/plugins/docker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import logging
import subprocess
import docker as pypi_docker
import pytest


logger = logging.getLogger(__name__)


def pytest_addoption(parser):
parser.addoption(
"--docker-image",
action="store",
required=True,
help="Docker image to run tests against.",
)
parser.addoption(
"--docker-image-bootstrap",
action="store",
required=False,
help="Docker image bootstrap command, that will be executed before referencing the container.",
)


@pytest.fixture()
def docker(request):
docker_image_bootstrap = request.config.getoption("docker_image_bootstrap")
if docker_image_bootstrap:
logger.info(
f"Executing custom image bootstrap command: {docker_image_bootstrap}"
)
subprocess.run([docker_image_bootstrap], check=True)

docker_image = request.config.getoption("docker_image")
client = pypi_docker.from_env()
container = client.containers.run(
docker_image, "sleep infinity", detach=True, auto_remove=True, init=True
)
yield container
container.stop(timeout=1)
7 changes: 7 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import sys
import pytest


if __name__ == "__main__":
args = sys.argv[1:]
sys.exit(pytest.main(args))
12 changes: 12 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[pytest]
log_cli=True
log_cli_level=Debug
log_cli_format = [%(asctime)s.%(msecs)03d] [%(levelname)-3s] [%(name)s] %(message)s
log_cli_date_format = %Y-%m-%d %H:%M:%S

log_format = [%(asctime)s.%(msecs)03d] [%(levelname)-3s] [%(name)s] %(message)s
log_date_format = %Y-%m-%d %H:%M:%S

log_file_level=Debug
log_file_format = [%(asctime)s.%(msecs)03d] [%(levelname)-3s] [%(name)s] %(message)s
log_file_date_format = %Y-%m-%d %H:%M:%S
4 changes: 4 additions & 0 deletions requirements.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
--extra-index-url https://pypi.org/simple/

docker==7.1.0
pytest==8.3.3
22 changes: 22 additions & 0 deletions test/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
load("//:defs.bzl", "py_itf_test")

py_itf_test(
name = "test_rules_are_working_correctly",
srcs = [
"conftest.py",
"test_rules_are_working_correctly.py",
],
)

py_itf_test(
name = "test_docker",
srcs = [
"test_docker.py",
],
args = [
"--docker-image=ubuntu:24.04",
],
plugins = [
"itf.plugins.docker",
],
)
6 changes: 6 additions & 0 deletions test/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import pytest


@pytest.fixture()
def fixture42():
yield 42
3 changes: 3 additions & 0 deletions test/test_docker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def test_docker_runs(docker):
exit_code, output = docker.exec_run("echo -n Hello, World!")
assert "Hello, World!" == output.decode()
2 changes: 2 additions & 0 deletions test/test_rules_are_working_correctly.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def test_local_fixture_has_correct_value(fixture42):
assert 42 == fixture42
21 changes: 21 additions & 0 deletions tools/format/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
load("@aspect_rules_lint//format:defs.bzl", "format_multirun", "format_test")

format_multirun(
name = "format.fix",
python = "@aspect_rules_lint//format:ruff",
starlark = "@buildifier_prebuilt//:buildifier",
visibility = [
"//visibility:public",
],
)

format_test(
name = "format.check",
no_sandbox = True,
python = "@aspect_rules_lint//format:ruff",
starlark = "@buildifier_prebuilt//:buildifier",
visibility = [
"//visibility:public",
],
workspace = "//:.ruff.toml",
)
Empty file added tools/lint/BUILD
Empty file.
8 changes: 8 additions & 0 deletions tools/lint/linters.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# load("@aspect_rules_lint//lint:ruff.bzl", "lint_ruff_aspect")

# ruff = lint_ruff_aspect(
# binary = "@multitool//tools/ruff",
# configs = [
# "@@//:.ruff.toml",
# ],
# )

0 comments on commit d70be98

Please sign in to comment.