Skip to content

Commit a046413

Browse files
Copilottrask
andcommitted
Add comprehensive end-to-end test using docker-compose up --build
Co-authored-by: trask <[email protected]>
1 parent 96e5af9 commit a046413

File tree

4 files changed

+366
-0
lines changed

4 files changed

+366
-0
lines changed

reference-application/E2E-TEST.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# End-to-End Test
2+
3+
This directory contains an end-to-end test (`test-e2e.sh`) that validates the complete OpenTelemetry reference application stack.
4+
5+
## What it tests
6+
7+
The test verifies:
8+
1. **Application functionality**: All endpoints return correct responses
9+
2. **OpenTelemetry integration**: Telemetry data is generated and exported
10+
3. **Collector functionality**: OTLP data is received and processed
11+
4. **Prometheus integration**: Metrics are scraped and available
12+
5. **Docker Compose setup**: All services start and work together
13+
14+
## Running the test
15+
16+
### Prerequisites
17+
18+
- Docker
19+
- Docker Compose (or `docker compose`)
20+
- curl
21+
- jq
22+
23+
### Execution
24+
25+
```bash
26+
# Via Gradle
27+
../gradlew e2eTest
28+
29+
# Directly
30+
./test-e2e.sh
31+
32+
# Dry-run (validation only)
33+
./test-e2e.sh --dry-run
34+
```
35+
36+
## Test flow
37+
38+
1. **Setup**: Cleans any existing containers and builds fresh images
39+
2. **Start services**: Runs `docker-compose up --build -d`
40+
3. **Wait for readiness**: Polls health endpoints until services are ready
41+
4. **Functional tests**: Tests all application endpoints
42+
5. **Telemetry validation**: Verifies OpenTelemetry data collection
43+
6. **Integration tests**: Checks collector and Prometheus functionality
44+
7. **Cleanup**: Stops and removes all containers and volumes
45+
46+
## What's tested
47+
48+
### Application Endpoints
49+
- `GET /rolldice` - Basic dice rolling
50+
- `GET /rolldice?player=testuser` - Parameterized requests
51+
- `GET /rolldice?rolls=3` - Multiple dice rolls
52+
- `GET /fibonacci?n=10` - Computational example
53+
- `GET /health` - Health check
54+
- `GET /actuator/prometheus` - Metrics export
55+
56+
### OpenTelemetry Integration
57+
- Java Agent instrumentation
58+
- Custom span creation
59+
- Metrics generation
60+
- Log correlation
61+
- OTLP export to collector
62+
63+
### Infrastructure
64+
- OpenTelemetry Collector OTLP ingestion
65+
- Prometheus metrics scraping
66+
- Service networking and dependencies
67+
68+
## Using in CI/CD
69+
70+
This test can be integrated into CI/CD pipelines to ensure the reference application works correctly in a production-like environment.
71+
72+
Example GitHub Actions usage:
73+
```yaml
74+
- name: Run end-to-end test
75+
run: |
76+
cd reference-application
77+
./test-e2e.sh
78+
```
79+
80+
The test automatically handles cleanup and provides clear success/failure indicators.

reference-application/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,28 @@ All logs include:
142142
../gradlew test
143143
```
144144

145+
### End-to-End Testing
146+
147+
Run the comprehensive end-to-end test that verifies the complete OpenTelemetry stack:
148+
149+
```shell
150+
# Run via Gradle
151+
../gradlew e2eTest
152+
153+
# Or run directly
154+
./test-e2e.sh
155+
```
156+
157+
This test:
158+
- Builds and starts all services using `docker-compose up --build`
159+
- Waits for services to be ready (application, collector, Prometheus)
160+
- Tests all application endpoints
161+
- Verifies OpenTelemetry data collection and export
162+
- Validates Prometheus metric scraping
163+
- Cleans up resources automatically
164+
165+
For detailed information about the end-to-end test, see [E2E-TEST.md](E2E-TEST.md).
166+
145167
### Running locally
146168

147169
```shell

reference-application/build.gradle.kts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ tasks.withType<Test> {
4848
useJUnitPlatform()
4949
}
5050

