Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
services:
Comment thread
RedExtreme12 marked this conversation as resolved.
rabbitmq:
image: rabbitmq:4.3.1-management-alpine
container_name: django-rmq-test
ports:
- "5672:5672" # AMQP — RMQ_PORT
- "15672:15672" # Management HTTP API — RMQ_MGMT_PORT (used by the suite)
healthcheck:
test: [ "CMD", "rabbitmq-diagnostics", "-q", "ping" ]
interval: 10s
timeout: 5s
retries: 10
100 changes: 100 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch:
workflow_call:

permissions:
contents: read

jobs:

# Unit tests across the supported Python versions
unit-test:
runs-on: self-hosted

strategy:
matrix:
python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14" ]
fail-fast: true

steps:
- uses: actions/checkout@v4.2.2

- name: Install uv
uses: astral-sh/setup-uv@v6

- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}

- name: Install dependencies
run: uv sync --group dev --python ${{ matrix.python-version }}

- name: Run tests
run: uv run --python ${{ matrix.python-version }} pytest

- name: Clean up runner artifacts
if: always()
run: |
rm -rf .venv .pytest_cache .ruff_cache .coverage htmlcov
find . -type d -name "__pycache__" -prune -exec rm -rf {} +

# Integration tests against a real RabbitMQ broker (deselected in the unit job)
integration-test:
runs-on: self-hosted

strategy:
matrix:
python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14" ]
rabbitmq-version: [ "3.13", "4.0", "4.1", "4.2", "4.3" ]
fail-fast: true

services:
rabbitmq:
image: rabbitmq:${{ matrix.rabbitmq-version }}-management-alpine
ports:
- 5672:5672
- 15672:15672
options: >-
--health-cmd "rabbitmq-diagnostics -q ping"
--health-interval 10s
--health-timeout 5s
--health-retries 10

env:
RMQ_HOST: localhost
RMQ_PORT: 5672
RMQ_MGMT_PORT: 15672
RMQ_USER: guest
RMQ_PASSWORD: guest
RMQ_VHOST: /

steps:
- uses: actions/checkout@v4.2.2

- name: Install uv
uses: astral-sh/setup-uv@v6

- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}

- name: Install dependencies
run: uv sync --group dev --python ${{ matrix.python-version }}

- name: Run integration tests
run: uv run --python ${{ matrix.python-version }} pytest -m integration

- name: Tear down RabbitMQ and clean up runner artifacts
if: always()
run: |
# Force-remove any RabbitMQ containers left on the runner
docker ps -aq --filter "ancestor=rabbitmq:${{ matrix.rabbitmq-version }}-management-alpine" \
| xargs -r docker rm -fv
docker image rm -f "rabbitmq:${{ matrix.rabbitmq-version }}-management-alpine" || true
# Wipe per-run Python/pytest build artifacts from the persistent workspace.
rm -rf .venv .pytest_cache .ruff_cache .coverage htmlcov
find . -type d -name "__pycache__" -prune -exec rm -rf {} +
28 changes: 4 additions & 24 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,14 @@ permissions:

jobs:

# The testing phase of a package with supported Python versions
test:
runs-on: self-hosted

strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
fail-fast: true

steps:
- uses: actions/checkout@v4.2.2

- name: Install uv
uses: astral-sh/setup-uv@v6

- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}

- name: Install dependencies
run: uv sync --group dev --python ${{ matrix.python-version }}

- name: Run tests
run: uv run --python ${{ matrix.python-version }} pytest
# Run the full test suite (unit + integration) before publishing anything
tests:
uses: ./.github/workflows/ci.yml

# Assemble the package (once, py3-none-any)
release-build:
runs-on: self-hosted
needs: test
Comment thread
Wern-rm marked this conversation as resolved.
needs: tests

