Skip to content

Commit a3e20ea

Browse files
committed
feat(labs): implement Lab 16-02 external dependencies (MariaDB + Mailhog)
1 parent df39be2 commit a3e20ea

3 files changed

Lines changed: 217 additions & 44 deletions

File tree

.github/workflows/ci.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,39 @@ run: bash tests/labs/test-lab-16-01.sh
111111
- name: Cleanup
112112
if: always()
113113
run: docker compose -f docker/docker-compose.standalone.yml down -v
114+
lab-02-smoke:
115+
name: Lab 02 -- Snipe-IT External Dependencies (MariaDB + Mailhog)
116+
runs-on: ubuntu-latest
117+
needs: validate
118+
continue-on-error: true
119+
steps:
120+
- uses: actions/checkout@v4
121+
122+
- name: Install tools
123+
run: sudo apt-get install -y curl default-mysql-client -qq
124+
125+
- name: Validate LAN compose
126+
run: docker compose -f docker/docker-compose.lan.yml config -q && echo "LAN compose valid"
127+
128+
- name: Start LAN stack
129+
run: docker compose -f docker/docker-compose.lan.yml up -d
130+
131+
- name: Wait for MariaDB
132+
run: timeout 120 bash -c 'until docker exec snipeit-l02-db mysqladmin ping -uroot -pRootLab02! --silent; do sleep 5; done'
133+
134+
- name: Wait for Mailhog
135+
run: timeout 60 bash -c 'until curl -sf http://localhost:8711/api/v2/messages; do sleep 5; done'
136+
137+
- name: Wait for Snipe-IT web
138+
run: timeout 300 bash -c 'until curl -o /dev/null -sw "%{http_code}" http://localhost:8411/ | grep -q "^[234]"; do sleep 10; done'
139+
140+
- name: Run Lab 16-02 test script
141+
run: bash tests/labs/test-lab-16-02.sh --no-cleanup
142+
143+
- name: Collect logs on failure
144+
if: failure()
145+
run: docker compose -f docker/docker-compose.lan.yml logs
146+
147+
- name: Cleanup
148+
if: always()
149+
run: docker compose -f docker/docker-compose.lan.yml down -v

docker/docker-compose.lan.yml

Lines changed: 76 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,90 @@
1-
# Lab 02 — External Dependencies: snipeit with external PostgreSQL and Redis
1+
# Lab 02 — External Dependencies: Snipe-IT with external MariaDB and Mailhog
2+
# Models the LAN tier: MariaDB on data-net (simulates lab-db1), app on app-net.
3+
# Snipe-IT: http://localhost:8411
4+
# Mailhog: http://localhost:8711
25
---
6+
name: it-stack-snipeit-lab02
7+
38
services:
4-
snipeit:
5-
image: snipe/snipe-it:latest
6-
container_name: it-stack-snipeit
9+
10+
# ── External Database (simulates lab-db1) ─────────────────────────────────
11+
snipeit-l02-db:
12+
image: mariadb:10.11
13+
container_name: snipeit-l02-db
714
restart: unless-stopped
8-
ports:
9-
- "80:$firstPort"
1015
environment:
11-
- IT_STACK_ENV=lab-02-lan
12-
- DB_HOST=
13-
- DB_PORT=5432
14-
- REDIS_HOST=
16+
MARIADB_ROOT_PASSWORD: RootLab02!
17+
MARIADB_DATABASE: snipeit
18+
MARIADB_USER: snipeit
19+
MARIADB_PASSWORD: SnipeLab02!
20+
volumes:
21+
- snipeit-l02-db-data:/var/lib/mysql
22+
healthcheck:
23+
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
24+
interval: 10s
25+
timeout: 5s
26+
retries: 10
27+
start_period: 30s
1528
networks:
16-
- it-stack-net
29+
- snipeit-l02-data-net
1730

