From 706a12b8e47b29c9273f655836f3be72fc7dd7a5 Mon Sep 17 00:00:00 2001 From: Bryan Joshua Pedini Date: Tue, 25 Aug 2026 13:47:18 +0200 Subject: [PATCH] feat: throwaway netbox deployment for end-to-end testing compose stack modelled on the production netbox deployment (same pinned images, worker, healthchecks) minus traefik: the API is served straight on localhost and nothing survives an e2e-down. --- .gitignore | 1 + e2e/docker-compose.yml | 105 +++++++++++++++++++++++++++++++++++++++++ e2e/env.example | 24 ++++++++++ makefile | 15 +++++- 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 e2e/docker-compose.yml create mode 100644 e2e/env.example diff --git a/.gitignore b/.gitignore index 5ae67fe..c282e79 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ __pycache__/ # Configuration config.yaml +e2e/.env # IDE .idea/ diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml new file mode 100644 index 0000000..8a18543 --- /dev/null +++ b/e2e/docker-compose.yml @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Bryan Joshua Pedini +--- +services: + netbox: &netbox + image: netboxcommunity/netbox:${NETBOX_VERSION}-${NETBOX_DOCKER_VERSION} + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + redis-cache: + condition: service_healthy + environment: + - API_TOKEN_PEPPER_1=${NETBOX_API_TOKEN_PEPPER_1} + - DB_HOST=postgres + - DB_NAME=${PSQL_NAME} + - DB_USER=${PSQL_USER} + - DB_PASSWORD=${PSQL_PASS} + - REDIS_HOST=redis + - REDIS_DATABASE=0 + - REDIS_PASSWORD=${REDIS_PASS} + - REDIS_SSL=false + - REDIS_CACHE_HOST=redis-cache + - REDIS_CACHE_DATABASE=1 + - REDIS_CACHE_PASSWORD=${REDIS_CACHE_PASS} + - REDIS_CACHE_SSL=false + - SECRET_KEY=${NETBOX_SECRET_KEY} + - SKIP_SUPERUSER=false + - SUPERUSER_NAME=${NETBOX_SUPERUSER_NAME} + - SUPERUSER_EMAIL=${NETBOX_SUPERUSER_EMAIL} + - SUPERUSER_PASSWORD=${NETBOX_SUPERUSER_PASS} + healthcheck: + test: curl -f http://localhost:8080/login/ || exit 1 + # first boot runs every migration, give it plenty of headroom + start_period: 600s + timeout: 3s + interval: 15s + ports: + - "127.0.0.1:${NETBOX_HTTP_PORT}:8080" + networks: + - internal + + netbox-worker: + <<: *netbox + command: + - /opt/netbox/venv/bin/python + - /opt/netbox/netbox/manage.py + - rqworker + depends_on: + netbox: + condition: service_healthy + healthcheck: + test: ps -aux | grep -v grep | grep -q rqworker || exit 1 + start_period: 20s + timeout: 3s + interval: 15s + ports: [] + + postgres: + image: postgres:${PSQL_VERSION} + environment: + - POSTGRES_DB=${PSQL_NAME} + - POSTGRES_USER=${PSQL_USER} + - POSTGRES_PASSWORD=${PSQL_PASS} + healthcheck: + test: pg_isready -q -t 2 -d $$POSTGRES_DB -U $$POSTGRES_USER + start_period: 20s + timeout: 30s + interval: 10s + retries: 5 + networks: + - internal + + redis: + image: redis:${REDIS_VERSION} + command: + - sh + - -c + - redis-server --appendonly yes --requirepass $$REDIS_PASSWORD + environment: + - REDIS_PASSWORD=${REDIS_PASS} + healthcheck: &redis-healthcheck + test: '[ $$(redis-cli --pass "$${REDIS_PASSWORD}" ping) = ''PONG'' ]' + start_period: 5s + timeout: 3s + interval: 1s + retries: 5 + networks: + - internal + + redis-cache: + image: redis:${REDIS_VERSION} + command: + - sh + - -c + - redis-server --requirepass $$REDIS_PASSWORD + environment: + - REDIS_PASSWORD=${REDIS_CACHE_PASS} + healthcheck: *redis-healthcheck + networks: + - internal + +networks: + internal: diff --git a/e2e/env.example b/e2e/env.example new file mode 100644 index 0000000..70818d4 --- /dev/null +++ b/e2e/env.example @@ -0,0 +1,24 @@ +# Throwaway credentials for the local e2e stack only, never reuse them. + +# NetBox +NETBOX_DOCKER_VERSION=4.0.2 +NETBOX_VERSION=v4.5.8 +NETBOX_HTTP_PORT=8800 +NETBOX_API_TOKEN_PEPPER_1="e2e-only-pepper-0123456789abcdefghijklmnopqrstuvwxyz-0123456789" +NETBOX_SECRET_KEY="e2e-only-secret-key-0123456789abcdefghijklmnopqrstuvwxyz" +NETBOX_SUPERUSER_NAME=admin +NETBOX_SUPERUSER_EMAIL=admin@example.com +NETBOX_SUPERUSER_PASS=admin-e2e-password + +# PostgreSQL +PSQL_VERSION=18.3-alpine3.22 +PSQL_NAME=netbox +PSQL_USER=netbox +PSQL_PASS=netbox-e2e-password + +# Redis +REDIS_VERSION=8.6.2-alpine3.23 +REDIS_PASS=redis-e2e-password + +# Redis Cache +REDIS_CACHE_PASS=redis-cache-e2e-password diff --git a/makefile b/makefile index 842cbfa..1d2df95 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2026 Bryan Joshua Pedini -.PHONY: help dev-environment test lint lint-fix format clean +.PHONY: help dev-environment test lint lint-fix format clean e2e-up e2e-down test-e2e VENV ?= .venv PYTHON ?= $(VENV)/bin/python @@ -13,6 +13,9 @@ help: @echo " lint-fix run ruff checks and fix what is auto-fixable" @echo " format run the ruff formatter" @echo " clean remove the virtualenv and caches" + @echo " e2e-up start the throwaway NetBox stack for e2e tests" + @echo " e2e-down stop the e2e stack and delete its data" + @echo " test-e2e run the end-to-end tests against the e2e stack" dev-environment: python3 -m venv $(VENV) @@ -31,5 +34,15 @@ lint-fix: format: $(PYTHON) -m ruff format . +e2e-up: + test -f e2e/.env || cp e2e/env.example e2e/.env + docker compose --project-directory e2e --env-file e2e/.env up -d --wait + +e2e-down: + docker compose --project-directory e2e --env-file e2e/.env down -v + +test-e2e: + $(PYTHON) -m pytest e2e + clean: rm -rf $(VENV) .pytest_cache .ruff_cache __pycache__ tests/__pycache__