-
Notifications
You must be signed in to change notification settings - Fork 2
270 lines (234 loc) · 10.1 KB
/
integration-tests.yml
File metadata and controls
270 lines (234 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
name: Integration Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
schedule:
# Run integration tests nightly at 3 AM UTC to catch integration issues early
- cron: "0 3 * * *"
env:
REGISTRY: ghcr.io
IMAGE_PREFIX: ghcr.io/${{ github.repository_owner }}/nexuslims-test
jobs:
integration-test:
name: Integration Tests (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12", "3.13", "3.14"]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Determine image tag
id: image-tag
run: |
# Match the tag generation from build-test-images.yml
# For branches: use branch name
# For PRs: use pr-<number>
# For other: use sha
if [[ "${{ github.ref }}" == refs/heads/* ]]; then
TAG="${{ github.ref_name }}"
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
TAG="pr-${{ github.event.pull_request.number }}"
else
TAG="sha-${{ github.sha }}"
fi
# Replace / with - for valid Docker tags
TAG="${TAG//\//-}"
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "Using image tag: ${TAG}"
- name: Pull pre-built test images
continue-on-error: true
run: |
docker pull ${{ env.IMAGE_PREFIX }}-nemo:${{ steps.image-tag.outputs.tag }} || echo "Tagged NEMO image not found"
docker pull ${{ env.IMAGE_PREFIX }}-cdcs:${{ steps.image-tag.outputs.tag }} || echo "Tagged CDCS image not found"
docker pull ${{ env.IMAGE_PREFIX }}-elabftw:${{ steps.image-tag.outputs.tag }} || echo "Tagged eLabFTW image not found"
- name: Tag images for local use
continue-on-error: true
run: |
docker tag ${{ env.IMAGE_PREFIX }}-nemo:${{ steps.image-tag.outputs.tag }} nexuslims-test-nemo:latest 2>/dev/null || true
docker tag ${{ env.IMAGE_PREFIX }}-cdcs:${{ steps.image-tag.outputs.tag }} nexuslims-test-cdcs:latest 2>/dev/null || true
docker tag ${{ env.IMAGE_PREFIX }}-elabftw:${{ steps.image-tag.outputs.tag }} nexuslims-test-elabftw:latest 2>/dev/null || true
- name: Start Docker services
working-directory: tests/integration/docker
env:
REGISTRY: ${{ env.REGISTRY }}
IMAGE_OWNER: ${{ github.repository_owner }}
IMAGE_TAG: ${{ steps.image-tag.outputs.tag }}
run: |
# Try to use pre-built images with the PR/branch tag from build-test-images.yml
if docker image inspect nexuslims-test-nemo:latest >/dev/null 2>&1 && \
docker image inspect nexuslims-test-cdcs:latest >/dev/null 2>&1 && \
docker image inspect nexuslims-test-elabftw:latest >/dev/null 2>&1; then
echo "Using pre-built images from registry (tag: ${{ steps.image-tag.outputs.tag }})"
docker compose -f docker-compose.ci.yml up -d
else
echo "Pre-built images not available - building locally"
docker compose up -d
fi
- name: Wait for services to be healthy
run: |
echo "Waiting for NEMO to be ready..."
timeout 180 bash -c 'until curl -f http://localhost:48000/ > /dev/null 2>&1; do echo -n "."; sleep 3; done'
echo "✓ NEMO is ready"
echo "Waiting for CDCS to be ready..."
timeout 240 bash -c 'until curl -f http://localhost:48080/ > /dev/null 2>&1; do echo -n "."; sleep 5; done'
echo "✓ CDCS is ready"
echo "Waiting for eLabFTW to be ready..."
timeout 240 bash -c 'until curl -fk https://localhost:48148/login.php > /dev/null 2>&1; do echo -n "."; sleep 5; done'
echo "✓ eLabFTW is ready"
echo "Waiting for MailPit to be ready..."
timeout 60 bash -c 'until curl -f http://localhost:48025/ > /dev/null 2>&1; do echo -n "."; sleep 2; done'
echo "✓ MailPit is ready"
- name: Show Docker service status
if: always()
working-directory: tests/integration/docker
run: docker compose ps
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y findutils
- name: Set up uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync
- name: Run all tests (unit + integration)
run: |
uv run pytest tests/ \
-v \
--override-ini=addopts= \
--mpl \
--mpl-baseline-path=tests/unit/files/figs \
--cov=nexusLIMS \
--cov-report html:tests/coverage-combined \
--cov-report term-missing \
--cov-report=xml:coverage-combined.xml \
--tb=short \
--maxfail=5
env:
# Integration test environment variables
PYTEST_TIMEOUT: 600
- name: Upload combined test coverage
uses: actions/upload-artifact@v4
with:
name: coverage-combined-${{ matrix.python-version }}
path: |
.coverage
coverage-combined.xml
include-hidden-files: true
- name: Upload HTML coverage report
if: matrix.python-version == '3.11'
uses: actions/upload-artifact@v4
with:
name: coverage-combined-html
path: tests/coverage-combined
- name: Collect Docker container logs
if: always()
working-directory: tests/integration/docker
run: |
mkdir -p ../../docker-logs
# Debug: Show what containers exist
echo "=== Running Containers ==="
docker ps -a --filter "name=nexuslims-test" || true
echo ""
# Determine which compose file was used and collect logs
if docker image inspect nexuslims-test-nemo:latest >/dev/null 2>&1 && \
docker image inspect nexuslims-test-cdcs:latest >/dev/null 2>&1 && \
docker image inspect nexuslims-test-elabftw:latest >/dev/null 2>&1; then
COMPOSE_FILE="docker-compose.ci.yml"
else
COMPOSE_FILE="docker-compose.yml"
fi
echo "Collecting logs from compose stack (using $COMPOSE_FILE)..."
# Collect full compose logs (try both approaches)
docker compose -f "$COMPOSE_FILE" logs --no-color > ../../docker-logs/docker-compose.log 2>&1 || true
# Also try collecting by container name directly as fallback
for container in nexuslims-test-nemo nexuslims-test-cdcs nexuslims-test-cdcs-mongo nexuslims-test-cdcs-postgres nexuslims-test-cdcs-redis nexuslims-test-elabftw nexuslims-test-elabftw-mysql nexuslims-test-mailpit nexuslims-test-caddy-proxy; do
docker logs "$container" > "../../docker-logs/${container##*-}.log" 2>&1 || true
done
# Display summary to action logs
echo "=== Docker Logs Summary ==="
du -sh ../../docker-logs/* 2>/dev/null || echo "No logs collected"
echo ""
echo "=== Log Files Created ==="
ls -lh ../../docker-logs/ 2>/dev/null || echo "No log directory"
- name: Display Docker logs on failure
if: failure()
run: |
echo "=== Docker Compose Full Log ==="
cat docker-logs/docker-compose.log 2>/dev/null || echo "No compose log available"
echo ""
echo "=== NEMO Log ==="
cat docker-logs/nemo.log 2>/dev/null || echo "No NEMO log available"
echo ""
echo "=== CDCS Log ==="
cat docker-logs/cdcs.log 2>/dev/null || echo "No CDCS log available"
echo ""
echo "=== MongoDB Log ==="
cat docker-logs/mongo.log 2>/dev/null || echo "No MongoDB log available"
echo ""
echo "=== PostgreSQL Log ==="
cat docker-logs/postgres.log 2>/dev/null || echo "No PostgreSQL log available"
echo ""
echo "=== Redis Log ==="
cat docker-logs/redis.log 2>/dev/null || echo "No Redis log available"
echo ""
echo "=== eLabFTW Log ==="
cat docker-logs/elabftw.log 2>/dev/null || echo "No eLabFTW log available"
echo ""
echo "=== eLabFTW MySQL Log ==="
cat docker-logs/mysql.log 2>/dev/null || echo "No eLabFTW MySQL log available"
echo ""
echo "=== Mailpit Log ==="
cat docker-logs/mailpit.log 2>/dev/null || echo "No Mailpit log available"
echo ""
echo "=== Caddy Proxy Log ==="
cat docker-logs/proxy.log 2>/dev/null || echo "No Caddy Proxy log available"
- name: Upload Docker logs artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: docker-logs-${{ matrix.python-version }}
path: tests/docker-logs/
if-no-files-found: ignore
- name: Cleanup Docker services
if: always()
working-directory: tests/integration/docker
run: |
docker compose down -v --remove-orphans || true
upload-coverage:
name: Upload Combined Coverage to Codecov
needs: integration-test
runs-on: ubuntu-latest
if: always()
steps:
- uses: actions/checkout@v4
- name: Download all coverage artifacts
uses: actions/download-artifact@v4
with:
pattern: coverage-combined-*
path: coverage-reports
- name: Upload combined coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage-reports/**/*.xml
flags: combined
fail_ci_if_error: false