mirror of
https://github.com/jazzband/django-auditlog.git
synced 2026-03-16 22:20:26 +00:00
Extend CI and local test coverage to MySQL and SQLite (#744)
* Add test runner and improve test with multi databases * Enhance cross-database compatibility and testing - Fix TRUNCATE command support detection for different databases - Add conditional PostgreSQL-specific model registration - Improve database-specific test skipping logic - Remove SQLite from TRUNCATE supported vendors list * Add docker compose for testing * Improve CI/CD with multi-database support - Add separate test workflows for SQLite, PostgreSQL, and MySQL * Add `mysqlclient` deps * fix minor - Add mysqlclient deps - upload coverage step * Fix coverage upload name conflicts in CI workflow - Add database type to coverage upload names (SQLite/PostgreSQL/MySQL)
This commit is contained in:
parent
9ef8cf2476
commit
8003b069c9
14 changed files with 385 additions and 116 deletions
30
.github/actions/setup-python-deps/action.yml
vendored
Normal file
30
.github/actions/setup-python-deps/action.yml
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
name: 'Setup Python and Dependencies'
|
||||
description: 'Common setup steps for Python and pip dependencies'
|
||||
|
||||
inputs:
|
||||
python-version:
|
||||
description: 'Python version to setup'
|
||||
required: true
|
||||
cache-key-prefix:
|
||||
description: 'Prefix for pip cache key'
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Set up Python ${{ inputs.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ inputs.cache-key-prefix }}-${{ inputs.python-version }}-${{ hashFiles('**/pyproject.toml') }}
|
||||
|
||||
- name: Install Python dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade tox tox-gh-actions
|
||||
124
.github/workflows/test.yml
vendored
124
.github/workflows/test.yml
vendored
|
|
@ -3,67 +3,125 @@ name: Test
|
|||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
test-sqlite:
|
||||
name: SQLite • Python ${{ matrix.python-version }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 5
|
||||
matrix:
|
||||
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python and dependencies
|
||||
uses: ./.github/actions/setup-python-deps
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache-key-prefix: sqlite3
|
||||
|
||||
- name: Run tests
|
||||
env:
|
||||
TEST_DB_BACKEND: sqlite3
|
||||
run: tox -v
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
name: SQLite • Python ${{ matrix.python-version }}
|
||||
|
||||
test-postgres:
|
||||
name: PostgreSQL • Python ${{ matrix.python-version }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:14
|
||||
image: postgres:15
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: postgres
|
||||
POSTGRES_DB: auditlog
|
||||
ports:
|
||||
- 5432/tcp
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
--health-retries 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
- name: Setup Python and dependencies
|
||||
uses: ./.github/actions/setup-python-deps
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache-key-prefix: postgresql
|
||||
|
||||
- name: Get pip cache dir
|
||||
id: pip-cache
|
||||
run: |
|
||||
echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.pip-cache.outputs.dir }}
|
||||
key:
|
||||
-${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.py') }}
|
||||
restore-keys: |
|
||||
-${{ matrix.python-version }}-v1-
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade tox tox-gh-actions
|
||||
|
||||
- name: Tox tests
|
||||
run: |
|
||||
tox -v
|
||||
- name: Run tests
|
||||
env:
|
||||
TEST_DB_BACKEND: postgresql
|
||||
TEST_DB_HOST: localhost
|
||||
TEST_DB_USER: postgres
|
||||
TEST_DB_PASS: postgres
|
||||
TEST_DB_NAME: postgres
|
||||
TEST_DB_NAME: auditlog
|
||||
TEST_DB_PORT: ${{ job.services.postgres.ports[5432] }}
|
||||
|
||||
run: tox -v
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
name: Python ${{ matrix.python-version }}
|
||||
name: PostgreSQL • Python ${{ matrix.python-version }}
|
||||
|
||||
test-mysql:
|
||||
name: MySQL • Python ${{ matrix.python-version }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
env:
|
||||
MYSQL_DATABASE: auditlog
|
||||
MYSQL_USER: mysql
|
||||
MYSQL_PASSWORD: mysql
|
||||
MYSQL_ROOT_PASSWORD: mysql
|
||||
ports:
|
||||
- 3306/tcp
|
||||
options: >-
|
||||
--health-cmd="sh -c 'export MYSQL_PWD=\"$MYSQL_ROOT_PASSWORD\"; mysqladmin ping -h 127.0.0.1 --protocol=TCP -uroot --silent || exit 1'"
|
||||
--health-interval=10s
|
||||
--health-timeout=5s
|
||||
--health-retries=20
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install MySQL client libraries
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libmysqlclient-dev pkg-config mysql-client
|
||||
|
||||
- name: Setup Python and dependencies
|
||||
uses: ./.github/actions/setup-python-deps
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
cache-key-prefix: mysql
|
||||
|
||||
- name: Run tests
|
||||
env:
|
||||
TEST_DB_BACKEND: mysql
|
||||
TEST_DB_HOST: 127.0.0.1
|
||||
TEST_DB_USER: root
|
||||
TEST_DB_PASS: mysql
|
||||
TEST_DB_NAME: auditlog
|
||||
TEST_DB_PORT: ${{ job.services.mysql.ports[3306] }}
|
||||
run: tox -v
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
name: MySQL • Python ${{ matrix.python-version }}
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ class Command(BaseCommand):
|
|||
|
||||
|
||||
class TruncateQuery:
|
||||
SUPPORTED_VENDORS = ("postgresql", "mysql", "sqlite", "oracle", "microsoft")
|
||||
SUPPORTED_VENDORS = ("postgresql", "mysql", "oracle", "microsoft")
|
||||
|
||||
@classmethod
|
||||
def support_truncate_statement(cls, database_vendor) -> bool:
|
||||
|
|
|
|||
47
auditlog_tests/docker-compose.yml
Normal file
47
auditlog_tests/docker-compose.yml
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
services:
|
||||
postgres:
|
||||
container_name: auditlog_postgres
|
||||
image: postgres:15
|
||||
restart: "no"
|
||||
environment:
|
||||
POSTGRES_DB: auditlog
|
||||
POSTGRES_USER: ${TEST_DB_USER}
|
||||
POSTGRES_PASSWORD: ${TEST_DB_PASS}
|
||||
ports:
|
||||
- "${TEST_DB_PORT:-5432}:5432"
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: pg_isready -U ${TEST_DB_USER} -d auditlog
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
|
||||
mysql:
|
||||
container_name: auditlog_mysql
|
||||
platform: linux/x86_64
|
||||
image: mysql:8.0
|
||||
restart: "no"
|
||||
environment:
|
||||
MYSQL_DATABASE: auditlog
|
||||
MYSQL_USER: ${TEST_DB_USER}
|
||||
MYSQL_PASSWORD: ${TEST_DB_PASS}
|
||||
MYSQL_ROOT_PASSWORD: ${TEST_DB_PASS}
|
||||
ports:
|
||||
- "${TEST_DB_PORT:-3306}:3306"
|
||||
expose:
|
||||
- '${TEST_DB_PORT:-3306}'
|
||||
volumes:
|
||||
- mysql-data:/var/lib/mysql
|
||||
- ./docker/db/init-mysql.sh:/docker-entrypoint-initdb.d/init.sh
|
||||
healthcheck:
|
||||
test: mysqladmin ping -h 127.0.0.1 -u ${TEST_DB_USER} --password=${TEST_DB_PASS}
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
driver: local
|
||||
mysql-data:
|
||||
driver: local
|
||||
6
auditlog_tests/docker/db/init-mysql.sh
Executable file
6
auditlog_tests/docker/db/init-mysql.sh
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
mysql -u root -p"$MYSQL_ROOT_PASSWORD" <<-EOSQL
|
||||
GRANT ALL PRIVILEGES ON test_auditlog.* to '$MYSQL_USER';
|
||||
EOSQL
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import uuid
|
||||
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
from django.conf import settings
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.db import models
|
||||
|
||||
|
|
@ -311,7 +311,11 @@ class CharfieldTextfieldModel(models.Model):
|
|||
history = AuditlogHistoryField(delete_related=True)
|
||||
|
||||
|
||||
class PostgresArrayFieldModel(models.Model):
|
||||
# Only define PostgreSQL-specific models when ArrayField is available
|
||||
if settings.TEST_DB_BACKEND == "postgresql":
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
|
||||
class PostgresArrayFieldModel(models.Model):
|
||||
"""
|
||||
Test auditlog with Postgres's ArrayField
|
||||
"""
|
||||
|
|
@ -332,6 +336,12 @@ class PostgresArrayFieldModel(models.Model):
|
|||
|
||||
history = AuditlogHistoryField(delete_related=True)
|
||||
|
||||
else:
|
||||
|
||||
class PostgresArrayFieldModel(models.Model):
|
||||
class Meta:
|
||||
managed = False
|
||||
|
||||
|
||||
class NoDeleteHistoryModel(models.Model):
|
||||
integer = models.IntegerField(blank=True, null=True)
|
||||
|
|
@ -448,7 +458,8 @@ auditlog.register(AdditionalDataIncludedModel)
|
|||
auditlog.register(DateTimeFieldModel)
|
||||
auditlog.register(ChoicesFieldModel)
|
||||
auditlog.register(CharfieldTextfieldModel)
|
||||
auditlog.register(PostgresArrayFieldModel)
|
||||
if settings.TEST_DB_BACKEND == "postgresql":
|
||||
auditlog.register(PostgresArrayFieldModel)
|
||||
auditlog.register(NoDeleteHistoryModel)
|
||||
auditlog.register(JSONModel)
|
||||
auditlog.register(NullableJSONModel)
|
||||
|
|
|
|||
|
|
@ -6,9 +6,13 @@ from unittest import mock
|
|||
|
||||
import freezegun
|
||||
from django.core.management import call_command
|
||||
from django.db import connection
|
||||
from django.test import TestCase, TransactionTestCase
|
||||
from django.test.utils import skipIf
|
||||
from test_app.models import SimpleModel
|
||||
|
||||
from auditlog.management.commands.auditlogflush import TruncateQuery
|
||||
|
||||
|
||||
class AuditlogFlushTest(TestCase):
|
||||
def setUp(self):
|
||||
|
|
@ -139,6 +143,10 @@ class AuditlogFlushWithTruncateTest(TransactionTestCase):
|
|||
)
|
||||
self.assertEqual(err, "", msg="No stderr")
|
||||
|
||||
@skipIf(
|
||||
not TruncateQuery.support_truncate_statement(connection.vendor),
|
||||
"Database does not support TRUNCATE",
|
||||
)
|
||||
def test_flush_with_truncate_and_yes(self):
|
||||
obj = self.make_object()
|
||||
self.assertEqual(obj.history.count(), 1, msg="There is one log entry.")
|
||||
|
|
@ -152,6 +160,10 @@ class AuditlogFlushWithTruncateTest(TransactionTestCase):
|
|||
)
|
||||
self.assertEqual(err, "", msg="No stderr")
|
||||
|
||||
@skipIf(
|
||||
not TruncateQuery.support_truncate_statement(connection.vendor),
|
||||
"Database does not support TRUNCATE",
|
||||
)
|
||||
def test_flush_with_truncate_with_input_yes(self):
|
||||
obj = self.make_object()
|
||||
self.assertEqual(obj.history.count(), 1, msg="There is one log entry.")
|
||||
|
|
|
|||
51
auditlog_tests/test_postgresql.py
Normal file
51
auditlog_tests/test_postgresql.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
"""
|
||||
PostgreSQL-specific tests for django-auditlog.
|
||||
"""
|
||||
|
||||
from unittest import skipIf
|
||||
|
||||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from test_app.models import PostgresArrayFieldModel
|
||||
|
||||
|
||||
@skipIf(settings.TEST_DB_BACKEND != "postgresql", "PostgreSQL-specific test")
|
||||
class PostgresArrayFieldModelTest(TestCase):
|
||||
databases = "__all__"
|
||||
|
||||
def setUp(self):
|
||||
self.obj = PostgresArrayFieldModel.objects.create(
|
||||
arrayfield=[PostgresArrayFieldModel.RED, PostgresArrayFieldModel.GREEN],
|
||||
)
|
||||
|
||||
@property
|
||||
def latest_array_change(self):
|
||||
return self.obj.history.latest().changes_display_dict["arrayfield"][1]
|
||||
|
||||
def test_changes_display_dict_arrayfield(self):
|
||||
self.assertEqual(
|
||||
self.latest_array_change,
|
||||
"Red, Green",
|
||||
msg="The human readable text for the two choices, 'Red, Green' is displayed.",
|
||||
)
|
||||
self.obj.arrayfield = [PostgresArrayFieldModel.GREEN]
|
||||
self.obj.save()
|
||||
self.assertEqual(
|
||||
self.latest_array_change,
|
||||
"Green",
|
||||
msg="The human readable text 'Green' is displayed.",
|
||||
)
|
||||
self.obj.arrayfield = []
|
||||
self.obj.save()
|
||||
self.assertEqual(
|
||||
self.latest_array_change,
|
||||
"",
|
||||
msg="The human readable text '' is displayed.",
|
||||
)
|
||||
self.obj.arrayfield = [PostgresArrayFieldModel.GREEN]
|
||||
self.obj.save()
|
||||
self.assertEqual(
|
||||
self.latest_array_change,
|
||||
"Green",
|
||||
msg="The human readable text 'Green' is displayed.",
|
||||
)
|
||||
|
|
@ -8,6 +8,8 @@ DEBUG = True
|
|||
|
||||
SECRET_KEY = "test"
|
||||
|
||||
TEST_DB_BACKEND = os.getenv("TEST_DB_BACKEND", "sqlite3")
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
|
|
@ -20,6 +22,7 @@ INSTALLED_APPS = [
|
|||
"test_app",
|
||||
]
|
||||
|
||||
|
||||
MIDDLEWARE = [
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
|
|
@ -28,7 +31,8 @@ MIDDLEWARE = [
|
|||
"auditlog.middleware.AuditlogMiddleware",
|
||||
]
|
||||
|
||||
DATABASES = {
|
||||
if TEST_DB_BACKEND == "postgresql":
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.postgresql",
|
||||
"NAME": os.getenv(
|
||||
|
|
@ -39,7 +43,40 @@ DATABASES = {
|
|||
"HOST": os.getenv("TEST_DB_HOST", "127.0.0.1"),
|
||||
"PORT": os.getenv("TEST_DB_PORT", "5432"),
|
||||
}
|
||||
}
|
||||
}
|
||||
elif TEST_DB_BACKEND == "mysql":
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.mysql",
|
||||
"NAME": os.getenv(
|
||||
"TEST_DB_NAME", "auditlog" + os.environ.get("TOX_PARALLEL_ENV", "")
|
||||
),
|
||||
"USER": os.getenv("TEST_DB_USER", "root"),
|
||||
"PASSWORD": os.getenv("TEST_DB_PASS", ""),
|
||||
"HOST": os.getenv("TEST_DB_HOST", "127.0.0.1"),
|
||||
"PORT": os.getenv("TEST_DB_PORT", "3306"),
|
||||
"OPTIONS": {
|
||||
"charset": "utf8mb4",
|
||||
"init_command": "SET sql_mode='STRICT_TRANS_TABLES'",
|
||||
},
|
||||
}
|
||||
}
|
||||
elif TEST_DB_BACKEND == "sqlite3":
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": os.getenv(
|
||||
"TEST_DB_NAME",
|
||||
(
|
||||
":memory:"
|
||||
if os.getenv("TOX_PARALLEL_ENV")
|
||||
else "test_auditlog.sqlite3"
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
else:
|
||||
raise ValueError(f"Unsupported database backend: {TEST_DB_BACKEND}")
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ import json
|
|||
from io import StringIO
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management import CommandError, call_command
|
||||
from django.test import TestCase, override_settings
|
||||
from django.test.utils import skipIf
|
||||
from test_app.models import SimpleModel
|
||||
|
||||
from auditlog.models import LogEntry
|
||||
|
|
@ -124,6 +126,7 @@ class AuditlogMigrateJsonTest(TestCase):
|
|||
# Assert
|
||||
self.assertEqual(call_count, 2)
|
||||
|
||||
@skipIf(settings.TEST_DB_BACKEND != "postgresql", "PostgreSQL-specific test")
|
||||
def test_native_postgres(self):
|
||||
# Arrange
|
||||
log_entry = self.make_logentry()
|
||||
|
|
@ -136,6 +139,7 @@ class AuditlogMigrateJsonTest(TestCase):
|
|||
self.assertEqual(errbuf, "")
|
||||
self.assertIsNotNone(log_entry.changes)
|
||||
|
||||
@skipIf(settings.TEST_DB_BACKEND != "postgresql", "PostgreSQL-specific test")
|
||||
def test_native_postgres_changes_not_overwritten(self):
|
||||
# Arrange
|
||||
log_entry = self.make_logentry()
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ from test_app.models import (
|
|||
ModelPrimaryKeyModel,
|
||||
NoDeleteHistoryModel,
|
||||
NullableJSONModel,
|
||||
PostgresArrayFieldModel,
|
||||
ProxyModel,
|
||||
RelatedModel,
|
||||
ReusableThroughRelatedModel,
|
||||
|
|
@ -1717,47 +1716,6 @@ class CharFieldTextFieldModelTest(TestCase):
|
|||
)
|
||||
|
||||
|
||||
class PostgresArrayFieldModelTest(TestCase):
|
||||
databases = "__all__"
|
||||
|
||||
def setUp(self):
|
||||
self.obj = PostgresArrayFieldModel.objects.create(
|
||||
arrayfield=[PostgresArrayFieldModel.RED, PostgresArrayFieldModel.GREEN],
|
||||
)
|
||||
|
||||
@property
|
||||
def latest_array_change(self):
|
||||
return self.obj.history.latest().changes_display_dict["arrayfield"][1]
|
||||
|
||||
def test_changes_display_dict_arrayfield(self):
|
||||
self.assertEqual(
|
||||
self.latest_array_change,
|
||||
"Red, Green",
|
||||
msg="The human readable text for the two choices, 'Red, Green' is displayed.",
|
||||
)
|
||||
self.obj.arrayfield = [PostgresArrayFieldModel.GREEN]
|
||||
self.obj.save()
|
||||
self.assertEqual(
|
||||
self.latest_array_change,
|
||||
"Green",
|
||||
msg="The human readable text 'Green' is displayed.",
|
||||
)
|
||||
self.obj.arrayfield = []
|
||||
self.obj.save()
|
||||
self.assertEqual(
|
||||
self.latest_array_change,
|
||||
"",
|
||||
msg="The human readable text '' is displayed.",
|
||||
)
|
||||
self.obj.arrayfield = [PostgresArrayFieldModel.GREEN]
|
||||
self.obj.save()
|
||||
self.assertEqual(
|
||||
self.latest_array_change,
|
||||
"Green",
|
||||
msg="The human readable text 'Green' is displayed.",
|
||||
)
|
||||
|
||||
|
||||
class AdminPanelTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@ django>=4.2,<4.3
|
|||
sphinx
|
||||
sphinx_rtd_theme
|
||||
psycopg2-binary
|
||||
mysqlclient==2.2.5
|
||||
43
runtests.sh
Executable file
43
runtests.sh
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Run tests against all supported databases
|
||||
set -e
|
||||
|
||||
# Default settings
|
||||
export TEST_DB_USER=${TEST_DB_USER:-testuser}
|
||||
export TEST_DB_PASS=${TEST_DB_PASS:-testpass}
|
||||
export TEST_DB_HOST=${TEST_DB_HOST:-127.0.0.1}
|
||||
export TEST_DB_NAME=${TEST_DB_NAME:-auditlog}
|
||||
|
||||
# Cleanup on exit
|
||||
trap 'docker compose -f auditlog_tests/docker-compose.yml down -v --remove-orphans 2>/dev/null || true' EXIT
|
||||
|
||||
echo "Starting containers..."
|
||||
docker compose -f auditlog_tests/docker-compose.yml up -d
|
||||
|
||||
echo "Waiting for databases..."
|
||||
echo "Waiting for PostgreSQL..."
|
||||
until docker compose -f auditlog_tests/docker-compose.yml exec postgres pg_isready -U ${TEST_DB_USER} -d auditlog >/dev/null 2>&1; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Waiting for MySQL..."
|
||||
|
||||
until docker compose -f auditlog_tests/docker-compose.yml exec mysql mysqladmin ping -h 127.0.0.1 -u ${TEST_DB_USER} --password=${TEST_DB_PASS} --silent >/dev/null 2>&1; do
|
||||
sleep 1
|
||||
done
|
||||
echo "Databases ready!"
|
||||
|
||||
# Run tests for each database
|
||||
for backend in sqlite3 postgresql mysql; do
|
||||
echo "Testing $backend..."
|
||||
export TEST_DB_BACKEND=$backend
|
||||
case $backend in
|
||||
postgresql) export TEST_DB_PORT=5432 ;;
|
||||
mysql) export TEST_DB_PORT=3306;;
|
||||
sqlite3) unset TEST_DB_PORT ;;
|
||||
esac
|
||||
tox
|
||||
done
|
||||
|
||||
echo "All tests completed!"
|
||||
15
tox.ini
15
tox.ini
|
|
@ -11,7 +11,7 @@ envlist =
|
|||
|
||||
[testenv]
|
||||
setenv =
|
||||
COVERAGE_FILE={toxworkdir}/.coverage.{envname}
|
||||
COVERAGE_FILE={toxworkdir}/.coverage.{envname}.{env:TEST_DB_BACKEND}
|
||||
changedir = auditlog_tests
|
||||
commands =
|
||||
coverage run --source auditlog ./manage.py test
|
||||
|
|
@ -27,7 +27,10 @@ deps =
|
|||
codecov
|
||||
freezegun
|
||||
psycopg2-binary
|
||||
mysqlclient
|
||||
|
||||
passenv=
|
||||
TEST_DB_BACKEND
|
||||
TEST_DB_HOST
|
||||
TEST_DB_USER
|
||||
TEST_DB_PASS
|
||||
|
|
@ -56,7 +59,15 @@ description = Check for missing migrations
|
|||
changedir = auditlog_tests
|
||||
deps =
|
||||
Django>=4.2
|
||||
psycopg2
|
||||
psycopg2-binary
|
||||
mysqlclient
|
||||
passenv=
|
||||
TEST_DB_BACKEND
|
||||
TEST_DB_HOST
|
||||
TEST_DB_USER
|
||||
TEST_DB_PASS
|
||||
TEST_DB_NAME
|
||||
TEST_DB_PORT
|
||||
commands =
|
||||
python manage.py makemigrations --check --dry-run
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue