Skip to content

Commit f00812b

Browse files
committed
Add full integration test suite for cloud sync operations
1 parent d952d92 commit f00812b

File tree

22 files changed

+1987
-0
lines changed

22 files changed

+1987
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/bin/bash
2+
# Cleanup Docker infrastructure for integration tests
3+
4+
set -euo pipefail
5+
6+
#######################################
7+
# Main cleanup function
8+
#######################################
9+
do_cleanup() {
10+
if [[ -z "${COMPOSE_PROJECT_NAME:-}" ]]; then
11+
log WARN "No compose project name set, skipping Docker cleanup"
12+
return 0
13+
fi
14+
15+
if [[ -z "${TEST_INFRA_DIR:-}" || ! -d "${TEST_INFRA_DIR:-}" ]]; then
16+
log WARN "Infrastructure directory not found, trying cleanup anyway"
17+
fi
18+
19+
log INFO "Stopping Docker containers..."
20+
21+
# Change to infrastructure directory if it exists
22+
if [[ -d "${TEST_INFRA_DIR:-}" ]]; then
23+
cd "$TEST_INFRA_DIR"
24+
fi
25+
26+
# Stop and remove containers, volumes, and networks
27+
if docker compose -p "$COMPOSE_PROJECT_NAME" down -v --remove-orphans 2>/dev/null; then
28+
log OK "Docker containers stopped and removed"
29+
else
30+
log WARN "Failed to stop containers gracefully, forcing removal..."
31+
# Force remove any remaining containers
32+
docker ps -aq --filter "name=${COMPOSE_PROJECT_NAME}" | xargs -r docker rm -f 2>/dev/null || true
33+
# Remove any remaining volumes
34+
docker volume ls -q --filter "name=${COMPOSE_PROJECT_NAME}" | xargs -r docker volume rm -f 2>/dev/null || true
35+
# Remove any remaining networks
36+
docker network ls -q --filter "name=${COMPOSE_PROJECT_NAME}" | xargs -r docker network rm 2>/dev/null || true
37+
fi
38+
39+
# Remove infrastructure directory
40+
if [[ -n "${TEST_INFRA_DIR:-}" && -d "$TEST_INFRA_DIR" ]]; then
41+
rm -rf "$TEST_INFRA_DIR"
42+
log OK "Removed infrastructure directory"
43+
fi
44+
}
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
#!/bin/bash
2+
# Setup isolated Docker infrastructure for integration tests
3+
4+
set -euo pipefail
5+
6+
DEPLOY_DIR="$PROJECT_ROOT/cloud/deploy"
7+
8+
#######################################
9+
# Generate random password
10+
#######################################
11+
gen_password() {
12+
openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c 32
13+
}
14+
15+
#######################################
16+
# Generate random secret (64 chars)
17+
#######################################
18+
gen_secret() {
19+
openssl rand -base64 64 | tr -dc 'a-zA-Z0-9' | head -c 64
20+
}
21+
22+
#######################################
23+
# Wait for API to be ready
24+
#######################################
25+
wait_for_api() {
26+
local max_attempts=60
27+
local attempt=1
28+
29+
log INFO "Waiting for API to be ready..."
30+
31+
while [[ $attempt -le $max_attempts ]]; do
32+
if curl -sf "http://localhost:$NGINX_PORT/health" &>/dev/null; then
33+
log OK "API is ready"
34+
return 0
35+
fi
36+
37+
if [[ $((attempt % 10)) -eq 0 ]]; then
38+
log INFO "Still waiting... (attempt $attempt/$max_attempts)"
39+
fi
40+
41+
sleep 2
42+
((attempt++))
43+
done
44+
45+
log ERROR "API failed to start within timeout"
46+
return 1
47+
}
48+
49+
#######################################
50+
# Login and get API key
51+
#######################################
52+
setup_auth() {
53+
log INFO "Logging in as admin..."
54+
55+
# Login with seeded admin credentials
56+
local login_response
57+
login_response=$(curl -sf -X POST "http://localhost:$NGINX_PORT/api/auth/login" \
58+
-H "Content-Type: application/json" \
59+
-d '{"email":"admin@localhost","password":"Password123!"}' 2>&1) || {
60+
log ERROR "Failed to login: $login_response"
61+
return 1
62+
}
63+
64+
JWT_TOKEN=$(echo "$login_response" | jq -r '.data.token // empty')
65+
if [[ -z "$JWT_TOKEN" ]]; then
66+
log ERROR "Failed to extract JWT token from login response"
67+
echo "Response: $login_response"
68+
return 1
69+
fi
70+
71+
log OK "Logged in successfully"
72+
73+
# Create API key
74+
log INFO "Creating API key..."
75+
76+
local api_key_response
77+
api_key_response=$(curl -sf -X POST "http://localhost:$NGINX_PORT/api/cli-api-keys" \
78+
-H "Authorization: Bearer $JWT_TOKEN" \
79+
-H "Content-Type: application/json" \
80+
-d '{"name":"integration-test"}' 2>&1) || {
81+
log ERROR "Failed to create API key: $api_key_response"
82+
return 1
83+
}
84+
85+
API_KEY=$(echo "$api_key_response" | jq -r '.data.key // empty')
86+
if [[ -z "$API_KEY" ]]; then
87+
log ERROR "Failed to extract API key from response"
88+
echo "Response: $api_key_response"
89+
return 1
90+
fi
91+
92+
log OK "API key created: ${API_KEY:0:20}..."
93+
94+
export JWT_TOKEN
95+
export API_KEY
96+
}
97+
98+
#######################################
99+
# Main setup function
100+
#######################################
101+
do_setup_infrastructure() {
102+
# Generate unique identifiers
103+
COMPOSE_PROJECT_NAME="lrmcloud-test-$$"
104+
NGINX_PORT=$(shuf -i 10000-60000 -n 1)
105+
106+
log INFO "Setting up test infrastructure..."
107+
log INFO "Project name: $COMPOSE_PROJECT_NAME"
108+
log INFO "Port: $NGINX_PORT"
109+
110+
# Create temp directory for infrastructure
111+
TEST_INFRA_DIR=$(mktemp -d)
112+
log INFO "Infrastructure directory: $TEST_INFRA_DIR"
113+
114+
# Generate secrets
115+
local db_password
116+
db_password=$(gen_password)
117+
local redis_password
118+
redis_password=$(gen_password)
119+
local minio_password
120+
minio_password=$(gen_password)
121+
local jwt_secret
122+
jwt_secret=$(gen_secret)
123+
local api_key_secret
124+
api_key_secret=$(gen_secret)
125+
local encryption_key
126+
encryption_key=$(openssl rand -base64 32)
127+
128+
# Copy necessary files
129+
cp "$DEPLOY_DIR/docker-compose.yml" "$TEST_INFRA_DIR/"
130+
cp "$DEPLOY_DIR/Dockerfile.api" "$TEST_INFRA_DIR/"
131+
cp "$DEPLOY_DIR/Dockerfile.web" "$TEST_INFRA_DIR/"
132+
cp "$DEPLOY_DIR/Dockerfile.www" "$TEST_INFRA_DIR/"
133+
cp "$DEPLOY_DIR/init-db.sql" "$TEST_INFRA_DIR/"
134+
cp -r "$DEPLOY_DIR/nginx" "$TEST_INFRA_DIR/"
135+
mkdir -p "$TEST_INFRA_DIR/certs"
136+
mkdir -p "$TEST_INFRA_DIR/data"/{postgres,redis,minio,logs/{api,web,www,nginx}}
137+
138+
# Create .env file
139+
cat > "$TEST_INFRA_DIR/.env" << EOF
140+
ENVIRONMENT=Development
141+
POSTGRES_DB=lrmcloud
142+
POSTGRES_USER=lrm
143+
POSTGRES_PASSWORD=$db_password
144+
REDIS_PASSWORD=$redis_password
145+
MINIO_USER=lrmcloud
146+
MINIO_PASSWORD=$minio_password
147+
EOF
148+
149+
# Create docker-compose.override.yml with ports
150+
cat > "$TEST_INFRA_DIR/docker-compose.override.yml" << EOF
151+
services:
152+
nginx:
153+
ports:
154+
- "$NGINX_PORT:80"
155+
156+
postgres:
157+
ports: []
158+
159+
redis:
160+
ports: []
161+
162+
minio:
163+
ports: []
164+
EOF
165+
166+
# Create minimal config.json for testing
167+
cat > "$TEST_INFRA_DIR/config.json" << EOF
168+
{
169+
"server": {
170+
"urls": "http://0.0.0.0:8080",
171+
"environment": "Development",
172+
"baseUrl": "http://localhost:$NGINX_PORT",
173+
"appPath": "/app"
174+
},
175+
"database": {
176+
"connectionString": "Host=lrmcloud-test-$$-postgres-1;Port=5432;Database=lrmcloud;Username=lrm;Password=$db_password",
177+
"autoMigrate": true
178+
},
179+
"redis": {
180+
"connectionString": "lrmcloud-test-$$-redis-1:6379,password=$redis_password"
181+
},
182+
"storage": {
183+
"endpoint": "lrmcloud-test-$$-minio-1:9000",
184+
"accessKey": "lrmcloud",
185+
"secretKey": "$minio_password",
186+
"bucket": "lrmcloud",
187+
"useSSL": false
188+
},
189+
"encryption": {
190+
"tokenKey": "$encryption_key"
191+
},
192+
"apiKeyMasterSecret": "$api_key_secret",
193+
"auth": {
194+
"jwtSecret": "$jwt_secret",
195+
"jwtExpiryHours": 24,
196+
"githubClientId": "",
197+
"githubClientSecret": ""
198+
},
199+
"mail": {
200+
"backend": "none"
201+
},
202+
"features": {
203+
"registration": true,
204+
"githubSync": false,
205+
"freeTranslations": true,
206+
"teams": true
207+
},
208+
"limits": {
209+
"freeTranslationChars": 50000,
210+
"freeOtherChars": 250000,
211+
"freeMaxProjects": 100,
212+
"freeMaxApiKeys": 10,
213+
"teamTranslationChars": 500000,
214+
"teamOtherChars": 2500000,
215+
"teamMaxMembers": 100,
216+
"teamMaxApiKeys": 100,
217+
"maxKeysPerProject": 100000,
218+
"freeMaxSnapshots": 100,
219+
"teamMaxSnapshots": 100,
220+
"enterpriseMaxSnapshots": 100,
221+
"freeSnapshotRetentionDays": 365,
222+
"teamSnapshotRetentionDays": 365,
223+
"enterpriseSnapshotRetentionDays": 365,
224+
"freeMaxStorageBytes": 262144000,
225+
"teamMaxStorageBytes": 2621440000,
226+
"enterpriseMaxStorageBytes": 5242880000,
227+
"freeMaxFileSizeBytes": 10485760,
228+
"teamMaxFileSizeBytes": 20971520,
229+
"enterpriseMaxFileSizeBytes": 52428800
230+
},
231+
"payment": {
232+
"activeProvider": "none"
233+
},
234+
"lrmProvider": {
235+
"enabled": true,
236+
"enabledBackends": ["mymemory"],
237+
"selectionStrategy": "priority",
238+
"backends": {
239+
"myMemory": {
240+
"rateLimitPerMinute": 20
241+
}
242+
}
243+
},
244+
"superAdmin": {
245+
"emails": ["admin@localhost"]
246+
}
247+
}
248+
EOF
249+
250+
# Update docker-compose.yml to use correct context paths
251+
# The test runs from a temp directory, so we need absolute paths
252+
sed -i "s|context: \.\./\.\.|context: $PROJECT_ROOT|g" "$TEST_INFRA_DIR/docker-compose.yml"
253+
sed -i "s|context: \.\.|context: $PROJECT_ROOT/cloud|g" "$TEST_INFRA_DIR/docker-compose.yml"
254+
sed -i "s|dockerfile: cloud/deploy/|dockerfile: $TEST_INFRA_DIR/|g" "$TEST_INFRA_DIR/docker-compose.yml"
255+
sed -i "s|dockerfile: deploy/|dockerfile: $TEST_INFRA_DIR/|g" "$TEST_INFRA_DIR/docker-compose.yml"
256+
257+
# Update container name references in config.json to match compose project name
258+
# Docker Compose v2 uses project-service-1 naming
259+
sed -i "s/lrmcloud-test-\$\$/${COMPOSE_PROJECT_NAME}/g" "$TEST_INFRA_DIR/config.json"
260+
261+
# Start containers
262+
log INFO "Starting Docker containers..."
263+
264+
cd "$TEST_INFRA_DIR"
265+
266+
if ! docker compose -p "$COMPOSE_PROJECT_NAME" up -d --build 2>&1 | tee -a "${LOG_FILE:-/dev/null}"; then
267+
log ERROR "Failed to start Docker containers"
268+
docker compose -p "$COMPOSE_PROJECT_NAME" logs 2>&1 | tail -50
269+
return 1
270+
fi
271+
272+
# Wait for API
273+
if ! wait_for_api; then
274+
log ERROR "Docker container logs:"
275+
docker compose -p "$COMPOSE_PROJECT_NAME" logs api 2>&1 | tail -100
276+
return 1
277+
fi
278+
279+
# Setup authentication
280+
if ! setup_auth; then
281+
return 1
282+
fi
283+
284+
# Export variables
285+
export NGINX_PORT
286+
export COMPOSE_PROJECT_NAME
287+
export TEST_INFRA_DIR
288+
289+
log OK "Infrastructure ready at http://localhost:$NGINX_PORT"
290+
}

0 commit comments

Comments
 (0)