Skip to content

Commit 5ce015e

Browse files
behinddwallsclaude
andcommitted
refactor(test): migrate test infrastructure to Testcontainers-Go
Replace docker-compose based test setup with Testcontainers-Go for programmatic container lifecycle management in Go tests. - Add testutil helpers: SetupMySQL, StartServer, SetupNetwork - Real-time log streaming via LogConsumer -> t.Log - Readiness via wait.ForLog / MySQL module built-in health - SKIP_CLEANUP + t.Failed() container preservation for debugging - Container naming: sq-test-{context}-{shortid}-{service} - Delete compose.go (316 lines) and 5 docker-compose.yml test files - Fix PR #41 review comments: CI workflow, counter tests, SIGTERM Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 123bacd commit 5ce015e

34 files changed

Lines changed: 786 additions & 1018 deletions

‎.github/workflows/ci.yml‎

Lines changed: 15 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,18 @@ jobs:
2727

2828
- name: Check BUILD files are up to date
2929
run: |
30-
echo "Running Gazelle to check BUILD files..."
30+
echo "Running Gazelle to check BUILD files..." >&2
3131
make gazelle
3232
if ! git diff --quiet; then
33-
echo "❌ BUILD files are out of date!"
34-
echo ""
35-
echo "The following files were modified by Gazelle:"
36-
git diff --name-only
37-
echo ""
38-
echo "Please run 'make gazelle' locally and commit the changes."
33+
echo "BUILD files are out of date!" >&2
34+
echo "" >&2
35+
echo "The following files were modified by Gazelle:" >&2
36+
git diff --name-only >&2
37+
echo "" >&2
38+
echo "Please run 'make gazelle' locally and commit the changes." >&2
3939
exit 1
4040
fi
41-
echo "✅ BUILD files are up to date"
41+
echo "BUILD files are up to date" >&2
4242
4343
- name: Build project
4444
run: make build
@@ -47,10 +47,10 @@ jobs:
4747
run: make test || echo "No unit tests found"
4848

4949
# ---------------------------------------------------------------------------
50-
# INTEGRATION TESTS (e2e, gateway, orchestrator)
50+
# INTEGRATION TESTS
5151
# ---------------------------------------------------------------------------
52-
e2e-integration-test:
53-
name: E2E Integration Test
52+
e2e:
53+
name: E2E Test
5454
runs-on: ubuntu-latest
5555
steps:
5656
- uses: actions/checkout@v4
@@ -86,41 +86,10 @@ jobs:
8686
- uses: ./.github/actions/logs
8787

8888
# ---------------------------------------------------------------------------
89-
# EXTENSION TESTS (conditional on path changes)
89+
# EXTENSION TESTS
9090
# ---------------------------------------------------------------------------
91-
detect-changes:
92-
name: Detect Extension Changes
93-
runs-on: ubuntu-latest
94-
outputs:
95-
counter: ${{ steps.filter.outputs.counter }}
96-
queue: ${{ steps.filter.outputs.queue }}
97-
storage: ${{ steps.filter.outputs.storage }}
98-
steps:
99-
- uses: actions/checkout@v4
100-
- uses: dorny/paths-filter@v3
101-
id: filter
102-
with:
103-
filters: |
104-
counter:
105-
- 'extension/counter/**'
106-
- 'test/integration/extension/counter/**'
107-
- 'entity/**'
108-
- '.github/workflows/ci.yml'
109-
queue:
110-
- 'extension/queue/**'
111-
- 'test/integration/extension/queue/**'
112-
- 'entity/**'
113-
- '.github/workflows/ci.yml'
114-
storage:
115-
- 'extension/storage/**'
116-
- 'test/integration/extension/storage/**'
117-
- 'entity/**'
118-
- '.github/workflows/ci.yml'
119-
12091
counter-integration-test:
12192
name: Counter Extension Test
122-
needs: detect-changes
123-
if: needs.detect-changes.outputs.counter == 'true'
12493
runs-on: ubuntu-latest
12594
steps:
12695
- uses: actions/checkout@v4
@@ -131,8 +100,6 @@ jobs:
131100