steps:
- uses: actions/checkout@v4.2.2
Expand Down
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
[![PyPI status](https://img.shields.io/pypi/status/django-rmq.svg?style=for-the-badge)](https://pypi.python.org/pypi/django-rmq)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/django-rmq?style=for-the-badge)](https://pypistats.org/packages/django-rmq)
[![PyPI - Types](https://img.shields.io/pypi/types/django-rmq.svg?style=for-the-badge)](https://pypi.python.org/pypi/django-rmq)
[![Tests](https://github.com/RDDLab/Django-RMQ/actions/workflows/ci.yml/badge.svg?branch=main&style=for-the-badge)](https://github.com/RDDLab/Django-RMQ/actions/workflows/ci.yml)

---

Expand All @@ -23,4 +24,37 @@

# Django-RMQ

TODO ...
TODO ...


---

## Testing

### Unit tests

Unit tests mock `pika` and need no broker. They run by default — integration
tests are marked `integration` and deselected:

```bash
uv run pytest
```

### Integration tests

Integration tests run against a **real** RabbitMQ broker. The repo ships a
`.github/docker-compose.yml` that starts the same image CI uses (with the
management plugin the suite needs on port `15672`). Connection params are read
from `RMQ_*` env vars (defaults: `localhost:5672`, `guest`/`guest`, vhost `/`),
which already match the Compose service:

```bash
docker compose -f .github/docker-compose.yml up -d --wait # start the broker, block until healthy
uv run pytest -m integration
docker compose -f .github/docker-compose.yml down # stop it when done
```

The suite isolates itself with per-test `uuid`-suffixed queues/exchanges and
cleans them up, so it is safe against a shared broker (use a dedicated vhost).

---
2 changes: 1 addition & 1 deletion django_rmq/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class RabbitMQConnectionManager:
Manages thread-local connections and the producer channel for RabbitMQ.

Producer and Consumer get *separate* BlockingConnections per thread.
A pika BlockingConnection is owned by exactly one I/O loop; while
Exactly one I/O loop owns a pika BlockingConnection; while
Consumer.consume() drives that loop via process_data_events(), any
concurrent operation on the same connection — whether a publish()
from a handler or a heartbeat from another thread — corrupts the AMQP
Expand Down
File renamed without changes.
28 changes: 28 additions & 0 deletions docs/en/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,31 @@ You can install Django-RMQ with pip or your favorite Python dependency manager:
```bash
pip install django-rmq
```

## Testing

### Unit tests

Unit tests mock `pika` and need no broker. They run by default — integration
tests are marked `integration` and deselected:

```bash
uv run pytest
```

### Integration tests

Integration tests run against a **real** RabbitMQ broker. The repo ships a
`.github/docker-compose.yml` that starts the same image CI uses (with the
management plugin the suite needs on port `15672`). Connection params are read
from `RMQ_*` env vars (defaults: `localhost:5672`, `guest`/`guest`, vhost `/`),
which already match the Compose service:

```bash
docker compose -f .github/docker-compose.yml up -d --wait # start the broker, block until healthy
uv run pytest -m integration
docker compose -f .github/docker-compose.yml down # stop it when done
```

The suite isolates itself with per-test `uuid`-suffixed queues/exchanges and
cleans them up, so it is safe against a shared broker (use a dedicated vhost).
15 changes: 14 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,28 @@ dependencies = [
[dependency-groups]
dev = [
"pytest>=9.0.3",
"pytest-django>=4.9.0",
"pytest-mock>=3.14.0",
"pytest-cov>=6.0.0",
"ruff>=0.14.0",
]

[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "tests.settings"
pythonpath = ["."]
testpaths = ["tests"]
markers = [
"integration: tests that require a real RabbitMQ broker (deselected by default)",
]
addopts = '-ra -m "not integration"'

[project.urls]
Homepage = "https://django-rmq.rdd-lab.com/"
Repository = "https://github.com/RDDLab/Django-RMQ"

[tool.setuptools.packages.find]
where = ["."]
include = ["django_rmq*"]

[tool.setuptools.package-data]
"*" = ["py.typed"]
"django_rmq" = ["py.typed"]
4 changes: 4 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ ignore = [

[lint.per-file-ignores]
"apps.py" = ["F401"]
"tests/*" = [
"PLR2004", # magic value in comparison — expected in assertions
"PLW0108", # lambda may be unnecessary — concise test stubs
]

[lint.flake8-tidy-imports]
ban-relative-imports = "all"
Expand Down
14 changes: 0 additions & 14 deletions runtests.py

This file was deleted.

Loading
Loading