11#! /usr/bin/env bash
22# test-lab-13-03.sh — Lab 13-03: Advanced Features
3- # Module 13: Odoo ERP and business management
4- # odoo with TLS, resource limits, and production-grade configuration
3+ # Module 13: Odoo ERP
4+ # Tests: multi-worker + gevent longpolling port + Redis + resource limits
55set -euo pipefail
66
77LAB_ID=" 13-03"
@@ -11,61 +11,164 @@ COMPOSE_FILE="docker/docker-compose.advanced.yml"
1111PASS=0
1212FAIL=0
1313
14- # ── Colors ────────────────────────────────────────────────────────────────────
1514RED=' \033[0;31m' ; GREEN=' \033[0;32m' ; YELLOW=' \033[1;33m'
1615CYAN=' \033[0;36m' ; NC=' \033[0m'
1716
18- pass () { echo -e " ${GREEN} [PASS]${NC} $1 " ; (( PASS++ )) ; }
19- fail () { echo -e " ${RED} [FAIL]${NC} $1 " ; (( FAIL++ )) ; }
20- info () { echo -e " ${CYAN} [INFO] $ {NC} $1 " ; }
21- warn () { echo -e " ${YELLOW} [WARN ]${NC} $1 " ; }
17+ pass () { echo -e " ${GREEN} [PASS]${NC} $1 " ; (( PASS++ )) ; }
18+ fail () { echo -e " ${RED} [FAIL]${NC} $1 " ; (( FAIL++ )) ; }
19+ section () { echo -e " \n ${CYAN} ── $1 ── $ {NC}" ; }
20+ info () { echo -e " ${CYAN} [INFO ]${NC} $1 " ; }
2221
23- echo -e " ${CYAN} ======================================${NC} "
22+ CLEANUP=true
23+ [[ " ${1:- } " == " --no-cleanup" ]] && CLEANUP=false
24+
25+ cleanup () {
26+ if [[ " ${CLEANUP} " == " true" ]]; then
27+ info " Cleaning up..."
28+ docker compose -f " ${COMPOSE_FILE} " down -v --remove-orphans 2> /dev/null || true
29+ fi
30+ }
31+ trap cleanup EXIT
32+
33+ echo -e " ${CYAN} ========================================${NC} "
2434echo -e " ${CYAN} Lab ${LAB_ID} : ${LAB_NAME}${NC} "
2535echo -e " ${CYAN} Module: ${MODULE}${NC} "
26- echo -e " ${CYAN} ======================================${NC} "
27- echo " "
36+ echo -e " ${CYAN} ========================================${NC} "
2837
2938# ── PHASE 1: Setup ────────────────────────────────────────────────────────────
30- info " Phase 1: Setup"
39+ section " Phase 1: Setup"
3140docker compose -f " ${COMPOSE_FILE} " up -d
32- info " Waiting 30s for ${MODULE} to initialize..."
33- sleep 30
3441
3542# ── PHASE 2: Health Checks ────────────────────────────────────────────────────
36- info " Phase 2: Health Checks"
43+ section " Phase 2: Health Checks"
44+
45+ info " Waiting for PostgreSQL (up to 60s)..."
46+ for i in $( seq 1 12) ; do
47+ if docker exec odoo-a03-db pg_isready -U odoo -d odoo_lab03 > /dev/null 2>&1 ; then
48+ pass " PostgreSQL healthy" ; break
49+ fi
50+ [[ $i -eq 12 ]] && fail " PostgreSQL timed out"
51+ sleep 5
52+ done
3753
38- if docker compose -f " ${COMPOSE_FILE} " ps | grep -q " running\|Up" ; then
39- pass " Container is running"
54+ info " Waiting for Redis (up to 30s)..."
55+ for i in $( seq 1 6) ; do
56+ if docker exec odoo-a03-redis redis-cli ping 2> /dev/null | grep -q PONG; then
57+ pass " Redis healthy (PONG)" ; break
58+ fi
59+ [[ $i -eq 6 ]] && fail " Redis not responding"
60+ sleep 5
61+ done
62+
63+ info " Waiting for Mailhog (up to 60s)..."
64+ for i in $( seq 1 12) ; do
65+ if curl -sf http://localhost:8630/api/v2/messages > /dev/null 2>&1 ; then
66+ pass " Mailhog reachable on :8630" ; break
67+ fi
68+ [[ $i -eq 12 ]] && fail " Mailhog not reachable on :8630"
69+ sleep 5
70+ done
71+
72+ info " Waiting for Odoo web (up to 2 min)..."
73+ for i in $( seq 1 24) ; do
74+ if curl -sf http://localhost:8330/web/health 2> /dev/null | grep -q ' ok\|pass' ; then
75+ pass " Odoo /web/health OK on :8330" ; break
76+ fi
77+ [[ $i -eq 24 ]] && fail " Odoo not reachable on :8330"
78+ sleep 5
79+ done
80+
81+ # ── PHASE 3: Functional Tests ─────────────────────────────────────────────────
82+ section " Phase 3: Functional Tests"
83+
84+ # Containers
85+ for cname in odoo-a03-db odoo-a03-redis odoo-a03-mail odoo-a03-app; do
86+ if docker inspect " ${cname} " --format ' {{.State.Status}}' 2> /dev/null | grep -q running; then
87+ pass " ${cname} running"
88+ else
89+ fail " ${cname} not running"
90+ fi
91+ done
92+
93+ # Gevent longpolling port
94+ info " Waiting for Odoo gevent longpoll on :8331 (up to 60s)..."
95+ for i in $( seq 1 12) ; do
96+ if curl -sf http://localhost:8331/ > /dev/null 2>&1 ; then
97+ pass " Odoo gevent longpolling reachable on :8331" ; break
98+ fi
99+ [[ $i -eq 12 ]] && fail " Odoo gevent longpolling not reachable on :8331"
100+ sleep 5
101+ done
102+
103+ # Multi-worker: multiple odoo processes
104+ WORKER_COUNT=$( docker exec odoo-a03-app pgrep -c ' python\|odoo' 2> /dev/null || echo 0)
105+ if [[ " ${WORKER_COUNT:- 0} " -ge 2 ]]; then
106+ pass " Odoo running ${WORKER_COUNT} worker processes"
40107else
41- fail " Container is not running "
108+ fail " Odoo has only ${WORKER_COUNT :- 0} processes (expected ≥2 with --workers=2) "
42109fi
43110
44- # ── PHASE 3: Functional Tests ─────────────────────────────────────────────────
45- info " Phase 3: Functional Tests (Lab 03 — Advanced Features)"
111+ # Redis connectivity from app
112+ if docker exec odoo-a03-app redis-cli -h odoo-a03-redis ping 2> /dev/null | grep -q PONG; then
113+ pass " App connects to Redis"
114+ else
115+ fail " App cannot reach Redis"
116+ fi
46117
47- # TODO: Add module-specific functional tests here
48- # Example:
49- # if curl -sf http://localhost:8069/health > /dev/null 2>&1; then
50- # pass "Health endpoint responds"
51- # else
52- # fail "Health endpoint not reachable"
53- # fi
118+ # /web/health
119+ if curl -sf http://localhost:8330/web/health | grep -q ' ok\|pass' ; then
120+ pass " Odoo /web/health endpoint OK"
121+ else
122+ fail " Odoo /web/health endpoint failed"
123+ fi
124+
125+ # JSON-RPC
126+ DB_LIST=$( curl -sf -X POST http://localhost:8330/web/database/get_list \
127+ -H ' Content-Type: application/json' \
128+ -d ' {"jsonrpc":"2.0","method":"call","params":{}}' 2> /dev/null || echo " {}" )
129+ if echo " ${DB_LIST} " | grep -q ' result' ; then
130+ pass " Odoo JSON-RPC /web/database/get_list OK"
131+ else
132+ fail " Odoo JSON-RPC not responding"
133+ fi
134+
135+ # Resource limits
136+ MEM_LIMIT=$( docker inspect odoo-a03-app --format ' {{.HostConfig.Memory}}' 2> /dev/null || echo 0)
137+ if [[ " ${MEM_LIMIT:- 0} " -gt 0 ]]; then
138+ pass " Memory limit set on odoo-a03-app (${MEM_LIMIT} bytes)"
139+ else
140+ fail " No memory limit on odoo-a03-app"
141+ fi
54142
55- warn " Functional tests for Lab 13-03 pending implementation"
143+ # CPU limit
144+ CPU_LIMIT=$( docker inspect odoo-a03-app --format ' {{.HostConfig.NanoCpus}}' 2> /dev/null || echo 0)
145+ if [[ " ${CPU_LIMIT:- 0} " -gt 0 ]]; then
146+ pass " CPU limit set on odoo-a03-app"
147+ else
148+ fail " No CPU limit on odoo-a03-app"
149+ fi
56150
57- # ── PHASE 4: Cleanup ──────────────────────────────────────────────────────────
58- info " Phase 4: Cleanup"
59- docker compose -f " ${COMPOSE_FILE} " down -v --remove-orphans
60- info " Cleanup complete"
151+ # Mailhog API
152+ if curl -sf http://localhost:8630/api/v2/messages | grep -q ' total\|items' ; then
153+ pass " Mailhog API valid"
154+ else
155+ fail " Mailhog API invalid"
156+ fi
157+
158+ # Volumes
159+ for vol in odoo-a03-db-data odoo-a03-redis-data odoo-a03-data odoo-a03-addons; do
160+ if docker volume ls --format ' {{.Name}}' | grep -q " ${vol} " ; then
161+ pass " Volume ${vol} exists"
162+ else
163+ fail " Volume ${vol} missing"
164+ fi
165+ done
61166
62167# ── Results ───────────────────────────────────────────────────────────────────
63168echo " "
64- echo -e " ${CYAN} ======================================${NC} "
65- echo -e " Lab ${LAB_ID} Complete "
169+ echo -e " ${CYAN} ======================================== ${NC} "
170+ echo " Lab ${LAB_ID} Results "
66171echo -e " ${GREEN} PASS: ${PASS}${NC} | ${RED} FAIL: ${FAIL}${NC} "
67- echo -e " ${CYAN} ======================================${NC} "
68-
69- if [ " ${FAIL} " -gt 0 ]; then
70- exit 1
71- fi
172+ echo -e " ${CYAN} ========================================${NC} "
173+ [[ " ${FAIL} " -gt 0 ]] && exit 1
174+ exit 0
0 commit comments