132101
queue-integration-test:
133102
name: Queue Extension Test
134-
needs: detect-changes
135-
if: needs.detect-changes.outputs.queue == 'true'
136103
runs-on: ubuntu-latest
137104
steps:
138105
- uses: actions/checkout@v4
@@ -143,8 +110,6 @@ jobs:
143110

144111
storage-integration-test:
145112
name: Storage Extension Test
146-
needs: detect-changes
147-
if: needs.detect-changes.outputs.storage == 'true'
148113
runs-on: ubuntu-latest
149114
steps:
150115
- uses: actions/checkout@v4
@@ -161,31 +126,12 @@ jobs:
161126
runs-on: ubuntu-latest
162127
needs:
163128
- build-and-unit-test
164-
- e2e-integration-test
129+
- counter-integration-test
130+
- e2e
165131
- gateway-integration-test
166132
- orchestrator-integration-test
167-
- counter-integration-test
168133
- queue-integration-test
169134
- storage-integration-test
170135
steps:
171136
- name: All required checks passed
172-
run: |
173-
echo "✅ All required checks passed!"
174-
echo ""
175-
echo "Core checks:"
176-
echo " - build-and-unit-test"
177-
echo " - e2e-integration-test"
178-
echo " - gateway-integration-test"
179-
echo " - orchestrator-integration-test"
180-
echo ""
181-
echo "Extension checks (if paths changed):"
182-
echo " - counter-integration-test"
183-
echo " - queue-integration-test"
184-
echo " - storage-integration-test"
185-
echo ""
186-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
187-
echo "📝 To add a new required check:"
188-
echo " 1. Add the job to this workflow"
189-
echo " 2. Add the job name to the 'needs:' list above"
190-
echo " 3. That's it! No branch protection updates needed."
191-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
137+
run: echo "All required checks passed!" >&2

