-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Expand file tree
/
Copy pathrun-integration-tests.sh
More file actions
executable file
·347 lines (302 loc) · 11.4 KB
/
run-integration-tests.sh
File metadata and controls
executable file
·347 lines (302 loc) · 11.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#!/bin/bash
# Federation Integration Test Runner
# This script builds Rocket.Chat locally and starts the federation services,
# then waits for Rocket.Chat to be ready before running the end-to-end tests.
set -e # Exit on any error
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Script moved under tests/scripts; package root is two levels up from script dir
PACKAGE_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
DOCKER_COMPOSE_FILE="$PACKAGE_ROOT/docker-compose.test.yml"
MAX_WAIT_TIME=240 # 4 minutes
CHECK_INTERVAL=5 # Check every 5 seconds
RC1_CONTAINER="rc1"
# Build configuration
# Use a temporary directory outside the repo to avoid symlink traversal issues during Meteor build
BUILD_DIR="$(mktemp -d "${FEDERATION_TEST_TMPDIR:-/tmp}/rc-federation-build-XXXXXX")"
ROCKETCHAT_ROOT="$(cd "$PACKAGE_ROOT/../../.." && pwd)" # Go up to project root
# Parse command line arguments
KEEP_RUNNING=false
INCLUDE_ELEMENT=false
USE_PREBUILT_IMAGE=false
PREBUILT_IMAGE=""
INTERRUPTED=false
PROFILE_PREFIX="local" # Default to local build
NO_TEST=false
while [[ $# -gt 0 ]]; do
case $1 in
--keep-running)
KEEP_RUNNING=true
shift
;;
--element)
INCLUDE_ELEMENT=true
shift
;;
--no-test)
NO_TEST=true
shift
;;
--image)
USE_PREBUILT_IMAGE=true
# If no IMAGE value is provided (or next token is another flag), default to latest
if [[ -z "${2:-}" || "$2" == -* ]]; then
PREBUILT_IMAGE="rocketchat/rocket.chat:latest"
shift 1
else
PREBUILT_IMAGE="$2"
shift 2
fi
;;
--help|-h)
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " --keep-running Keep Docker containers running after tests complete"
echo " --element Include Element web client in the test environment"
echo " --no-test Start containers and skip running tests"
echo " --image [IMAGE] Use a pre-built Docker image instead of building locally"
echo " --help, -h Show this help message"
echo ""
echo "By default, builds Rocket.Chat locally and runs the 'test' profile"
echo "Use --image to test against a pre-built image (e.g., --image rocketchat/rocket.chat:latest)"
echo "If --image is provided without a value, defaults to rocketchat/rocket.chat:latest"
echo "Use --element to run all services including Element web client"
echo "Use --no-test to start containers and skip running tests"
exit 0
;;
*)
echo "Unknown option: $1"
echo "Use --help for usage information"
exit 1
;;
esac
done
# Logging functions
log_info() {
echo -e "${BLUE}ℹ️ [$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}"
}
log_success() {
echo -e "${GREEN}✅ [$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}"
}
log_warning() {
echo -e "${YELLOW}⚠️ [$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}"
}
log_error() {
echo -e "${RED}❌ [$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}"
}
# Cleanup function
cleanup() {
# Show container logs if tests failed
if [ -n "${TEST_EXIT_CODE:-}" ] && [ "$TEST_EXIT_CODE" -ne 0 ]; then
echo ""
echo "=========================================="
echo "CONTAINER LOGS (Test Failed)"
echo "=========================================="
echo ""
echo "ROCKET.CHAT (rc1) LOGS:"
echo "----------------------------------------"
if docker ps -q -f name=rc1 | grep -q .; then
docker logs rc1 2>&1 | sed 's/^/ /'
else
echo " Rocket.Chat container not found or no logs"
fi
echo ""
echo "SYNAPSE (hs1) LOGS:"
echo "----------------------------------------"
if docker ps -q -f name=hs1 | grep -q .; then
docker logs hs1 2>&1 | sed 's/^/ /'
else
echo " Synapse container not found or no logs"
fi
echo ""
echo "=========================================="
fi
if [ "$KEEP_RUNNING" = true ]; then
log_info "Keeping Docker containers running (--keep-running flag set)"
log_info "Services are available at:"
log_info " - Rocket.Chat: https://rc1"
log_info " - Synapse: https://hs1"
log_info " - MongoDB: localhost:27017"
if [ "$INCLUDE_ELEMENT" = true ]; then
log_info " - Element: https://element"
fi
if [ "$INCLUDE_ELEMENT" = true ]; then
log_info "To stop containers manually, run: docker compose -f $DOCKER_COMPOSE_FILE --profile element-$PROFILE_PREFIX down -v"
else
log_info "To stop containers manually, run: docker compose -f $DOCKER_COMPOSE_FILE --profile test-$PROFILE_PREFIX down -v"
fi
else
log_info "Cleaning up services..."
if [ -f "$DOCKER_COMPOSE_FILE" ]; then
if [ "$INCLUDE_ELEMENT" = true ]; then
docker compose -f "$DOCKER_COMPOSE_FILE" --profile "element-$PROFILE_PREFIX" down -v 2>/dev/null || true
else
docker compose -f "$DOCKER_COMPOSE_FILE" --profile "test-$PROFILE_PREFIX" down -v 2>/dev/null || true
fi
fi
log_success "Cleanup completed"
fi
# Remove temporary build directory if it exists
if [ -n "${BUILD_DIR:-}" ] && [ -d "$BUILD_DIR" ]; then
rm -rf "$BUILD_DIR" || true
fi
# Exit with the test result code
if [ -n "${TEST_EXIT_CODE:-}" ]; then
exit $TEST_EXIT_CODE
fi
}
# Setup signal handlers for cleanup
trap cleanup EXIT TERM
# Handle interrupt signal (Ctrl+C) immediately
trap 'INTERRUPTED=true; log_info "Received interrupt signal (Ctrl+C), stopping..."; cleanup; exit 130' INT
# Check if docker-compose.test.yml exists
if [ ! -f "$DOCKER_COMPOSE_FILE" ]; then
log_error "docker-compose.test.yml not found at $DOCKER_COMPOSE_FILE"
exit 1
fi
# Build Rocket.Chat locally if not using pre-built image
if [ "$USE_PREBUILT_IMAGE" = false ]; then
log_info "🚀 Building Rocket.Chat locally..."
log_info "====================================="
# Clean up any existing build
log_info "Cleaning up previous build..."
rm -rf "$BUILD_DIR"
# Build the project
log_info "Building packages from project root..."
cd "$ROCKETCHAT_ROOT"
yarn build
# Build the Meteor bundle (must be run from the meteor directory)
log_info "Building Meteor bundle..."
cd "$ROCKETCHAT_ROOT/apps/meteor"
METEOR_DISABLE_OPTIMISTIC_CACHING=1 meteor build --server-only --directory "$BUILD_DIR"
log_success "Build completed!"
else
log_info "🚀 Using pre-built image: $PREBUILT_IMAGE"
log_info "====================================="
fi
log_info "🚀 Starting Federation Integration Tests"
log_info "====================================="
# Set environment variables for Docker Compose
if [ "$USE_PREBUILT_IMAGE" = true ]; then
export ROCKETCHAT_IMAGE="$PREBUILT_IMAGE"
PROFILE_PREFIX="prebuilt"
log_info "Using pre-built image: $PREBUILT_IMAGE"
else
export ROCKETCHAT_BUILD_CONTEXT="$BUILD_DIR"
export ROCKETCHAT_DOCKERFILE="$ROCKETCHAT_ROOT/apps/meteor/.docker/Dockerfile.alpine"
PROFILE_PREFIX="local"
log_info "Building from local context: $BUILD_DIR"
fi
# Start services
if [ "$INCLUDE_ELEMENT" = true ]; then
PROFILE="element-$PROFILE_PREFIX"
log_info "Starting all federation services including Element web client..."
docker compose -f "$DOCKER_COMPOSE_FILE" --profile "$PROFILE" up -d --build
else
PROFILE="test-$PROFILE_PREFIX"
log_info "Starting federation services (test profile only)..."
docker compose -f "$DOCKER_COMPOSE_FILE" --profile "$PROFILE" up -d --build
fi
# Wait for rc1 container to be running
log_info "Waiting for rc1 container to start..."
timeout=60
while [ $timeout -gt 0 ] && [ "$INTERRUPTED" = false ]; do
if docker ps --filter "name=$RC1_CONTAINER" --filter "status=running" | grep -q "$RC1_CONTAINER"; then
log_success "rc1 container is running"
break
fi
sleep 2
timeout=$((timeout - 2))
done
if [ "$INTERRUPTED" = true ]; then
log_info "Container startup interrupted by user"
exit 130
fi
if [ $timeout -le 0 ]; then
log_error "rc1 container failed to start within 60 seconds"
exit 1
fi
# Wait for both Rocket.Chat and Synapse to be ready
log_info "Waiting for Rocket.Chat and Synapse servers to be ready..."
# Function to wait for a service to be ready
wait_for_service() {
local url=$1
local name=$2
local host=$3
local elapsed=0
local ca_cert="${CA_CERT:-$PACKAGE_ROOT/docker-compose/traefik/certs/ca/rootCA.crt}"
# Derive host/port from URL when not explicitly provided
local host_with_port="${url#*://}"
host_with_port="${host_with_port%%/*}"
if [ -z "$host" ]; then
host="${host_with_port%%:*}"
fi
local port
if [[ "$host_with_port" == *:* ]]; then
port="${host_with_port##*:}"
else
if [[ "$url" == https://* ]]; then
port=443
else
port=80
fi
fi
log_info "Checking $name at $url (host $host -> 127.0.0.1:$port)..."
while [ $elapsed -lt $MAX_WAIT_TIME ] && [ "$INTERRUPTED" = false ]; do
# Capture curl output and error for debugging
curl_output=$(curl -fsS --cacert "$ca_cert" --resolve "${host}:${port}:127.0.0.1" "$url" 2>&1)
curl_exit_code=$?
if [ $curl_exit_code -eq 0 ]; then
log_success "$name is ready!"
return 0
fi
log_info "$name not ready yet, waiting... (${elapsed}s/${MAX_WAIT_TIME}s)"
log_info "Curl error: $curl_output"
sleep $CHECK_INTERVAL
elapsed=$((elapsed + CHECK_INTERVAL))
done
if [ "$INTERRUPTED" = true ]; then
log_info "Service check interrupted by user"
return 1
fi
log_error "$name failed to become ready within ${MAX_WAIT_TIME} seconds"
return 1
}
# Wait for Rocket.Chat
if ! wait_for_service "https://rc1/api/info" "Rocket.Chat" "rc1"; then
log_error "Last 50 lines of rc1 logs:"
docker logs --tail 50 "$RC1_CONTAINER" 2>&1 | sed 's/^/ /'
exit 1
fi
# Wait for Synapse
if ! wait_for_service "https://hs1/_matrix/client/versions" "Synapse" "hs1"; then
log_error "Last 50 lines of hs1 logs:"
docker logs --tail 50 "hs1" 2>&1 | sed 's/^/ /'
exit 1
fi
# Run the end-to-end tests
if [ "$NO_TEST" = false ]; then
log_info "Running end-to-end tests..."
cd "$PACKAGE_ROOT"
IS_EE=true NODE_EXTRA_CA_CERTS=$(pwd)/docker-compose/traefik/certs/ca/rootCA.crt yarn test:federation
TEST_EXIT_CODE=$?
else
log_info "No-test mode: skipping test execution"
log_info "Services are ready and running. You can now:"
log_info " - Access Rocket.Chat at: https://rc1"
log_info " - Access Synapse at: https://hs1"
log_info " - Access MongoDB at: localhost:27017"
if [ "$INCLUDE_ELEMENT" = true ]; then
log_info " - Access Element at: https://element"
fi
log_info ""
log_info "To run tests manually, execute: yarn testend-to-end"
log_info "To stop containers, use: docker compose -f $DOCKER_COMPOSE_FILE down"
TEST_EXIT_CODE=0
fi