ci: migrate to GitLab CI with multi-distribution RPM builds

- Replace GitHub Actions with GitLab CI using Docker-in-Docker
- Build 3 RPMs (el7, el8, el9) + 1 DEB from Dockerfile.package
- Add verify jobs for each target distribution
- Remove obsolete files:
  - Dockerfile, Dockerfile.test-socket (replaced by Dockerfile.package)
  - scripts/socket_consumer.py, scripts/socket_listener.py
  - scripts/test_unix_socket.sh, scripts/run_integration_tests.sh
- Update README.md with new package targets
- Update architecture.yml for GitLab CI workflow

Breaks: Single RPM no longer supported (glibc incompatibility)
Replaced by: Distribution-specific RPMs (el7, el8, el9)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
Jacquin Antoine
2026-02-28 16:06:57 +01:00
parent 2fc3f92cf8
commit a935ed1641
14 changed files with 392 additions and 1312 deletions

View File

@ -1,202 +0,0 @@
name: CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
# Build on Rocky Linux 8
build-rocky-8:
runs-on: ubuntu-latest
container:
image: rockylinux:8
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
dnf install -y epel-release
dnf install -y gcc make httpd httpd-devel apr-devel apr-util-devel rpm-build
- name: Build module
run: |
make APXS=/usr/bin/apxs
- name: Verify module
run: |
ls -la modules/mod_reqin_log.so
- name: Upload module artifact
uses: actions/upload-artifact@v4
with:
name: mod_reqin_log-rocky8
path: modules/mod_reqin_log.so
# Build on Debian
build-debian:
runs-on: ubuntu-latest
container:
image: debian:stable
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
apt-get update
apt-get install -y build-essential apache2 apache2-dev
- name: Build module
run: |
make APXS=/usr/bin/apxs
- name: Verify module
run: |
ls -la modules/mod_reqin_log.so
- name: Upload module artifact
uses: actions/upload-artifact@v4
with:
name: mod_reqin_log-debian
path: modules/mod_reqin_log.so
# Unit tests
unit-tests:
runs-on: ubuntu-latest
container:
image: debian:stable
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
apt-get update
apt-get install -y build-essential cmake libcmocka-dev apache2-dev
- name: Configure tests
run: |
mkdir -p build/tests
cd build/tests
cmake ../../
- name: Build tests
run: |
make -C build/tests
- name: Run tests
run: |
make -C build/tests run_tests
# Build RPM package
build-rpm:
runs-on: ubuntu-latest
container:
image: rockylinux:8
needs: [build-rocky-8]
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
dnf install -y epel-release
dnf install -y gcc make httpd httpd-devel apr-devel apr-util-devel rpm-build rpmlint
- name: Create source tarball
run: |
tar -czf mod_reqin_log-1.0.0.tar.gz --transform 's,^,mod_reqin_log-1.0.0/,' .
- name: Setup rpmbuild
run: |
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
cp mod_reqin_log-1.0.0.tar.gz ~/rpmbuild/SOURCES/
cp packaging/rpm/mod_reqin_log.spec ~/rpmbuild/SPECS/
- name: Build RPM
run: |
rpmbuild -ba ~/rpmbuild/SPECS/mod_reqin_log.spec
- name: Upload RPM artifacts
uses: actions/upload-artifact@v4
with:
name: rpm-packages
path: ~/rpmbuild/RPMS/x86_64/*.rpm
# Build DEB package
build-deb:
runs-on: ubuntu-latest
container:
image: debian:stable
needs: [build-debian]
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
apt-get update
apt-get install -y build-essential apache2 apache2-dev debhelper devscripts dpkg-dev
- name: Setup package metadata
run: |
cp -r packaging/deb/* ./debian/
echo "1.0.0" > debian/changelog
echo "mod_reqin_log (1.0.0) stable; urgency=medium" >> debian/changelog
echo "" >> debian/changelog
echo " * Initial release" >> debian/changelog
echo "" >> debian/changelog
echo " -- Developer <dev@example.com> $(date -R)" >> debian/changelog
- name: Build DEB
run: |
debuild -us -uc -b
- name: Upload DEB artifacts
uses: actions/upload-artifact@v4
with:
name: deb-packages
path: ../*.deb
# Integration tests
integration-tests:
runs-on: ubuntu-latest
container:
image: rockylinux:8
needs: [build-rocky-8]
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
dnf install -y epel-release
dnf install -y gcc make httpd httpd-devel apr-devel apr-util-devel python3 curl
- name: Build module
run: |
make APXS=/usr/bin/apxs
- name: Setup Apache configuration
run: |
mkdir -p /var/run/mod_reqin_log
cp conf/mod_reqin_log.conf /etc/httpd/conf.d/
echo "LoadModule reqin_log_module /github/workspace/modules/mod_reqin_log.so" > /etc/httpd/conf.d/00-mod_reqin_log.conf
- name: Start socket consumer
run: |
python3 scripts/socket_consumer.py &
sleep 2
- name: Start Apache
run: |
httpd -t
httpd -DFOREGROUND &
sleep 3
- name: Run integration tests
run: |
curl -H "X-Request-Id: test-123" http://localhost/
curl -H "X-Trace-Id: trace-456" http://localhost/api
sleep 2
- name: Verify logs
run: |
echo "Integration test completed"

135
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,135 @@
# GitLab CI/CD configuration for mod_reqin_log
# Uses Docker-in-Docker (dind) for building and testing
stages:
- build
- test
- package
- verify
# Variables
variables:
DOCKER_TLS_CERTDIR: "/certs"
DOCKER_DRIVER: overlay2
VERSION: "1.0.0"
# =============================================================================
# Build Stage - Compile all packages
# =============================================================================
build-packages:
stage: build
image: docker:24
services:
- docker:24-dind
script:
# Build all packages (DEB + RPMs for el7, el8, el9)
- docker build -f Dockerfile.package
--target output
--build-arg VERSION=$VERSION
-t mod_reqin_log:packages .
# Create output directories
- mkdir -p dist/deb dist/rpm
# Extract packages from Docker image
- docker run --rm -v $(pwd)/dist:/output mod_reqin_log:packages
sh -c 'cp -r /packages/deb/* /output/deb/ && cp -r /packages/rpm/* /output/rpm/'
# List built packages
- echo "=== DEB Packages ==="
- ls -la dist/deb/
- echo "=== RPM Packages ==="
- ls -la dist/rpm/
artifacts:
paths:
- dist/deb/
- dist/rpm/
expire_in: 30 days
# =============================================================================
# Test Stage - Unit tests
# =============================================================================
unit-tests:
stage: test
image: docker:24
services:
- docker:24-dind
script:
# Build test image
- docker build -f Dockerfile.tests -t mod_reqin_log:tests .
# Run unit tests
- docker run --rm mod_reqin_log:tests ctest --output-on-failure
# =============================================================================
# Package Stage - Already done in build-packages
# =============================================================================
# =============================================================================
# Verify Stage - Test package installation on each target distribution
# =============================================================================
verify-rpm-el7:
stage: verify
image: docker:24
services:
- docker:24-dind
needs: [build-packages]
script:
# Download artifacts
- apk add --no-cache curl
- curl -L -o /tmp/rpm-el7.rpm "$CI_PROJECT_URL/-/jobs/$CI_JOB_ID/artifacts/dist/rpm/mod_reqin_log-$VERSION-1.el7.x86_64.rpm"
2>/dev/null || echo "Artifact download via curl failed, trying alternative..."
# Alternative: extract from build artifact
- docker run --rm -v $(pwd)/dist:/packages centos:7 sh -c "
sed -i 's/mirror.centos.org/vault.centos.org/g' /etc/yum.repos.d/*.repo &&
sed -i 's/#baseurl/baseurl/g' /etc/yum.repos.d/*.repo &&
sed -i 's/metalink/#metalink/g' /etc/yum.repos.d/*.repo &&
yum install -y /packages/rpm/*.el7.*.rpm &&
httpd -M 2>&1 | grep reqin_log &&
echo 'RPM el7 verification OK'
"
allow_failure: true
verify-rpm-el8:
stage: verify
image: docker:24
services:
- docker:24-dind
needs: [build-packages]
script:
- docker run --rm -v $(pwd)/dist:/packages rockylinux:8 sh -c "
dnf install -y /packages/rpm/*.el8.*.rpm &&
httpd -M 2>&1 | grep reqin_log &&
echo 'RPM el8 verification OK'
"
verify-rpm-el9:
stage: verify
image: docker:24
services:
- docker:24-dind
needs: [build-packages]
script:
- docker run --rm -v $(pwd)/dist:/packages rockylinux:9 sh -c "
dnf install -y /packages/rpm/*.el9.*.rpm &&
httpd -M 2>&1 | grep reqin_log &&
echo 'RPM el9 verification OK'
"
verify-deb:
stage: verify
image: docker:24
services:
- docker:24-dind
needs: [build-packages]
script:
- docker run --rm -v $(pwd)/dist:/packages debian:stable sh -c "
apt-get update &&
apt-get install -y /packages/deb/*.deb &&
ls -la /usr/lib/apache2/modules/mod_reqin_log.so &&
echo 'DEB verification OK'
"

View File

@ -1,33 +0,0 @@
# Dockerfile for building mod_reqin_log (minimal - no tests)
FROM rockylinux:8
# Install build dependencies
RUN dnf install -y epel-release && \
dnf install -y \
gcc \
make \
httpd \
httpd-devel \
apr-devel \
apr-util-devel \
python3 \
curl \
redhat-rpm-config \
&& dnf clean all
# Set working directory
WORKDIR /build
# Copy source files
COPY src/ src/
COPY Makefile Makefile
COPY conf/ conf/
# Build the module
RUN make APXS=/usr/bin/apxs
# Verify module was built
RUN ls -la modules/mod_reqin_log.so
# Default command
CMD ["/bin/bash"]

View File

@ -1,16 +1,49 @@
# syntax=docker/dockerfile:1
# =============================================================================
# mod_reqin_log - Dockerfile de packaging unifié (DEB + RPM avec fpm)
# Builds RPMs for multiple RHEL-compatible versions:
# - AlmaLinux 7 / CentOS 7 (el7) - RHEL 7 compatible (using vault repos)
# - Rocky Linux 8 (el8) - RHEL 8 compatible
# - Rocky Linux 9 (el9) - RHEL 9 compatible
# =============================================================================
# =============================================================================
# Stage 1: Builder - Compilation du module Apache
# Stage 1a: Builder CentOS 7 (RHEL 7 compatible, EOL - using vault)
# =============================================================================
FROM rockylinux:8 AS builder
FROM centos:7 AS builder-el7
# CentOS 7 is EOL since June 2024, use vault.centos.org for repositories
RUN sed -i 's/mirror.centos.org/vault.centos.org/g' /etc/yum.repos.d/*.repo && \
sed -i 's/#baseurl/baseurl/g' /etc/yum.repos.d/*.repo && \
sed -i 's/metalink/#metalink/g' /etc/yum.repos.d/*.repo
# Install build dependencies
RUN yum install -y \
gcc \
make \
httpd \
httpd-devel \
apr-devel \
apr-util-devel \
python3 \
curl \
redhat-rpm-config \
&& yum clean all
WORKDIR /build
COPY src/ src/
COPY Makefile Makefile
COPY conf/ conf/
RUN make APXS=/usr/bin/apxs
RUN ls -la modules/mod_reqin_log.so
# =============================================================================
# Stage 1b: Builder Rocky Linux 8
# =============================================================================
FROM rockylinux:8 AS builder-el8
RUN dnf install -y epel-release && \
dnf install -y \
dnf install -y --allowerasing \
gcc \
make \
httpd \
@ -22,18 +55,36 @@ RUN dnf install -y epel-release && \
redhat-rpm-config \
&& dnf clean all
# Set working directory
WORKDIR /build
# Copy source files
COPY src/ src/
COPY Makefile Makefile
COPY conf/ conf/
# Build the module
RUN make APXS=/usr/bin/apxs
RUN ls -la modules/mod_reqin_log.so
# Verify module was built
# =============================================================================
# Stage 1c: Builder Rocky Linux 9
# =============================================================================
FROM rockylinux:9 AS builder-el9
RUN dnf install -y epel-release && \
dnf install -y --allowerasing \
gcc \
make \
httpd \
httpd-devel \
apr-devel \
apr-util-devel \
python3 \
curl \
redhat-rpm-config \
&& dnf clean all
WORKDIR /build
COPY src/ src/
COPY Makefile Makefile
COPY conf/ conf/
RUN make APXS=/usr/bin/apxs
RUN ls -la modules/mod_reqin_log.so
# =============================================================================
@ -53,13 +104,33 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/* \
&& gem install fpm -v 1.16.0
# Copy binary from builder
COPY --from=builder /build/modules/mod_reqin_log.so /tmp/pkgroot/usr/lib/apache2/modules/mod_reqin_log.so
COPY --from=builder /build/conf/mod_reqin_log.conf /tmp/pkgroot/etc/apache2/conf-available/mod_reqin_log.conf
# =============================================================================
# Copy binaries from each builder stage
# =============================================================================
# Set permissions
RUN chmod 755 /tmp/pkgroot/usr/lib/apache2/modules/mod_reqin_log.so && \
chmod 644 /tmp/pkgroot/etc/apache2/conf-available/mod_reqin_log.conf
# CentOS 7 (el7)
COPY --from=builder-el7 /build/modules/mod_reqin_log.so /tmp/pkgroot-el7/usr/lib64/httpd/modules/mod_reqin_log.so
COPY --from=builder-el7 /build/conf/mod_reqin_log.conf /tmp/pkgroot-el7/etc/httpd/conf.d/mod_reqin_log.conf
RUN chmod 755 /tmp/pkgroot-el7/usr/lib64/httpd/modules/mod_reqin_log.so && \
chmod 644 /tmp/pkgroot-el7/etc/httpd/conf.d/mod_reqin_log.conf
# Rocky Linux 8 (el8)
COPY --from=builder-el8 /build/modules/mod_reqin_log.so /tmp/pkgroot-el8/usr/lib64/httpd/modules/mod_reqin_log.so
COPY --from=builder-el8 /build/conf/mod_reqin_log.conf /tmp/pkgroot-el8/etc/httpd/conf.d/mod_reqin_log.conf
RUN chmod 755 /tmp/pkgroot-el8/usr/lib64/httpd/modules/mod_reqin_log.so && \
chmod 644 /tmp/pkgroot-el8/etc/httpd/conf.d/mod_reqin_log.conf
# Rocky Linux 9 (el9)
COPY --from=builder-el9 /build/modules/mod_reqin_log.so /tmp/pkgroot-el9/usr/lib64/httpd/modules/mod_reqin_log.so
COPY --from=builder-el9 /build/conf/mod_reqin_log.conf /tmp/pkgroot-el9/etc/httpd/conf.d/mod_reqin_log.conf
RUN chmod 755 /tmp/pkgroot-el9/usr/lib64/httpd/modules/mod_reqin_log.so && \
chmod 644 /tmp/pkgroot-el9/etc/httpd/conf.d/mod_reqin_log.conf
# DEB package (Debian paths)
COPY --from=builder-el9 /build/modules/mod_reqin_log.so /tmp/pkgroot-deb/usr/lib/apache2/modules/mod_reqin_log.so
COPY --from=builder-el9 /build/conf/mod_reqin_log.conf /tmp/pkgroot-deb/etc/apache2/conf-available/mod_reqin_log.conf
RUN chmod 755 /tmp/pkgroot-deb/usr/lib/apache2/modules/mod_reqin_log.so && \
chmod 644 /tmp/pkgroot-deb/etc/apache2/conf-available/mod_reqin_log.conf
# Build DEB package (for Debian/Ubuntu)
ARG VERSION=1.0.0
@ -68,7 +139,7 @@ RUN mkdir -p /packages/deb && \
fpm -s dir -t deb \
-n libapache2-mod-reqin-log \
-v "${VERSION}" \
-C /tmp/pkgroot \
-C /tmp/pkgroot-deb \
--architecture "${ARCH}" \
--description "Apache HTTPD module for logging HTTP requests as JSON to Unix socket" \
--url "https://github.com/example/mod_reqin_log" \
@ -80,22 +151,61 @@ RUN mkdir -p /packages/deb && \
usr/lib/apache2/modules/mod_reqin_log.so \
etc/apache2/conf-available/mod_reqin_log.conf
# Build RPM package (for Rocky Linux/RHEL/CentOS)
ARG DIST=el8
# =============================================================================
# Build RPM packages for each distribution
# =============================================================================
# CentOS 7 (el7)
ARG VERSION=1.0.0
RUN mkdir -p /packages/rpm && \
fpm -s dir -t rpm \
-n mod_reqin_log \
-v "${VERSION}" \
-C /tmp/pkgroot \
--rpm-dist el7 \
-C /tmp/pkgroot-el7 \
--architecture "x86_64" \
--description "Apache HTTPD module for logging HTTP requests as JSON to Unix socket" \
--url "https://github.com/example/mod_reqin_log" \
--license "Apache-2.0" \
--vendor "Developer <dev@example.com>" \
--depends "httpd" \
-p /packages/rpm/mod_reqin_log-${VERSION}-1.x86_64.rpm \
usr/lib/apache2/modules/mod_reqin_log.so \
etc/apache2/conf-available/mod_reqin_log.conf
-p /packages/rpm/mod_reqin_log-${VERSION}-1.el7.x86_64.rpm \
usr/lib64/httpd/modules/mod_reqin_log.so \
etc/httpd/conf.d/mod_reqin_log.conf
# Rocky Linux 8 (el8)
RUN \
fpm -s dir -t rpm \
-n mod_reqin_log \
-v "${VERSION}" \
--rpm-dist el8 \
-C /tmp/pkgroot-el8 \
--architecture "x86_64" \
--description "Apache HTTPD module for logging HTTP requests as JSON to Unix socket" \
--url "https://github.com/example/mod_reqin_log" \
--license "Apache-2.0" \
--vendor "Developer <dev@example.com>" \
--depends "httpd" \
-p /packages/rpm/mod_reqin_log-${VERSION}-1.el8.x86_64.rpm \
usr/lib64/httpd/modules/mod_reqin_log.so \
etc/httpd/conf.d/mod_reqin_log.conf
# Rocky Linux 9 (el9)
RUN \
fpm -s dir -t rpm \
-n mod_reqin_log \
-v "${VERSION}" \
--rpm-dist el9 \
-C /tmp/pkgroot-el9 \
--architecture "x86_64" \
--description "Apache HTTPD module for logging HTTP requests as JSON to Unix socket" \
--url "https://github.com/example/mod_reqin_log" \
--license "Apache-2.0" \
--vendor "Developer <dev@example.com>" \
--depends "httpd" \
-p /packages/rpm/mod_reqin_log-${VERSION}-1.el9.x86_64.rpm \
usr/lib64/httpd/modules/mod_reqin_log.so \
etc/httpd/conf.d/mod_reqin_log.conf
# =============================================================================
# Stage 3: Output - Image finale avec les packages

View File

@ -1,40 +0,0 @@
# Dockerfile for running Unix socket integration tests
FROM rockylinux:8
# Install dependencies
RUN dnf install -y epel-release && \
dnf install -y \
gcc \
make \
httpd \
httpd-devel \
apr-devel \
apr-util-devel \
python3 \
curl \
redhat-rpm-config \
&& dnf clean all
# Copy module source
COPY src/ src/
COPY Makefile Makefile
COPY conf/ conf/
# Build the module
RUN make APXS=/usr/bin/apxs
# Copy test scripts
COPY scripts/test_unix_socket.sh /test_unix_socket.sh
COPY scripts/socket_listener.py /build/scripts/socket_listener.py
RUN chmod +x /test_unix_socket.sh
RUN mkdir -p /build/scripts
# Create document root
RUN mkdir -p /var/www/html
RUN echo "<html><body><h1>Test</h1></body></html>" > /var/www/html/index.html
# Set working directory
WORKDIR /build
# Run the test
CMD ["/test_unix_socket.sh"]

View File

@ -72,41 +72,64 @@ debug: clean all
# =============================================================================
# Packaging (DEB + RPM with Docker + fpm)
# Dockerfile.package builds all packages in a single multi-stage build:
# - 1 DEB package (Debian/Ubuntu)
# - 3 RPM packages (el7, el8, el9 for RHEL/CentOS/Rocky compatibility)
# =============================================================================
## package: Build all packages (deb + rpm)
package: package-deb package-rpm
## package-deb: Build DEB package (requires Docker)
package-deb:
## package: Build all packages (deb + rpm for el7, el8, el9)
package:
mkdir -p $(DIST_DIR)/deb $(DIST_DIR)/rpm
docker build --target output -t mod_reqin_log-packager:latest \
docker build --target output -t mod_reqin_log:packager \
--build-arg VERSION=$(VERSION) \
-f Dockerfile.package .
@echo "Extracting packages from Docker image..."
docker run --rm -v $(PWD)/$(DIST_DIR):/output mod_reqin_log-packager:latest \
sh -c 'cp -r /packages/deb /output/deb/ && cp -r /packages/rpm /output/rpm/'
@echo "DEB packages created:"
ls -la $(DIST_DIR)/deb/
@echo "RPM packages created:"
ls -la $(DIST_DIR)/rpm/
docker run --rm -v $(PWD)/$(DIST_DIR):/output mod_reqin_log:packager \
sh -c 'cp -r /packages/deb/* /output/deb/ && cp -r /packages/rpm/* /output/rpm/'
@echo "Packages created:"
@echo " DEB:"
@ls -la $(DIST_DIR)/deb/
@echo " RPM (el7, el8, el9):"
@ls -la $(DIST_DIR)/rpm/
## package-rpm: Build RPM package (requires Docker)
package-rpm: package-deb
@echo "RPM built together with DEB in Dockerfile.package"
## package-deb: Build DEB package (built together with RPMs in Dockerfile.package)
package-deb: package
@echo "DEB package built together with RPMs in Dockerfile.package"
## package-rpm: Build RPM packages (el7, el8, el9 built together in Dockerfile.package)
package-rpm: package
@echo "RPM packages built together with DEB in Dockerfile.package"
## test-package-deb: Test DEB package installation in Docker
test-package-deb: package-deb
test-package-deb: package
docker run --rm -v $(PWD)/$(DIST_DIR)/deb:/packages:ro debian:latest \
sh -c "apt-get update && apt-get install -y /packages/*.deb && echo 'DEB install OK'"
## test-package-rpm: Test RPM package installation in Docker
test-package-rpm: package-deb
## test-package-rpm: Test RPM package installation in Docker (tests el9 by default)
test-package-rpm: package
docker run --rm -v $(PWD)/$(DIST_DIR)/rpm:/packages:ro rockylinux:9 \
sh -c "dnf install -y /packages/*.el9.*.rpm && echo 'RPM el9 install OK'"
## test-package-rpm-el7: Test el7 RPM installation
test-package-rpm-el7: package
docker run --rm -v $(PWD)/$(DIST_DIR)/rpm:/packages:ro centos:7 \
sh -c "sed -i 's/mirror.centos.org/vault.centos.org/g' /etc/yum.repos.d/*.repo && \
sed -i 's/#baseurl/baseurl/g' /etc/yum.repos.d/*.repo && \
sed -i 's/metalink/#metalink/g' /etc/yum.repos.d/*.repo && \
yum install -y /packages/*.el7.*.rpm && echo 'RPM el7 install OK'"
## test-package-rpm-el8: Test el8 RPM installation
test-package-rpm-el8: package
docker run --rm -v $(PWD)/$(DIST_DIR)/rpm:/packages:ro rockylinux:8 \
sh -c "dnf install -y /packages/*.rpm && echo 'RPM install OK'"
sh -c "dnf install -y /packages/*.el8.*.rpm && echo 'RPM el8 install OK'"
## test-package-rpm-el9: Test el9 RPM installation
test-package-rpm-el9: package
docker run --rm -v $(PWD)/$(DIST_DIR)/rpm:/packages:ro rockylinux:9 \
sh -c "dnf install -y /packages/*.el9.*.rpm && echo 'RPM el9 install OK'"
## test-package: Test all packages installation
test-package: test-package-deb test-package-rpm
test-package: test-package-deb test-package-rpm-el7 test-package-rpm-el8 test-package-rpm-el9
# Help target
help:
@ -119,9 +142,9 @@ help:
@echo " clean - Remove build artifacts"
@echo " test - Run unit tests"
@echo " debug - Build with debug symbols"
@echo " package - Build all packages (deb + rpm)"
@echo " package - Build all packages (deb + rpm for el7, el8, el9)"
@echo " package-deb - Build DEB package"
@echo " package-rpm - Build RPM package"
@echo " package-rpm - Build RPM packages"
@echo " test-package - Test package installation"
@echo ""
@echo "Variables:"

View File

@ -24,14 +24,15 @@ Apache HTTPD 2.4 module for logging all incoming HTTP requests as JSON lines to
### Using Docker (recommended)
```bash
# Build DEB and RPM packages
make package-deb # Creates dist/deb/libapache2-mod-reqin-log_*.deb
make package-rpm # Creates dist/rpm/mod_reqin_log-*.rpm
make package # Build both packages
# Build all packages (DEB + RPMs for el7, el8, el9)
make package
# Test package installation
make test-package-deb # Test DEB in Docker container
make test-package-rpm # Test RPM in Docker container
make test-package-rpm-el7 # Test el7 RPM (CentOS 7/RHEL 7)
make test-package-rpm-el8 # Test el8 RPM (Rocky 8/RHEL 8)
make test-package-rpm-el9 # Test el9 RPM (Rocky 9/RHEL 9)
make test-package # Test all packages
```
### Build from Source
@ -237,11 +238,13 @@ ls -la /usr/lib/apache2/modules/mod_reqin_log.so
### Run Unit Tests
```bash
# Install test dependencies
# Using Docker (recommended)
docker build -f Dockerfile.tests -t mod_reqin_log:tests .
docker run --rm mod_reqin_log:tests ctest --output-on-failure
# Or locally with cmocka
sudo dnf install cmocka-devel # Rocky Linux
sudo apt install libcmocka-dev # Debian/Ubuntu
# Build and run tests
mkdir build && cd build
cmake ..
make test
@ -250,16 +253,25 @@ make test
### Integration Testing
```bash
# Start socket consumer
python3 scripts/socket_consumer.py &
# Using GitLab CI (recommended)
# All integration tests run automatically in CI
# Start Apache with module enabled
sudo systemctl start httpd
# Or manually with the Python test suite
python3 tests/integration/test_integration.py --url http://localhost:8080
```
# Send test requests
curl -H "X-Request-Id: test-123" http://localhost/
### Build and Test Packages
# Check consumer output
```bash
# Build all packages (DEB + RPMs for el7, el8, el9)
make package
# Test package installation
make test-package-deb # Test DEB in Docker
make test-package-rpm-el7 # Test el7 RPM in Docker
make test-package-rpm-el8 # Test el8 RPM in Docker
make test-package-rpm-el9 # Test el9 RPM in Docker
make test-package # Test all packages
```
## License

View File

@ -360,136 +360,51 @@ testing:
ci:
strategy:
description: >
All builds, tests and packaging are executed inside Docker containers.
The host only needs Docker and the CI runner (GitHub Actions).
All builds, tests and packaging are executed inside Docker containers
using GitLab CI with Docker-in-Docker (dind).
tools:
orchestrator: GitHub Actions
orchestrator: GitLab CI
container_engine: docker
workflow_file: .github/workflows/ci.yml
dind: true
workflow_file: .gitlab-ci.yml
rpm_strategy: >
Separate RPMs are built for each major RHEL/CentOS/Rocky version
(el7, el8, el9) due to glibc and httpd-devel incompatibilities
across major versions. A single RPM cannot work across all versions.
Note: CentOS 7 is EOL since June 2024, repositories use vault.centos.org.
All packages (DEB + multi-RPM) are built from Dockerfile.package.
stages:
- name: build
description: >
Compile mod_reqin_log as an Apache 2.4 module inside Docker images
dedicated to each target distribution.
jobs:
- name: build-rocky-8
image: "rockylinux:8"
steps:
- checkout: actions/checkout@v4
- install_deps:
- gcc
- make
- httpd
- httpd-devel
- apr-devel
- apr-util-devel
- rpm-build
- build_module:
command: "make APXS=/usr/bin/apxs"
- verify:
command: "ls -la modules/mod_reqin_log.so"
- upload_artifact: actions/upload-artifact@v4
- name: build-debian
image: "debian:stable"
steps:
- checkout: actions/checkout@v4
- install_deps:
- build-essential
- apache2
- apache2-dev
- build_module:
command: "make APXS=/usr/bin/apxs"
- verify:
command: "ls -la modules/mod_reqin_log.so"
- upload_artifact: actions/upload-artifact@v4
Build all packages (1 DEB + 3 RPMs) using Dockerfile.package with multi-stage build.
dockerfile: Dockerfile.package
artifacts:
- dist/deb/*.deb
- dist/rpm/*.el7.*.rpm
- dist/rpm/*.el8.*.rpm
- dist/rpm/*.el9.*.rpm
- name: test
description: >
Run unit tests (C with cmocka) inside Docker containers.
Integration tests require a running Apache instance.
dockerfile: Dockerfile.tests
execution: ctest --output-on-failure
- name: verify
description: >
Verify package installation on each target distribution.
jobs:
- name: unit-tests
image: "rockylinux:8"
steps:
- checkout: actions/checkout@v4
- install_deps:
- gcc
- make
- httpd
- httpd-devel
- apr-devel
- apr-util-devel
- cmake
- git
- pkgconfig
- libxml2-devel
- build_cmocka:
description: "Build cmocka from source (not available in EPEL)"
command: |
cd /tmp && git clone https://git.cryptomilk.org/projects/cmocka.git
cd cmocka && git checkout cmocka-1.1.5
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
make && make install && ldconfig
- build_tests:
command: |
mkdir -p build/tests
cd build/tests && cmake ../../ && make
- run_tests:
command: "cd build/tests && ctest --output-on-failure"
- name: package
description: >
Build RPM and DEB packages for mod_reqin_log using Docker and fpm.
Both packages are built from a single Dockerfile.package with multi-stage build.
dockerfile: Dockerfile.package
stages:
- name: builder
description: >
Compile mod_reqin_log.so as Apache 2.4 module using apxs.
- name: package_builder
description: >
Install fpm, rpm, dpkg-dev, apache2-dev. Create filesystem layout
and run fpm to generate both DEB and RPM packages.
- name: output
description: >
Minimal Alpine image with packages in /packages/deb and /packages/rpm.
files:
module:
source: build/mod_reqin_log.so
dest: /usr/lib/apache2/modules/mod_reqin_log.so
mode: "0755"
config:
- source: conf/mod_reqin_log.conf
dest: /etc/apache2/conf-available/mod_reqin_log.conf
mode: "0644"
config_file: true
dependencies:
deb:
- apache2
rpm:
- httpd
outputs:
deb:
name: libapache2-mod-reqin-log
path: dist/deb/libapache2-mod-reqin-log_${VERSION}_amd64.deb
rpm:
name: mod_reqin_log
path: dist/rpm/mod_reqin_log-${VERSION}-1.x86_64.rpm
verify:
deb:
command: docker run --rm -v $(pwd)/dist/deb:/packages debian:latest sh -c "apt-get update && apt-get install -y /packages/*.deb"
rpm:
command: docker run --rm -v $(pwd)/dist/rpm:/packages rockylinux:8 sh -c "dnf install -y /packages/*.rpm"
artifacts:
retention:
policy: "Keep build logs and packages for 30 days for debugging"
outputs:
- type: module
path: "modules/mod_reqin_log.so"
- type: rpm
path: "dist/rpm/"
- type: deb
path: "dist/deb/"
- name: verify-rpm-el7
image: centos:7
vault_repos: true
check: "httpd -M | grep reqin_log"
- name: verify-rpm-el8
image: rockylinux:8
check: "httpd -M | grep reqin_log"
- name: verify-rpm-el9
image: rockylinux:9
check: "httpd -M | grep reqin_log"
- name: verify-deb
image: debian:stable
check: "ls -la /usr/lib/apache2/modules/mod_reqin_log.so"

View File

@ -1,6 +1,8 @@
#!/bin/bash
#
# build.sh - Build mod_reqin_log in Docker
# Builds the module for the current platform only.
# For multi-platform packages, use: make package
#
set -e
@ -8,7 +10,10 @@ set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
IMAGE_NAME="mod_reqin_log-build"
echo "Building Docker image..."
echo "Building mod_reqin_log in Docker..."
echo ""
# Build the image (uses Dockerfile, not Dockerfile.package)
docker build -t "$IMAGE_NAME" "$SCRIPT_DIR/.."
echo ""
@ -18,10 +23,11 @@ echo "Build complete. Extracting module..."
mkdir -p "$SCRIPT_DIR/../dist"
# Extract the built module from container
docker run --rm -v "$SCRIPT_DIR/../dist:/output" "$IMAGE_NAME" cp /build/modules/mod_reqin_log.so /output/
docker run --rm -v "$SCRIPT_DIR/../dist:/output" "$IMAGE_NAME" \
cp /build/modules/mod_reqin_log.so /output/
echo ""
echo "Module built successfully: $SCRIPT_DIR/../dist/mod_reqin_log.so"
echo ""
echo "To test the module:"
echo " docker run --rm -v \$PWD/dist:/modules mod_reqin_log-build httpd -t -C 'LoadModule reqin_log_module /modules/mod_reqin_log.so'"
echo " docker run --rm -v \$PWD/dist:/modules $IMAGE_NAME httpd -t -C 'LoadModule reqin_log_module /modules/mod_reqin_log.so'"

View File

@ -1,263 +0,0 @@
#!/bin/bash
#
# run_integration_tests.sh - Integration test script for mod_reqin_log
#
# This script runs integration tests for the mod_reqin_log module.
# It requires:
# - Apache HTTPD with the module loaded
# - A running socket consumer
#
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Use /var/run for production (more secure than /tmp)
SOCKET_PATH="${SOCKET_PATH:-/var/run/mod_reqin_log.sock}"
LOG_FILE="${LOG_FILE:-/var/log/mod_reqin_log_test.log}"
APACHE_URL="${APACHE_URL:-http://localhost:8080}"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Counters
TESTS_RUN=0
TESTS_PASSED=0
TESTS_FAILED=0
log_info() {
echo -e "${YELLOW}[INFO]${NC} $1" >&2
}
log_pass() {
echo -e "${GREEN}[PASS]${NC} $1" >&2
((TESTS_PASSED++)) || true
}
log_fail() {
echo -e "${RED}[FAIL]${NC} $1" >&2
((TESTS_FAILED++)) || true
}
cleanup() {
log_info "Cleaning up..."
rm -f "$LOG_FILE"
rm -f "$SOCKET_PATH"
}
trap cleanup EXIT
# Check prerequisites
check_prerequisites() {
log_info "Checking prerequisites..."
if ! command -v curl &> /dev/null; then
echo "Error: curl is required but not installed."
exit 1
fi
if ! command -v python3 &> /dev/null; then
echo "Error: python3 is required but not installed."
exit 1
fi
}
# Strip timestamp prefix from log line
strip_log_prefix() {
# Remove [YYYY-MM-DD HH:MM:SS] prefix from log lines
sed 's/^\[[0-9-]* [0-9:]*\] //'
}
# Test: Basic request logging
test_basic_logging() {
((TESTS_RUN++)) || true
log_info "Test: Basic request logging"
curl -s "$APACHE_URL/" > /dev/null
sleep 1
# Strip prefix and check for method
if strip_log_prefix < "$LOG_FILE" 2>/dev/null | grep -q '"method":"GET"'; then
log_pass "Basic logging test"
return 0
else
log_fail "Basic logging test - No GET method found in logs"
return 1
fi
}
# Test: Custom header logging
test_custom_headers() {
((TESTS_RUN++)) || true
log_info "Test: Custom header logging"
curl -s -H "X-Request-Id: test-12345" "$APACHE_URL/" > /dev/null
sleep 1
if strip_log_prefix < "$LOG_FILE" 2>/dev/null | grep -q '"header_X-Request-Id":"test-12345"'; then
log_pass "Custom header logging test"
return 0
else
log_fail "Custom header logging test - X-Request-Id not found in logs"
return 1
fi
}
# Test: Multiple headers
test_multiple_headers() {
((TESTS_RUN++)) || true
log_info "Test: Multiple headers"
curl -s \
-H "X-Request-Id: req-abc" \
-H "X-Trace-Id: trace-xyz" \
"$APACHE_URL/" > /dev/null
sleep 1
local stripped_logs=$(strip_log_prefix < "$LOG_FILE" 2>/dev/null)
local found_request_id=$(echo "$stripped_logs" | grep -c '"header_X-Request-Id":"req-abc"' || echo 0)
local found_trace_id=$(echo "$stripped_logs" | grep -c '"header_X-Trace-Id":"trace-xyz"' || echo 0)
if [ "$found_request_id" -gt 0 ] && [ "$found_trace_id" -gt 0 ]; then
log_pass "Multiple headers test"
return 0
else
log_fail "Multiple headers test - Not all headers found"
return 1
fi
}
# Test: JSON format validation
test_json_format() {
((TESTS_RUN++)) || true
log_info "Test: JSON format validation"
curl -s "$APACHE_URL/" > /dev/null
sleep 1
# Get last line, strip prefix, and validate JSON
local last_line=$(tail -1 "$LOG_FILE" 2>/dev/null | strip_log_prefix)
if echo "$last_line" | python3 -m json.tool > /dev/null 2>&1; then
log_pass "JSON format validation test"
return 0
else
log_fail "JSON format validation test - Invalid JSON format"
return 1
fi
}
# Test: Required fields presence
test_required_fields() {
((TESTS_RUN++)) || true
log_info "Test: Required fields presence"
curl -s "$APACHE_URL/" > /dev/null
sleep 1
local last_line=$(tail -1 "$LOG_FILE" 2>/dev/null | strip_log_prefix)
local required_fields=("time" "timestamp" "src_ip" "dst_ip" "method" "path" "host")
local all_present=true
for field in "${required_fields[@]}"; do
if ! echo "$last_line" | grep -q "\"$field\":"; then
all_present=false
break
fi
done
if $all_present; then
log_pass "Required fields presence test"
return 0
else
log_fail "Required fields presence test - Missing required fields"
return 1
fi
}
# Test: HTTP method variations
test_method_variations() {
((TESTS_RUN++)) || true
log_info "Test: HTTP method variations"
curl -s -X POST "$APACHE_URL/" > /dev/null
curl -s -X PUT "$APACHE_URL/" > /dev/null
curl -s -X DELETE "$APACHE_URL/" > /dev/null
sleep 1
local stripped_logs=$(strip_log_prefix < "$LOG_FILE" 2>/dev/null)
local found_post=$(echo "$stripped_logs" | grep -c '"method":"POST"' || echo 0)
local found_put=$(echo "$stripped_logs" | grep -c '"method":"PUT"' || echo 0)
local found_delete=$(echo "$stripped_logs" | grep -c '"method":"DELETE"' || echo 0)
if [ "$found_post" -gt 0 ] && [ "$found_put" -gt 0 ] && [ "$found_delete" -gt 0 ]; then
log_pass "HTTP method variations test"
return 0
else
log_fail "HTTP method variations test - Not all methods found"
return 1
fi
}
# Test: Path logging
test_path_logging() {
((TESTS_RUN++)) || true
log_info "Test: Path logging"
curl -s "$APACHE_URL/api/users" > /dev/null
curl -s "$APACHE_URL/foo/bar/baz" > /dev/null
sleep 1
local stripped_logs=$(strip_log_prefix < "$LOG_FILE" 2>/dev/null)
local found_api=$(echo "$stripped_logs" | grep -c '"path":"/api/users"' || echo 0)
local found_foo=$(echo "$stripped_logs" | grep -c '"path":"/foo/bar/baz"' || echo 0)
if [ "$found_api" -gt 0 ] && [ "$found_foo" -gt 0 ]; then
log_pass "Path logging test"
return 0
else
log_fail "Path logging test - Not all paths found"
return 1
fi
}
# Main test runner
main() {
echo "========================================"
echo "mod_reqin_log Integration Tests"
echo "========================================"
echo ""
check_prerequisites
# Run individual tests
test_basic_logging || true
test_custom_headers || true
test_multiple_headers || true
test_json_format || true
test_required_fields || true
test_method_variations || true
test_path_logging || true
# Summary
echo ""
echo "========================================"
echo "Test Summary"
echo "========================================"
echo "Tests run: $TESTS_RUN"
echo -e "Tests passed: ${GREEN}$TESTS_PASSED${NC}"
echo -e "Tests failed: ${RED}$TESTS_FAILED${NC}"
echo ""
if [ $TESTS_FAILED -gt 0 ]; then
exit 1
fi
echo -e "${GREEN}All tests passed!${NC}"
exit 0
}
main "$@"

View File

@ -1,187 +0,0 @@
#!/usr/bin/env python3
"""
socket_consumer.py - Unix socket consumer for mod_reqin_log
This script creates a Unix domain socket server that receives JSON log lines
from the mod_reqin_log Apache module. It is primarily used for testing and
development purposes.
Usage:
python3 socket_consumer.py [socket_path]
Example:
python3 socket_consumer.py /var/run/mod_reqin_log.sock
"""
import socket
import os
import sys
import json
import signal
import argparse
from datetime import datetime
# Default socket path
# Use /var/run for production (more secure than /tmp)
DEFAULT_SOCKET_PATH = os.environ.get("MOD_REQIN_LOG_SOCKET", "/var/run/mod_reqin_log.sock")
# Global flag for graceful shutdown
shutdown_requested = False
def signal_handler(signum, frame):
"""Handle shutdown signals gracefully."""
global shutdown_requested
shutdown_requested = True
print("\nShutdown requested, finishing current operations...")
def parse_args():
"""Parse command line arguments."""
parser = argparse.ArgumentParser(
description="Unix socket consumer for mod_reqin_log"
)
parser.add_argument(
"socket_path",
nargs="?",
default=DEFAULT_SOCKET_PATH,
help=f"Path to Unix socket (default: {DEFAULT_SOCKET_PATH})"
)
parser.add_argument(
"-q", "--quiet",
action="store_true",
help="Suppress log output"
)
parser.add_argument(
"-o", "--output",
type=str,
help="Write logs to file instead of stdout"
)
parser.add_argument(
"--validate-json",
action="store_true",
help="Validate JSON and pretty-print"
)
return parser.parse_args()
def create_socket(socket_path):
"""Create and bind Unix domain socket."""
# Remove existing socket file
if os.path.exists(socket_path):
os.remove(socket_path)
# Create socket
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(socket_path)
server.listen(5)
# Set permissions (owner and group only, not world-writable)
# Apache user must be in the socket's group to connect
os.chmod(socket_path, 0o660)
return server
def process_log_line(line, validate_json=False, output_file=None):
"""Process a single log line."""
line = line.strip()
if not line:
return
if validate_json:
try:
log_entry = json.loads(line)
line = json.dumps(log_entry, indent=2)
except json.JSONDecodeError as e:
line = f"[INVALID JSON] {line}\nError: {e}"
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
output = f"[{timestamp}] {line}"
if output_file:
output_file.write(output + "\n")
output_file.flush()
else:
print(output)
def handle_client(conn, validate_json=False, output_file=None):
"""Handle a client connection."""
data = b""
try:
while not shutdown_requested:
chunk = conn.recv(4096)
if not chunk:
break
data += chunk
# Process complete lines
while b"\n" in data:
newline_pos = data.index(b"\n")
line = data[:newline_pos].decode("utf-8", errors="replace")
data = data[newline_pos + 1:]
process_log_line(line, validate_json, output_file)
except Exception as e:
print(f"Error handling client: {e}", file=sys.stderr)
finally:
# Process any remaining data
if data:
line = data.decode("utf-8", errors="replace")
process_log_line(line, validate_json, output_file)
conn.close()
def main():
"""Main entry point."""
args = parse_args()
# Setup signal handlers
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
output_file = None
if args.output:
output_file = open(args.output, "a")
try:
# Create socket
server = create_socket(args.socket_path)
print(f"Listening on {args.socket_path}", file=sys.stderr)
if not args.quiet:
print(f"Waiting for connections... (Ctrl+C to stop)", file=sys.stderr)
# Accept connections
while not shutdown_requested:
try:
server.settimeout(1.0)
try:
conn, addr = server.accept()
except socket.timeout:
continue
# Handle client in same thread for simplicity
handle_client(conn, args.validate_json, output_file)
except Exception as e:
if not shutdown_requested:
print(f"Accept error: {e}", file=sys.stderr)
except Exception as e:
print(f"Fatal error: {e}", file=sys.stderr)
return 1
finally:
# Cleanup
if os.path.exists(args.socket_path):
os.remove(args.socket_path)
if output_file:
output_file.close()
print("Socket consumer stopped.", file=sys.stderr)
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@ -1,76 +0,0 @@
#!/usr/bin/env python3
"""
socket_listener.py - Simple Unix socket listener for testing mod_reqin_log
Receives JSON log lines and writes them to a file.
"""
import socket
import os
import sys
import signal
import argparse
shutdown_requested = False
def signal_handler(signum, frame):
global shutdown_requested
shutdown_requested = True
def main():
parser = argparse.ArgumentParser(description='Unix socket listener for testing')
parser.add_argument('socket_path', help='Path to Unix socket')
parser.add_argument('-o', '--output', required=True, help='Output file for logs')
args = parser.parse_args()
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
# Remove existing socket
if os.path.exists(args.socket_path):
os.remove(args.socket_path)
# Create socket
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(args.socket_path)
server.listen(5)
os.chmod(args.socket_path, 0o666)
print(f"Listening on {args.socket_path}", file=sys.stderr)
sys.stderr.flush()
with open(args.output, 'w') as f:
while not shutdown_requested:
try:
server.settimeout(1.0)
try:
conn, addr = server.accept()
print(f"Connection accepted from {addr}", file=sys.stderr)
sys.stderr.flush()
except socket.timeout:
continue
data = b""
while not shutdown_requested:
chunk = conn.recv(4096)
if not chunk:
break
data += chunk
while b"\n" in data:
newline_pos = data.index(b"\n")
line = data[:newline_pos].decode("utf-8", errors="replace")
data = data[newline_pos + 1:]
if line.strip():
f.write(line + "\n")
f.flush()
print(f"Received: {line[:100]}...", file=sys.stderr)
conn.close()
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
if os.path.exists(args.socket_path):
os.remove(args.socket_path)
print("Listener stopped.", file=sys.stderr)
if __name__ == "__main__":
main()

View File

@ -1,29 +1,27 @@
#!/bin/bash
#
# test.sh - Run tests for mod_reqin_log in Docker
# test.sh - Run unit tests for mod_reqin_log in Docker
#
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
IMAGE_NAME="mod_reqin_log-build"
echo "========================================"
echo "mod_reqin_log - Test Suite"
echo "mod_reqin_log - Unit Tests"
echo "========================================"
echo ""
# Build image if not exists
if ! docker images "$IMAGE_NAME" | grep -q "$IMAGE_NAME"; then
echo "Building Docker image first..."
"$SCRIPT_DIR/scripts/build.sh"
fi
# Build test image
echo "Building test container..."
docker build -f Dockerfile.tests -t mod_reqin_log:tests "$SCRIPT_DIR/.."
echo ""
echo "Running unit tests..."
echo ""
# Run unit tests in container
docker run --rm "$IMAGE_NAME" bash -c "cd build/tests && ctest --output-on-failure"
docker run --rm mod_reqin_log:tests ctest --output-on-failure
echo ""
echo "========================================"

View File

@ -1,318 +0,0 @@
#!/bin/bash
#
# test_unix_socket.sh - Integration test for mod_reqin_log Unix socket logging
#
# This test verifies that:
# 1. The module connects to a Unix socket
# 2. HTTP requests generate JSON log entries
# 3. Log entries are properly formatted and sent to the socket
#
set -e
# Use /var/run for production (more secure than /tmp)
SOCKET_PATH="${SOCKET_PATH:-/var/run/mod_reqin_log_test.sock}"
LOG_OUTPUT="${LOG_OUTPUT:-/var/log/mod_reqin_log_output.jsonl}"
APACHE_PORT="${APACHE_PORT:-8080}"
TIMEOUT=30
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() {
echo -e "${YELLOW}[INFO]${NC} $1"
}
log_pass() {
echo -e "${GREEN}[PASS]${NC} $1"
}
log_fail() {
echo -e "${RED}[FAIL]${NC} $1"
}
cleanup() {
log_info "Cleaning up..."
rm -f "$SOCKET_PATH" "$LOG_OUTPUT"
pkill -f "socket_listener.py" 2>/dev/null || true
pkill -f "apache.*test" 2>/dev/null || true
}
trap cleanup EXIT
# Check dependencies
check_dependencies() {
log_info "Checking dependencies..."
if ! command -v curl &> /dev/null; then
log_fail "curl is required but not installed"
exit 1
fi
if ! command -v python3 &> /dev/null; then
log_fail "python3 is required but not installed"
exit 1
fi
log_pass "Dependencies OK"
}
# Start Unix socket listener that logs received data
start_socket_listener() {
log_info "Starting Unix socket listener on $SOCKET_PATH..."
rm -f "$SOCKET_PATH"
# Use Python script to listen on Unix socket
python3 /build/scripts/socket_listener.py "$SOCKET_PATH" -o "$LOG_OUTPUT" &
LISTENER_PID=$!
sleep 2
if ! kill -0 $LISTENER_PID 2>/dev/null; then
log_fail "Failed to start socket listener"
exit 1
fi
log_pass "Socket listener started (PID: $LISTENER_PID)"
}
# Create Apache test configuration
create_apache_config() {
log_info "Creating Apache test configuration..."
cat > /tmp/httpd_test.conf << EOF
ServerRoot "/etc/httpd"
Listen $APACHE_PORT
ServerName localhost
LoadModule reqin_log_module /build/.libs/mod_reqin_log.so
LoadModule mpm_event_module modules/mod_mpm_event.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule dir_module modules/mod_dir.so
LoadModule mime_module modules/mod_mime.so
LoadModule unixd_module modules/mod_unixd.so
LoadModule log_config_module modules/mod_log_config.so
User apache
Group apache
TypesConfig /etc/mime.types
DirectoryIndex index.html
JsonSockLogEnabled On
JsonSockLogSocket "$SOCKET_PATH"
JsonSockLogHeaders X-Request-Id User-Agent X-Test-Header
JsonSockLogMaxHeaders 10
JsonSockLogMaxHeaderValueLen 256
JsonSockLogReconnectInterval 5
JsonSockLogErrorReportInterval 5
<VirtualHost *:$APACHE_PORT>
DocumentRoot /var/www/html
<Directory /var/www/html>
Require all granted
</Directory>
</VirtualHost>
ErrorLog /dev/stderr
LogLevel warn
EOF
log_pass "Apache configuration created"
}
# Start Apache with test configuration
start_apache() {
log_info "Starting Apache with mod_reqin_log..."
# Create document root if needed
mkdir -p /var/www/html
echo "<html><body><h1>Test</h1></body></html>" > /var/www/html/index.html
# Check socket exists
if [ ! -S "$SOCKET_PATH" ]; then
log_fail "Socket file does not exist: $SOCKET_PATH"
ls -la /tmp/*.sock 2>&1 || true
exit 1
fi
log_info "Socket file exists: $SOCKET_PATH"
ls -la "$SOCKET_PATH"
# Start Apache and capture stderr
httpd -f /tmp/httpd_test.conf -DFOREGROUND 2>&1 &
APACHE_PID=$!
# Wait for Apache to start
sleep 2
if ! kill -0 $APACHE_PID 2>/dev/null; then
log_fail "Failed to start Apache"
exit 1
fi
log_pass "Apache started (PID: $APACHE_PID)"
# Wait for Apache workers to initialize and connect to socket
log_info "Waiting for Apache workers to initialize..."
sleep 3
}
# Send test HTTP requests
send_test_requests() {
log_info "Sending test HTTP requests..."
# Health check first
local retries=5
while [ $retries -gt 0 ]; do
if curl -s -o /dev/null -w "%{http_code}" "http://localhost:$APACHE_PORT/" | grep -q "200"; then
break
fi
sleep 1
retries=$((retries - 1))
done
if [ $retries -eq 0 ]; then
log_fail "Apache health check failed"
return 1
fi
log_info "Apache health check passed"
# Request 1: Basic GET
curl -s "http://localhost:$APACHE_PORT/" > /dev/null
sleep 0.5
# Request 2: With custom headers
curl -s -H "X-Request-Id: test-12345" "http://localhost:$APACHE_PORT/" > /dev/null
sleep 0.5
# Request 3: POST request
curl -s -X POST -d "test=data" "http://localhost:$APACHE_PORT/" > /dev/null
sleep 0.5
# Request 4: With User-Agent
curl -s -A "TestAgent/1.0" "http://localhost:$APACHE_PORT/api/test" > /dev/null
sleep 0.5
# Request 5: Multiple headers
curl -s \
-H "X-Request-Id: req-abc" \
-H "X-Test-Header: header-value" \
-H "User-Agent: Mozilla/5.0" \
"http://localhost:$APACHE_PORT/page" > /dev/null
sleep 1
log_pass "Test requests sent"
}
# Verify log output
verify_logs() {
log_info "Verifying log output..."
if [ ! -f "$LOG_OUTPUT" ]; then
log_fail "Log file not created"
return 1
fi
local log_count=$(wc -l < "$LOG_OUTPUT")
if [ "$log_count" -lt 1 ]; then
log_fail "Expected at least 1 log entry, got $log_count"
return 1
fi
log_pass "Received $log_count log entries"
# Show all log entries
log_info "Log file contents:"
cat "$LOG_OUTPUT"
# Verify JSON format
log_info "Validating JSON format..."
local invalid_json=0
while IFS= read -r line; do
if [ -n "$line" ]; then
if ! echo "$line" | python3 -m json.tool > /dev/null 2>&1; then
log_fail "Invalid JSON: $line"
invalid_json=1
fi
fi
done < "$LOG_OUTPUT"
if [ $invalid_json -eq 0 ]; then
log_pass "All JSON entries are valid"
fi
# Verify required fields
log_info "Checking required fields..."
local first_line=$(head -1 "$LOG_OUTPUT")
local required_fields=("time" "timestamp" "src_ip" "dst_ip" "method" "path" "host")
local missing_fields=0
for field in "${required_fields[@]}"; do
if ! echo "$first_line" | grep -q "\"$field\":"; then
log_fail "Missing required field: $field"
missing_fields=1
fi
done
if [ $missing_fields -eq 0 ]; then
log_pass "All required fields present"
fi
# Verify header logging
log_info "Checking header logging..."
if grep -q '"header_X-Request-Id"' "$LOG_OUTPUT"; then
log_pass "Custom headers are logged"
else
log_info "Custom headers test skipped (no X-Request-Id in requests)"
fi
# Verify HTTP methods
log_info "Checking HTTP methods..."
if grep -q '"method":"GET"' "$LOG_OUTPUT"; then
log_pass "GET method logged"
fi
if grep -q '"method":"POST"' "$LOG_OUTPUT"; then
log_pass "POST method logged"
fi
# Show sample log entry
log_info "Sample log entry (formatted):"
head -1 "$LOG_OUTPUT" | python3 -m json.tool 2>/dev/null || head -1 "$LOG_OUTPUT"
return 0
}
# Main test runner
main() {
echo "========================================"
echo "mod_reqin_log Unix Socket Integration Test"
echo "========================================"
echo ""
check_dependencies
start_socket_listener
create_apache_config
start_apache
send_test_requests
log_info "Waiting for logs to be written..."
sleep 2
verify_logs
local result=$?
echo ""
echo "========================================"
if [ $result -eq 0 ]; then
echo -e "${GREEN}All tests passed!${NC}"
else
echo -e "${RED}Some tests failed!${NC}"
fi
echo "========================================"
return $result
}
main "$@"