‎MODULE.bazel‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ use_repo(
3434
"com_github_go_sql_driver_mysql",
3535
"com_github_gogo_protobuf",
3636
"com_github_stretchr_testify",
37+
"com_github_testcontainers_testcontainers_go",
38+
"com_github_testcontainers_testcontainers_go_modules_mysql",
3739
"com_github_uber_go_tally_v4",
3840
"org_golang_google_grpc",
3941
"org_golang_google_protobuf",

‎Makefile‎

Lines changed: 35 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,47 @@
11
# Bazel wrapper
22
BAZEL = ./tool/bazel
33

4-
# Docker Compose wrapper
4+
# Docker Compose wrapper (for local dev only)
55
COMPOSE = docker-compose
66
COMPOSE_FILE = example/server/docker-compose.yml
7-
GATEWAY_COMPOSE_FILE = example/server/gateway/docker-compose.yml
8-
ORCHESTRATOR_COMPOSE_FILE = example/server/orchestrator/docker-compose.yml
97

108
# Fixed project name for local manual testing (tests use unique random names)
119
LOCAL_PROJECT = submitqueue
1210

1311
# Set REPO_ROOT for docker-compose
1412
export REPO_ROOT := $(shell pwd)
1513

16-
.PHONY: build build-all-linux build-gateway-linux build-orchestrator-linux clean clean-proto deps e2e-test gazelle integration-test integration-test-extensions integration-test-gateway integration-test-orchestrator local-clean local-gateway-start local-gateway-stop local-init-schemas local-logs local-orchestrator-start local-orchestrator-stop local-ps local-restart local-start local-stop proto query-deps query-targets run-client-gateway run-client-orchestrator run-client-speculator test test-no-cache help
14+
# Detect host architecture for cross-compiling Linux binaries
15+
ARCH := $(shell uname -m)
16+
ifeq ($(ARCH),arm64)
17+
LINUX_PLATFORM = @rules_go//go/toolchain:linux_arm64
18+
else
19+
LINUX_PLATFORM = @rules_go//go/toolchain:linux_amd64
20+
endif
21+
22+
.PHONY: build build-all-linux build-gateway-linux build-orchestrator-linux clean clean-proto deps e2e-test gazelle integration-test integration-test-extensions integration-test-gateway integration-test-orchestrator local-clean local-init-schemas local-logs local-ps local-restart local-start local-stop proto query-deps query-targets run-client-gateway run-client-orchestrator run-client-speculator test test-no-cache help
1723

1824

1925
build: ## Build all services and examples
2026
@echo "Building all targets with Bazel..."
2127
@$(BAZEL) build //...
2228
@echo "Build complete!"
2329

24-
# Build Linux binaries required for Docker containers
30+
# Build Linux binaries required for Docker containers (local dev)
2531
build-all-linux: build-gateway-linux build-orchestrator-linux ## Build all Linux binaries for Docker
2632
@echo "All Linux binaries ready for Docker"
2733

2834
build-gateway-linux: ## Build Gateway Linux binary for Docker
29-
@echo "Building Gateway Linux binary for Docker..."
30-
@$(BAZEL) build --platforms=@rules_go//go/toolchain:linux_amd64 //example/server/gateway:gateway
35+
@echo "Building Gateway Linux binary for Docker ($(LINUX_PLATFORM))..."
36+
@$(BAZEL) build --platforms=$(LINUX_PLATFORM) //example/server/gateway:gateway
3137
@mkdir -p .docker-bin
3238
@cp -f bazel-bin/example/server/gateway/gateway_/gateway .docker-bin/gateway 2>/dev/null || \
3339
cp -f bazel-bin/example/server/gateway/gateway .docker-bin/gateway
3440
@echo "Gateway Linux binary ready at .docker-bin/gateway"
3541

3642
build-orchestrator-linux: ## Build Orchestrator Linux binary for Docker
37-
@echo "Building Orchestrator Linux binary for Docker..."
38-
@$(BAZEL) build --platforms=@rules_go//go/toolchain:linux_amd64 //example/server/orchestrator:orchestrator
43+
@echo "Building Orchestrator Linux binary for Docker ($(LINUX_PLATFORM))..."
44+
@$(BAZEL) build --platforms=$(LINUX_PLATFORM) //example/server/orchestrator:orchestrator
3945
@mkdir -p .docker-bin
4046
@cp -f bazel-bin/example/server/orchestrator/orchestrator_/orchestrator .docker-bin/orchestrator 2>/dev/null || \
4147
cp -f bazel-bin/example/server/orchestrator/orchestrator .docker-bin/orchestrator
@@ -60,54 +66,41 @@ deps: ## Install Go dependencies
6066
@go mod tidy
6167
@echo "Dependencies installed!"
6268

63-
e2e-test: build-all-linux ## Run end-to-end tests (hermetic, auto-builds binaries)
69+
# Common test flags for integration tests that use Docker containers.
70+
# --test_env passes env vars into the Bazel sandbox:
71+
# REPO_ROOT: locates pre-built Linux binaries in .docker-bin/
72+
# SKIP_CLEANUP: when "true", keeps containers running after tests for debugging
73+
TEST_FLAGS = --test_env=REPO_ROOT --test_env=SKIP_CLEANUP
74+
75+
e2e-test: build-all-linux ## Run end-to-end tests (Testcontainers-based)
6476
@echo "Running end-to-end tests..."
65-
@$(BAZEL) test //test/e2e:e2e_test --test_output=all
77+
@$(BAZEL) test //test/e2e:e2e_test $(TEST_FLAGS) --test_output=all
6678

6779
gazelle: ## Update BUILD.bazel files
6880
@echo "Running Gazelle to update BUILD files..."
6981
@$(BAZEL) run //:gazelle
7082

71-
integration-test: build-all-linux ## Run all integration tests (auto-builds binaries)
83+
integration-test: build-all-linux ## Run all integration tests (Testcontainers-based)
7284
@echo "Running all integration tests..."
73-
@$(BAZEL) test //test/integration/... --test_output=errors
85+
@$(BAZEL) test //test/integration/... $(TEST_FLAGS) --test_output=errors
7486

7587
integration-test-extensions: ## Run extension integration tests
7688
@echo "Running extension integration tests..."
77-
@$(BAZEL) test //test/integration/extension/... --test_output=errors
89+
@$(BAZEL) test //test/integration/extension/... $(TEST_FLAGS) --test_output=errors
7890

79-
integration-test-gateway: build-gateway-linux ## Run Gateway integration tests (auto-builds binary)
91+
integration-test-gateway: build-all-linux ## Run Gateway integration tests
8092
@echo "Running Gateway integration tests..."
81-
@$(BAZEL) test //test/integration/gateway:gateway_test --test_output=errors
93+
@$(BAZEL) test //test/integration/gateway:gateway_test $(TEST_FLAGS) --test_output=errors
8294

83-
integration-test-orchestrator: build-orchestrator-linux ## Run Orchestrator integration tests (auto-builds binary)
95+
integration-test-orchestrator: build-all-linux ## Run Orchestrator integration tests
8496
@echo "Running Orchestrator integration tests..."
85-
@$(BAZEL) test //test/integration/orchestrator:orchestrator_test --test_output=errors
97+
@$(BAZEL) test //test/integration/orchestrator:orchestrator_test $(TEST_FLAGS) --test_output=errors
8698

8799
local-clean: ## Stop and remove all local services, volumes, and images
88100
@echo "Cleaning all services and data..."
89101
@$(COMPOSE) -f $(COMPOSE_FILE) -p $(LOCAL_PROJECT) down -v --rmi local
90102
@echo "All services, volumes, and images removed."
91103

92-
local-gateway-start: build-gateway-linux ## Start Gateway service locally (Gateway + 2 MySQL databases)
93-
@echo "Starting Gateway with docker-compose..."
94-
@$(COMPOSE) -f $(GATEWAY_COMPOSE_FILE) -p $(LOCAL_PROJECT) up -d --build --wait
95-
@echo "Applying database schemas..."
96-
@$(MAKE) -s local-init-schemas
97-
@echo ""
98-
@echo "✅ Gateway is running!"
99-
@echo ""
100-
@$(COMPOSE) -f $(GATEWAY_COMPOSE_FILE) -p $(LOCAL_PROJECT) ps
101-
@echo ""
102-
@echo "Gateway gRPC port: $$(docker port $(LOCAL_PROJECT)-gateway-service-1 8080 2>/dev/null | cut -d: -f2 || echo 'unknown')"
103-
@echo "MySQL App port: $$(docker port $(LOCAL_PROJECT)-mysql-app-1 3306 2>/dev/null | cut -d: -f2 || echo 'unknown')"
104-
@echo "MySQL Queue port: $$(docker port $(LOCAL_PROJECT)-mysql-queue-1 3306 2>/dev/null | cut -d: -f2 || echo 'unknown')"
105-
106-
local-gateway-stop: ## Stop Gateway service
107-
@echo "Stopping Gateway services..."
108-
@$(COMPOSE) -f $(GATEWAY_COMPOSE_FILE) -p $(LOCAL_PROJECT) down
109-
@echo "Gateway services stopped."
110-
111104
local-init-schemas: ## Manually apply all database schemas
112105
@echo "Applying storage schema to mysql-app..."
113106
@for file in extension/storage/mysql/schema/*.sql; do \
@@ -124,44 +117,25 @@ local-init-schemas: ## Manually apply all database schemas
124117
echo " - Applying $$(basename $$file)..."; \
125118
docker exec -i $(LOCAL_PROJECT)-mysql-queue-1 mysql -uroot -proot submitqueue < $$file 2>&1 | grep -v "Using a password" || true; \
126119
done
127-
@echo "✅ All schemas applied successfully"
120+
@echo "All schemas applied successfully"
128121

129122
local-logs: ## View logs from all running services
130123
@$(COMPOSE) -f $(COMPOSE_FILE) -p $(LOCAL_PROJECT) logs -f
131124

132-
local-orchestrator-start: build-orchestrator-linux ## Start Orchestrator service locally (Orchestrator + 2 MySQL databases)
133-
@echo "Starting Orchestrator with docker-compose..."
134-
@$(COMPOSE) -f $(ORCHESTRATOR_COMPOSE_FILE) -p $(LOCAL_PROJECT) up -d --build --wait
135-
@echo "Applying database schemas..."
136-
@$(MAKE) -s local-init-schemas
137-
@echo ""
138-
@echo "✅ Orchestrator is running!"
139-
@echo ""
140-
@$(COMPOSE) -f $(ORCHESTRATOR_COMPOSE_FILE) -p $(LOCAL_PROJECT) ps
141-
@echo ""
142-
@echo "Orchestrator gRPC port: $$(docker port $(LOCAL_PROJECT)-orchestrator-service-1 8080 2>/dev/null | cut -d: -f2 || echo 'unknown')"
143-
@echo "MySQL App port: $$(docker port $(LOCAL_PROJECT)-mysql-app-1 3306 2>/dev/null | cut -d: -f2 || echo 'unknown')"
144-
@echo "MySQL Queue port: $$(docker port $(LOCAL_PROJECT)-mysql-queue-1 3306 2>/dev/null | cut -d: -f2 || echo 'unknown')"
145-
146-
local-orchestrator-stop: ## Stop Orchestrator service
147-
@echo "Stopping Orchestrator services..."
148-
@$(COMPOSE) -f $(ORCHESTRATOR_COMPOSE_FILE) -p $(LOCAL_PROJECT) down
149-
@echo "Orchestrator services stopped."
150-
151125
local-ps: ## Show running containers and their ports
152126
@echo "Running containers and ports:"
153127
@echo ""
154128
@$(COMPOSE) -f $(COMPOSE_FILE) -p $(LOCAL_PROJECT) ps
155129
@echo ""
156-
@echo "📡 Service Endpoints:"
130+
@echo "Service Endpoints:"
157131
@echo " Gateway gRPC: localhost:$$(docker port $(LOCAL_PROJECT)-gateway-service-1 8080 2>/dev/null | cut -d: -f2 || echo 'not running')"
158132
@echo " Orchestrator gRPC: localhost:$$(docker port $(LOCAL_PROJECT)-orchestrator-service-1 8080 2>/dev/null | cut -d: -f2 || echo 'not running')"
159133
@echo ""
160-
@echo "🗄️ Database Endpoints:"
134+
@echo "Database Endpoints:"
161135
@echo " MySQL App: localhost:$$(docker port $(LOCAL_PROJECT)-mysql-app-1 3306 2>/dev/null | cut -d: -f2 || echo 'not running')"
162136
@echo " MySQL Queue: localhost:$$(docker port $(LOCAL_PROJECT)-mysql-queue-1 3306 2>/dev/null | cut -d: -f2 || echo 'not running')"
163137
@echo ""
164-
@echo "💡 Usage:"
138+
@echo "Usage:"
165139
@echo " # Connect to MySQL App DB"
166140
@echo " mysql -h127.0.0.1 -P$$(docker port $(LOCAL_PROJECT)-mysql-app-1 3306 2>/dev/null | cut -d: -f2 || echo 'PORT') -uroot -proot submitqueue"
167141
@echo ""
@@ -183,7 +157,7 @@ local-start: build-all-linux ## Start full stack (Gateway + Orchestrator + MySQL
183157
@echo "Applying database schemas..."
184158
@$(MAKE) -s local-init-schemas
185159
@echo ""
186-
@echo "✅ Full stack is running!"
160+
@echo "Full stack is running!"
187161
@echo ""
188162
@make local-ps
189163

@@ -239,4 +213,3 @@ help: ## Show this help message
239213
@echo "Available targets:"
240214
@echo ""
241215
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-30s\033[0m %s\n", $$1, $$2}'
242-

‎example/server/gateway/BUILD.bazel‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
load("@rules_go//go:def.bzl", "go_binary", "go_library")
22

3-
exports_files(
4-
["docker-compose.yml"],
5-
visibility = ["//visibility:public"],
6-
)
7-
83
go_library(
94
name = "gateway_lib",
105
srcs = ["main.go"],

0 commit comments

Comments
 (0)