test_docker.sh 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. #!/bin/bash
  2. #
  3. # Docker Test Suite for BamBuddy
  4. # Runs build verification, unit tests, and integration tests in Docker
  5. #
  6. set -e
  7. # Configuration
  8. PORT=${PORT:-8000}
  9. # Enable BuildKit for better caching and parallel builds
  10. export DOCKER_BUILDKIT=1
  11. export COMPOSE_DOCKER_CLI_BUILD=1
  12. # Colors for output
  13. RED='\033[0;31m'
  14. GREEN='\033[0;32m'
  15. YELLOW='\033[1;33m'
  16. BLUE='\033[0;34m'
  17. NC='\033[0m' # No Color
  18. # Track results
  19. TESTS_PASSED=0
  20. TESTS_FAILED=0
  21. FAILED_TESTS=""
  22. print_header() {
  23. echo ""
  24. echo -e "${BLUE}========================================${NC}"
  25. echo -e "${BLUE} $1${NC}"
  26. echo -e "${BLUE}========================================${NC}"
  27. }
  28. print_success() {
  29. echo -e "${GREEN}✓ $1${NC}"
  30. TESTS_PASSED=$((TESTS_PASSED + 1))
  31. }
  32. print_failure() {
  33. echo -e "${RED}✗ $1${NC}"
  34. TESTS_FAILED=$((TESTS_FAILED + 1))
  35. FAILED_TESTS="${FAILED_TESTS}\n - $1"
  36. }
  37. print_info() {
  38. echo -e "${YELLOW}→ $1${NC}"
  39. }
  40. cleanup() {
  41. print_info "Cleaning up test containers..."
  42. sudo docker compose -f docker-compose.test.yml down -v --remove-orphans 2>/dev/null || true
  43. sudo docker compose down -v --remove-orphans 2>/dev/null || true
  44. }
  45. # Cleanup on exit
  46. trap cleanup EXIT
  47. # Parse arguments
  48. RUN_BUILD=true
  49. RUN_BACKEND=true
  50. RUN_FRONTEND=true
  51. RUN_INTEGRATION=true
  52. FRESH_BUILD=false
  53. while [[ $# -gt 0 ]]; do
  54. case $1 in
  55. --build-only)
  56. RUN_BACKEND=false
  57. RUN_FRONTEND=false
  58. RUN_INTEGRATION=false
  59. shift
  60. ;;
  61. --backend-only)
  62. RUN_BUILD=false
  63. RUN_FRONTEND=false
  64. RUN_INTEGRATION=false
  65. shift
  66. ;;
  67. --frontend-only)
  68. RUN_BUILD=false
  69. RUN_BACKEND=false
  70. RUN_INTEGRATION=false
  71. shift
  72. ;;
  73. --integration-only)
  74. RUN_BUILD=false
  75. RUN_BACKEND=false
  76. RUN_FRONTEND=false
  77. shift
  78. ;;
  79. --skip-build)
  80. RUN_BUILD=false
  81. shift
  82. ;;
  83. --skip-integration)
  84. RUN_INTEGRATION=false
  85. shift
  86. ;;
  87. --fresh)
  88. FRESH_BUILD=true
  89. shift
  90. ;;
  91. -h|--help)
  92. echo "Usage: $0 [OPTIONS]"
  93. echo ""
  94. echo "Options:"
  95. echo " --build-only Only run build test"
  96. echo " --backend-only Only run backend tests"
  97. echo " --frontend-only Only run frontend tests"
  98. echo " --integration-only Only run integration tests"
  99. echo " --skip-build Skip build test"
  100. echo " --skip-integration Skip integration tests"
  101. echo " --fresh Force fresh build (no cache)"
  102. echo " -h, --help Show this help"
  103. exit 0
  104. ;;
  105. *)
  106. echo "Unknown option: $1"
  107. exit 1
  108. ;;
  109. esac
  110. done
  111. # Set cache flag based on --fresh option
  112. CACHE_FLAG=""
  113. if [ "$FRESH_BUILD" = true ]; then
  114. CACHE_FLAG="--no-cache"
  115. print_info "Fresh build enabled (--no-cache)"
  116. fi
  117. print_header "BamBuddy Docker Test Suite"
  118. # ============================================
  119. # Pre-build: Build all test images in parallel
  120. # ============================================
  121. print_header "Pre-building Docker Images"
  122. # Determine which images to build
  123. IMAGES_TO_BUILD=""
  124. if [ "$RUN_BACKEND" = true ]; then
  125. IMAGES_TO_BUILD="$IMAGES_TO_BUILD backend-test"
  126. fi
  127. if [ "$RUN_FRONTEND" = true ]; then
  128. IMAGES_TO_BUILD="$IMAGES_TO_BUILD frontend-test"
  129. fi
  130. if [ "$RUN_INTEGRATION" = true ]; then
  131. IMAGES_TO_BUILD="$IMAGES_TO_BUILD integration integration-test-runner"
  132. fi
  133. if [ -n "$IMAGES_TO_BUILD" ]; then
  134. print_info "Building test images in parallel:$IMAGES_TO_BUILD"
  135. if sudo docker compose -f docker-compose.test.yml build --parallel $CACHE_FLAG $IMAGES_TO_BUILD; then
  136. print_success "Test images built successfully"
  137. else
  138. print_failure "Test image build failed"
  139. exit 1
  140. fi
  141. fi
  142. # ============================================
  143. # Test 1: Docker Build (Production Image)
  144. # ============================================
  145. if [ "$RUN_BUILD" = true ]; then
  146. print_header "Test 1: Docker Build (Production)"
  147. print_info "Building production Docker image..."
  148. if sudo docker build -t bambuddy:test . $CACHE_FLAG --progress=plain; then
  149. print_success "Production image builds successfully"
  150. # Verify image has expected labels/structure
  151. print_info "Verifying image structure..."
  152. if sudo docker run --rm bambuddy:test python -c "import backend.app.main; print('Backend imports OK')"; then
  153. print_success "Backend module imports correctly"
  154. else
  155. print_failure "Backend module import failed"
  156. fi
  157. if sudo docker run --rm bambuddy:test test -d /app/static; then
  158. print_success "Static files directory exists"
  159. else
  160. print_failure "Static files directory missing"
  161. fi
  162. else
  163. print_failure "Production image build failed"
  164. fi
  165. fi
  166. # ============================================
  167. # Test 2: Backend Unit Tests
  168. # ============================================
  169. if [ "$RUN_BACKEND" = true ]; then
  170. print_header "Test 2: Backend Unit Tests"
  171. print_info "Running backend tests..."
  172. if sudo docker compose -f docker-compose.test.yml run --rm backend-test; then
  173. print_success "Backend unit tests passed"
  174. else
  175. print_failure "Backend unit tests failed"
  176. fi
  177. fi
  178. # ============================================
  179. # Test 3: Frontend Unit Tests
  180. # ============================================
  181. if [ "$RUN_FRONTEND" = true ]; then
  182. print_header "Test 3: Frontend Unit Tests"
  183. print_info "Running frontend tests..."
  184. if sudo docker compose -f docker-compose.test.yml run --rm frontend-test; then
  185. print_success "Frontend unit tests passed"
  186. else
  187. print_failure "Frontend unit tests failed"
  188. fi
  189. fi
  190. # ============================================
  191. # Test 4: Integration Tests
  192. # ============================================
  193. if [ "$RUN_INTEGRATION" = true ]; then
  194. print_header "Test 4: Integration Tests"
  195. print_info "Starting application container..."
  196. # Start the integration container
  197. sudo docker compose -f docker-compose.test.yml up --remove-orphans -d integration
  198. # Wait for health check
  199. print_info "Waiting for application to be healthy..."
  200. RETRIES=30
  201. while [ $RETRIES -gt 0 ]; do
  202. if sudo docker compose -f docker-compose.test.yml ps integration | grep -q "healthy"; then
  203. break
  204. fi
  205. sleep 2
  206. ((RETRIES--))
  207. done
  208. if [ $RETRIES -eq 0 ]; then
  209. print_failure "Application failed to become healthy"
  210. sudo docker compose -f docker-compose.test.yml logs integration
  211. else
  212. print_success "Application is healthy"
  213. # Run basic health checks
  214. print_info "Running integration tests..."
  215. # Test health endpoint
  216. HEALTH_RESPONSE=$(sudo docker compose -f docker-compose.test.yml exec -T integration curl -s http://localhost:${PORT}/health)
  217. if echo "$HEALTH_RESPONSE" | grep -q "healthy"; then
  218. print_success "Health endpoint responds correctly"
  219. else
  220. print_failure "Health endpoint check failed"
  221. fi
  222. # Test API endpoints
  223. API_RESPONSE=$(sudo docker compose -f docker-compose.test.yml exec -T integration curl -s http://localhost:${PORT}/api/v1/settings)
  224. if echo "$API_RESPONSE" | grep -q "settings"; then
  225. print_success "Settings API endpoint responds"
  226. else
  227. # Settings might return empty, which is OK
  228. print_success "Settings API endpoint accessible"
  229. fi
  230. # Test static files
  231. STATIC_RESPONSE=$(sudo docker compose -f docker-compose.test.yml exec -T integration curl -s -o /dev/null -w "%{http_code}" http://localhost:${PORT}/)
  232. if [ "$STATIC_RESPONSE" = "200" ]; then
  233. print_success "Static files served correctly"
  234. else
  235. print_failure "Static files not served (HTTP $STATIC_RESPONSE)"
  236. fi
  237. # Run pytest integration tests if they exist
  238. if sudo docker compose -f docker-compose.test.yml run --rm integration-test-runner 2>/dev/null; then
  239. print_success "Integration test suite passed"
  240. else
  241. print_info "No Docker-specific integration tests found (this is OK)"
  242. fi
  243. fi
  244. # Cleanup integration containers
  245. sudo docker compose -f docker-compose.test.yml down -v
  246. fi
  247. # ============================================
  248. # Summary
  249. # ============================================
  250. print_header "Test Summary"
  251. echo ""
  252. echo -e "Tests Passed: ${GREEN}${TESTS_PASSED}${NC}"
  253. echo -e "Tests Failed: ${RED}${TESTS_FAILED}${NC}"
  254. if [ $TESTS_FAILED -gt 0 ]; then
  255. echo ""
  256. echo -e "${RED}Failed tests:${NC}"
  257. echo -e "$FAILED_TESTS"
  258. echo ""
  259. exit 1
  260. else
  261. echo ""
  262. echo -e "${GREEN}All tests passed!${NC}"
  263. echo ""
  264. exit 0
  265. fi