18-
# Lightweight local DB for lab (replace with lab-db1 in real env)
19-
postgres:
20-
image: postgres:16
21-
container_name: it-stack-snipeit-db
31+
# ── External SMTP relay (Mailhog) ─────────────────────────────────────────
32+
snipeit-l02-mail:
33+
image: mailhog/mailhog:latest
34+
container_name: snipeit-l02-mail
35+
restart: unless-stopped
36+
ports:
37+
- "8711:8025"
38+
networks:
39+
- snipeit-l02-app-net
40+
41+
# ── Snipe-IT application ───────────────────────────────────────────────────
42+
snipeit-l02-app:
43+
image: snipe/snipe-it:latest
44+
container_name: snipeit-l02-app
45+
restart: unless-stopped
46+
depends_on:
47+
snipeit-l02-db:
48+
condition: service_healthy
49+
snipeit-l02-mail:
50+
condition: service_started
2251
environment:
23-
POSTGRES_DB: snipeit_db
24-
POSTGRES_USER: snipeit_user
25-
POSTGRES_PASSWORD: snipeit_pass
52+
APP_ENV: local
53+
APP_DEBUG: "false"
54+
APP_KEY: "base64:3HLPbBKd9G4zWPKnQLxh4OTCKNWCGbSZFGbpfbpHPqk="
55+
APP_URL: "http://localhost:8411"
56+
DB_CONNECTION: mysql
57+
DB_HOST: snipeit-l02-db
58+
DB_PORT: "3306"
59+
DB_DATABASE: snipeit
60+
DB_USERNAME: snipeit
61+
DB_PASSWORD: SnipeLab02!
62+
MAIL_DRIVER: smtp
63+
MAIL_HOST: snipeit-l02-mail
64+
MAIL_PORT: "1025"
65+
MAIL_ENCRYPTION: "null"
66+
SESSION_DRIVER: file
67+
CACHE_DRIVER: file
68+
ports:
69+
- "8411:80"
2670
volumes:
27-
- snipeit_pg_data:/var/lib/postgresql/data
71+
- snipeit-l02-data:/var/lib/snipeit
72+
healthcheck:
73+
test: ["CMD-SHELL", "curl -sf http://localhost/health || exit 1"]
74+
interval: 30s
75+
timeout: 15s
76+
retries: 8
77+
start_period: 120s
2878
networks:
29-
- it-stack-net
79+
- snipeit-l02-data-net
80+
- snipeit-l02-app-net
3081

3182
networks:
32-
it-stack-net:
83+
snipeit-l02-data-net:
84+
driver: bridge
85+
snipeit-l02-app-net:
3386
driver: bridge
3487

3588
volumes:
36-
snipeit_pg_data:
89+
snipeit-l02-db-data:
90+
snipeit-l02-data:

tests/labs/test-lab-16-02.sh

Lines changed: 105 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,38 +26,121 @@ echo -e "${CYAN} Module: ${MODULE}${NC}"
2626
echo -e "${CYAN}======================================${NC}"
2727
echo ""
2828

29+
# ── Cleanup control ───────────────────────────────────────────────────────────
30+
CLEANUP=true
31+
[[ "${1:-}" == "--no-cleanup" ]] && CLEANUP=false
32+
33+
cleanup() {
34+
if [[ "${CLEANUP}" == "true" ]]; then
35+
info "Phase 4: Cleanup"
36+
docker compose -f "${COMPOSE_FILE}" down -v --remove-orphans 2>/dev/null || true
37+
info "Cleanup complete"
38+
else
39+
info "Skipping cleanup (--no-cleanup)"
40+
fi
41+
}
42+
trap cleanup EXIT
43+
2944
# ── PHASE 1: Setup ────────────────────────────────────────────────────────────
3045
info "Phase 1: Setup"
3146
docker compose -f "${COMPOSE_FILE}" up -d
32-
info "Waiting 30s for ${MODULE} to initialize..."
33-
sleep 30
3447

3548
# ── PHASE 2: Health Checks ────────────────────────────────────────────────────
3649
info "Phase 2: Health Checks"
3750