51+
task("e2eTest", Exec::class) {
52+
group = "verification"
53+
description = "Run end-to-end test using docker-compose"
54+
commandLine("./test-e2e.sh")
55+
dependsOn("bootJar")
56+
}
57+
5158
java {
5259
toolchain {
5360
languageVersion.set(JavaLanguageVersion.of(17))

reference-application/test-e2e.sh

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
#!/bin/bash
2+
3+
# End-to-end test for the reference application using docker-compose
4+
# This test verifies that the full stack works correctly with OpenTelemetry
5+
6+
set -euo pipefail
7+
8+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9+
cd "$SCRIPT_DIR"
10+
11+
# Colors for output
12+
RED='\033[0;31m'
13+
GREEN='\033[0;32m'
14+
YELLOW='\033[1;33m'
15+
NC='\033[0m' # No Color
16+
17+
# Function to print colored output
18+
print_status() {
19+
echo -e "${GREEN}[INFO]${NC} $1"
20+
}
21+
22+
print_warning() {
23+
echo -e "${YELLOW}[WARN]${NC} $1"
24+
}
25+
26+
print_error() {
27+
echo -e "${RED}[ERROR]${NC} $1"
28+
}
29+
30+
# Function to wait for a service to be ready
31+
wait_for_service() {
32+
local url=$1
33+
local service_name=$2
34+
local max_attempts=30
35+
local attempt=1
36+
37+
print_status "Waiting for $service_name to be ready at $url..."
38+
39+
while [ $attempt -le $max_attempts ]; do
40+
if curl -sf "$url" > /dev/null 2>&1; then
41+
print_status "$service_name is ready!"
42+
return 0
43+
fi
44+
45+
if [ $attempt -eq $max_attempts ]; then
46+
print_error "$service_name failed to start within $max_attempts attempts"
47+
return 1
48+
fi
49+
50+
print_status "Attempt $attempt/$max_attempts: $service_name not ready yet, waiting..."
51+
sleep 2
52+
((attempt++))
53+
done
54+
}
55+
56+
# Function to test application endpoints
57+
test_endpoints() {
58+
print_status "Testing application endpoints..."
59+
60+
# Test basic dice roll
61+
print_status "Testing /rolldice endpoint..."
62+
response=$(curl -sf http://localhost:8080/rolldice)
63+
if echo "$response" | jq -e '.result' > /dev/null && echo "$response" | jq -e '.player' > /dev/null; then
64+
print_status "✓ /rolldice endpoint working"
65+
else
66+
print_error "✗ /rolldice endpoint failed"
67+
return 1
68+
fi
69+
70+
# Test dice roll with player
71+
print_status "Testing /rolldice?player=testuser endpoint..."
72+
response=$(curl -sf "http://localhost:8080/rolldice?player=testuser")
73+
if echo "$response" | jq -r '.player' | grep -q "testuser"; then
74+
print_status "✓ /rolldice with player working"
75+
else
76+
print_error "✗ /rolldice with player failed"
77+
return 1
78+
fi
79+
80+
# Test fibonacci endpoint
81+
print_status "Testing /fibonacci?n=10 endpoint..."
82+
response=$(curl -sf "http://localhost:8080/fibonacci?n=10")
83+
if echo "$response" | jq -r '.result' | grep -q "55"; then
84+
print_status "✓ /fibonacci endpoint working"
85+
else
86+
print_error "✗ /fibonacci endpoint failed"
87+
return 1
88+
fi
89+
90+
# Test health endpoint
91+
print_status "Testing /health endpoint..."
92+
response=$(curl -sf http://localhost:8080/health)
93+
if echo "$response" | jq -r '.status' | grep -q "UP"; then
94+
print_status "✓ /health endpoint working"
95+
else
96+
print_error "✗ /health endpoint failed"
97+
return 1
98+
fi
99+
100+
# Test metrics endpoint
101+
print_status "Testing /actuator/prometheus endpoint..."
102+
if curl -sf http://localhost:8080/actuator/prometheus | grep -q "dice_rolls_total"; then
103+
print_status "✓ /actuator/prometheus endpoint working with custom metrics"
104+
else
105+
print_error "✗ /actuator/prometheus endpoint failed or missing custom metrics"
106+
return 1
107+
fi
108+
109+
print_status "All endpoint tests passed!"
110+
}
111+
112+
# Function to test OpenTelemetry collector
113+
test_collector() {
114+
print_status "Testing OpenTelemetry collector..."
115+
116+
# Check collector health endpoint
117+
if curl -sf http://localhost:13133 > /dev/null; then
118+
print_status "✓ OpenTelemetry collector health endpoint is accessible"
119+
else
120+
print_warning "! OpenTelemetry collector health endpoint not accessible (this might be expected)"
121+
fi
122+
123+
# Check if collector is receiving and processing data by examining logs
124+
print_status "Checking collector logs for telemetry data processing..."
125+
126+
# Generate some telemetry data
127+
curl -sf http://localhost:8080/rolldice > /dev/null
128+
curl -sf http://localhost:8080/fibonacci?n=5 > /dev/null
129+
130+
# Wait a bit for data to be processed
131+
sleep 5
132+
133+
# Check collector logs for evidence of data processing
134+
if $compose_cmd logs otel-collector 2>/dev/null | grep -q -E "(spans|metrics|logs).*processed"; then
135+
print_status "✓ OpenTelemetry collector is processing telemetry data"
136+
else
137+
print_warning "! Could not verify telemetry data processing in collector logs"
138+
fi
139+
}
140+
141+
# Function to test Prometheus integration
142+
test_prometheus() {
143+
print_status "Testing Prometheus integration..."
144+
145+
# Wait for Prometheus to be ready
146+
if wait_for_service "http://localhost:9090/-/ready" "Prometheus"; then
147+
print_status "✓ Prometheus is running"
148+
149+
# Check if Prometheus can scrape metrics from the collector
150+
if curl -sf "http://localhost:9090/api/v1/targets" | jq -r '.data.activeTargets[].health' | grep -q "up"; then
151+
print_status "✓ Prometheus has healthy targets"
152+
else
153+
print_warning "! Prometheus targets may not be healthy"
154+
fi
155+
else
156+
print_warning "! Prometheus failed to start"
157+
fi
158+
}
159+
160+
# Function to get the docker compose command
161+
get_docker_compose_cmd() {
162+
if command -v "docker-compose" &> /dev/null; then
163+
echo "docker-compose"
164+
elif docker compose version &> /dev/null; then
165+
echo "docker compose"
166+
else
167+
return 1
168+
fi
169+
}
170+
171+
# Function to cleanup resources
172+
cleanup() {
173+
print_status "Cleaning up resources..."
174+
local compose_cmd
175+
if compose_cmd=$(get_docker_compose_cmd); then
176+
$compose_cmd down --volumes --remove-orphans || true
177+
fi
178+
179+
# Clean up any dangling resources
180+
docker system prune -f || true
181+
}
182+
183+
# Main execution
184+
main() {
185+
print_status "Starting end-to-end test for OpenTelemetry Reference Application"
186+
187+
# Handle dry-run mode for testing
188+
if [[ "${1:-}" == "--dry-run" ]]; then
189+
print_status "Running in dry-run mode - skipping actual Docker operations"
190+
print_status "✅ Script validation passed"
191+
return 0
192+
fi
193+
194+
# Ensure we're in the right directory
195+
if [[ ! -f "docker-compose.yml" ]]; then
196+
print_error "docker-compose.yml not found. Please run this script from the reference-application directory."
197+
exit 1
198+
fi
199+
200+
# Ensure required tools are available
201+
for tool in docker curl jq; do
202+
if ! command -v "$tool" &> /dev/null; then
203+
print_error "$tool is required but not installed."
204+
exit 1
205+
fi
206+
done
207+
208+
# Check for docker compose command
209+
if ! compose_cmd=$(get_docker_compose_cmd); then
210+
print_error "docker-compose or 'docker compose' is required but not available."
211+
exit 1
212+
fi
213+
214+
print_status "Using Docker Compose command: $compose_cmd"
215+
216+
# Build and start services
217+
print_status "Building and starting services with docker-compose..."
218+
$compose_cmd down --volumes --remove-orphans || true
219+
$compose_cmd up --build -d
220+
221+
# Wait for services to be ready
222+
if ! wait_for_service "http://localhost:8080/health" "Reference Application"; then
223+
print_error "Reference application failed to start"
224+
cleanup
225+
exit 1
226+
fi
227+
228+
if ! wait_for_service "http://localhost:4318/v1/traces" "OpenTelemetry Collector OTLP HTTP"; then
229+
print_warning "OpenTelemetry Collector OTLP HTTP endpoint not accessible"
230+
fi
231+
232+
# Run tests
233+
if test_endpoints; then
234+
print_status "✅ Application endpoint tests passed"
235+
else
236+
print_error "❌ Application endpoint tests failed"
237+
cleanup
238+
exit 1
239+
fi
240+
241+
test_collector
242+
test_prometheus
243+
244+
print_status "🎉 End-to-end test completed successfully!"
245+
print_status "The reference application is working correctly with OpenTelemetry stack"
246+
247+
# Cleanup
248+
cleanup
249+
250+
print_status "✅ All tests passed and cleanup completed"
251+
}
252+
253+
# Trap to ensure cleanup on script exit
254+
trap cleanup EXIT
255+
256+
# Run main function
257+
main "$@"

0 commit comments

Comments
 (0)