Testing
Testing Guide¶
Complete guide to testing in TrikuSec.
Test Structure¶
All tests use pytest (not Django's unittest):
src/api/tests.py- Unit tests for API endpointssrc/api/tests_integration.py- Integration testssrc/api/tests_middleware.py- Middleware testssrc/api/tests_policy_security.py- Policy security testssrc/frontend/tests_e2e.py- End-to-end tests (Playwright)src/conftest.py- Shared pytest fixturessrc/frontend/conftest.py- E2E test fixtures
Running Tests¶
All Tests¶
Unit Tests Only¶
docker compose -f docker-compose.dev.yml --profile test run --rm test pytest -m "not integration and not e2e" -v
Note: E2E tests are automatically skipped if Playwright is not available. The -m "not e2e" marker explicitly excludes them for clarity.
Integration Tests Only¶
Run Lynis Client Integration Flow Manually (Dev)¶
Use this when you want to validate the real enrollment/upload flow against your running dev stack.
1) Ensure services are running:
2) Create (or update) a license key in DB:
export TRIKUSEC_LICENSE_KEY=aaaaaaaa-bbbbbbbb-cccccccc
docker compose -f docker-compose.dev.yml exec trikusec-manager \
python manage.py populate_db_licensekey "$TRIKUSEC_LICENSE_KEY" --name "Dev Integration License"
3) Run the Lynis client container once:
docker compose -f docker-compose.dev.yml run --rm \
-e TRIKUSEC_LICENSE_KEY="$TRIKUSEC_LICENSE_KEY" \
lynis-client
This should enroll/upload a device that appears in the Devices view.
Seed Example Devices for Manual UI Testing¶
If you only need sample data quickly (without running full Lynis audit), post synthetic reports directly to the upload endpoint.
export TRIKUSEC_LICENSE_KEY=aaaaaaaa-bbbbbbbb-cccccccc
# Ensure the license exists
docker compose -f docker-compose.dev.yml exec trikusec-manager \
python manage.py populate_db_licensekey "$TRIKUSEC_LICENSE_KEY" --name "Dev Seed License"
# Seed 12 demo devices
for i in $(seq 1 12); do
REPORT=$(cat <<EOF
# Lynis Report
report_version_major=1
report_version_minor=0
hostname=demo-device-$i
os=Linux
os_fullname=Ubuntu 22.04 LTS
os_version=22.04
lynis_version=3.0.9
uptime_in_days=$((RANDOM % 120))
warning_count=$((RANDOM % 15))
vulnerable_packages_found=$((RANDOM % 8))
hardening_index=$((50 + RANDOM % 45))
report_datetime_end=2026-05-06 12:00:00
finish=true
EOF
)
curl -sk -X POST "https://localhost:8001/api/lynis/upload/" \
--data-urlencode "licensekey=${TRIKUSEC_LICENSE_KEY}" \
--data-urlencode "hostid=demo-hostid-$i" \
--data-urlencode "hostid2=demo-hostid2-$i" \
--data-urlencode "data=${REPORT}" >/dev/null
echo "Uploaded demo device $i"
done
This is the fastest way to populate the device list for manual feature validation.
E2E Tests Only¶
E2E tests require Playwright and must be run in the test-e2e service:
See E2E Testing Documentation for detailed information.
Specific Test File¶
Specific Test¶
docker compose -f docker-compose.dev.yml --profile test run --rm test pytest api/tests.py::TestUploadReport::test_upload_report_valid_license_new_device -v
With Coverage¶
docker compose -f docker-compose.dev.yml --profile test run --rm test pytest --cov=api --cov=frontend --cov-report=html --cov-report=term-missing
Test Types¶
Unit Tests¶
Test individual components in isolation:
- API endpoints
- Models
- Forms
- Utilities
Integration Tests¶
Test end-to-end workflows:
- Lynis report upload
- License validation
- Policy compliance
Middleware Tests¶
Test custom middleware:
- Rate limiting
- Security headers
- Error handling
E2E Tests¶
Test complete user workflows in a real browser:
- Frontend interactions
- Form submissions
- Sidebar state management
- User flows
See E2E Testing Documentation for details.
Test Fixtures¶
Fixtures are defined in src/conftest.py:
license_key- Sample license keydevice- Sample devicelynis_report- Mock Lynis report data
Writing Tests¶
Example Unit Test¶
import pytest
from api.views import upload_report
def test_upload_report_valid_license(client, license_key):
response = client.post('/api/lynis/upload/', {
'licensekey': license_key.licensekey,
'hostid': 'test-host',
'data': 'base64-encoded-data'
})
assert response.status_code == 200
Example Integration Test¶
@pytest.mark.integration
def test_lynis_workflow(client, license_key):
# Upload report
response = client.post('/api/lynis/upload/', {...})
assert response.status_code == 200
# Check device created
device = Device.objects.get(hostid='test-host')
assert device is not None
Test Database¶
The test container automatically: - Runs migrations before tests - Uses a separate test database - Cleans up after tests
Continuous Integration¶
Tests run automatically on:
- Push to main or develop branches
- Pull requests
CI runs three separate test jobs: 1. Unit Tests - Fast unit tests (excludes integration and E2E tests) 2. Integration Tests - End-to-end API workflows with Lynis client 3. E2E Tests - Browser-based frontend tests with Playwright
See .github/workflows/test.yml for CI configuration.
Best Practices¶
- Isolation - Each test should be independent
- Fixtures - Use fixtures for common test data
- Naming - Use descriptive test names
- Coverage - Aim for high test coverage
- Speed - Keep tests fast
Next Steps¶
- Development Setup - Development environment
- Contributing - Contribution guidelines