38-
if docker compose -f "${COMPOSE_FILE}" ps | grep -q "running\|Up"; then
39-
pass "Container is running"
51+
info "Waiting for external MariaDB (snipeit-l02-db, up to 90s)..."
52+
for i in $(seq 1 18); do
53+
if docker exec snipeit-l02-db mysqladmin ping -uroot -pRootLab02! --silent 2>/dev/null; then
54+
pass "External MariaDB healthy"
55+
break
56+
fi
57+
[[ $i -eq 18 ]] && fail "External MariaDB timed out after 90s"
58+
sleep 5
59+
done
60+
61+
info "Waiting for Mailhog (snipeit-l02-mail, up to 60s)..."
62+
for i in $(seq 1 12); do
63+
if curl -sf http://localhost:8711/api/v2/messages >/dev/null 2>&1; then
64+
pass "Mailhog API reachable"
65+
break
66+
fi
67+
[[ $i -eq 12 ]] && fail "Mailhog timed out after 60s"
68+
sleep 5
69+
done
70+
71+
info "Waiting for Snipe-IT web (snipeit-l02-app, up to 300s)..."
72+
for i in $(seq 1 30); do
73+
http_code=$(curl -o /dev/null -sw '%{http_code}' http://localhost:8411/ 2>/dev/null || echo "000")
74+
if [[ "${http_code}" =~ ^[234] ]]; then
75+
pass "Snipe-IT web responding (HTTP ${http_code})"
76+
break
77+
fi
78+
[[ $i -eq 30 ]] && fail "Snipe-IT web timed out after 300s"
79+
sleep 10
80+
done
81+
82+
# ── PHASE 3: Functional Tests ─────────────────────────────────────────────────
83+
info "Phase 3: Functional Tests (Lab 16-02 — External Dependencies)"
84+
85+
# Container states
86+
for svc in snipeit-l02-db snipeit-l02-mail snipeit-l02-app; do
87+
state=$(docker inspect --format='{{.State.Status}}' "${svc}" 2>/dev/null || echo "missing")
88+
if [[ "${state}" == "running" ]]; then
89+
pass "Container ${svc} is running"
90+
else
91+
fail "Container ${svc} state: ${state}"
92+
fi
93+
done
94+
95+
# DB connectivity from app container
96+
table_count=$(docker exec snipeit-l02-db \
97+
mysql -usnipeit -pSnipeLab02! snipeit -e 'SHOW TABLES;' 2>/dev/null | wc -l | tr -d ' ')
98+
if [[ "${table_count}" -gt 5 ]]; then
99+
pass "Snipe-IT database has ${table_count} tables (migrations ran)"
40100
else
41-
fail "Container is not running"
101+
warn "Snipe-IT database tables: ${table_count} (migrations may still be running)"
42102
fi
43103

44-
# ── PHASE 3: Functional Tests ─────────────────────────────────────────────────
45-
info "Phase 3: Functional Tests (Lab 02 — External Dependencies)"
46-
47-
# TODO: Add module-specific functional tests here
48-
# Example:
49-
# if curl -sf http://localhost:80/health > /dev/null 2>&1; then
50-
# pass "Health endpoint responds"
51-
# else
52-
# fail "Health endpoint not reachable"
53-
# fi
54-
55-
warn "Functional tests for Lab 16-02 pending implementation"
56-
57-
# ── PHASE 4: Cleanup ──────────────────────────────────────────────────────────
58-
info "Phase 4: Cleanup"
59-
docker compose -f "${COMPOSE_FILE}" down -v --remove-orphans
60-
info "Cleanup complete"
104+
# Mailhog API format check
105+
mailhog_resp=$(curl -sf http://localhost:8711/api/v2/messages 2>/dev/null || echo "{}")
106+
if echo "${mailhog_resp}" | grep -q 'total\|items\|count'; then
107+
pass "Mailhog API returns valid JSON message list"
108+
else
109+
fail "Mailhog API response unexpected: ${mailhog_resp}"
110+
fi
111+
112+
# HTTP status check
113+
http_code=$(curl -o /dev/null -sw '%{http_code}' -L http://localhost:8411/ 2>/dev/null || echo "000")
114+
if [[ "${http_code}" =~ ^[234] ]]; then
115+
pass "Snipe-IT HTTP GET / -> ${http_code}"
116+
else
117+
fail "Snipe-IT HTTP GET / -> ${http_code}"
118+
fi
119+
120+
# Login page present
121+
if curl -sf -L http://localhost:8411/ 2>/dev/null | grep -qi 'snipe\|login\|email\|password'; then
122+
pass "Snipe-IT login page rendered"
123+
else
124+
warn "Snipe-IT login page check inconclusive"
125+
fi
126+
127+
# Key env vars present in app container
128+
for var in DB_HOST DB_DATABASE APP_KEY APP_URL MAIL_HOST; do
129+
if docker exec snipeit-l02-app printenv "${var}" 2>/dev/null | grep -q '.'; then
130+
pass "Env var ${var} set in snipeit-l02-app"
131+
else
132+
fail "Env var ${var} missing in snipeit-l02-app"
133+
fi
134+
done
135+
136+
# Volume existence
137+
for vol in snipeit-l02-db-data snipeit-l02-data; do
138+
if docker volume ls --format '{{.Name}}' | grep -q "${vol}"; then
139+
pass "Volume ${vol} exists"
140+
else
141+
fail "Volume ${vol} missing"
142+
fi
143+
done
61144

62145
# ── Results ───────────────────────────────────────────────────────────────────
63146
echo ""

0 commit comments

Comments
 (0)