Files
bifrost/.github/workflows/scripts/test-docker-image.sh
Beyhan Oğur 880f412e2c first commit
2026-04-26 21:52:23 +03:00

302 lines
10 KiB
Bash
Executable File

#!/bin/bash
set -e
# Test Docker image by building, starting with docker-compose, and running E2E API tests
# Usage: ./test-docker-image.sh <platform>
# Example: ./test-docker-image.sh linux/amd64
# Get the absolute path of the script directory
if command -v readlink >/dev/null 2>&1 && readlink -f "$0" >/dev/null 2>&1; then
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
else
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
fi
# Repository root (3 levels up from .github/workflows/scripts)
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd -P)"
# Setup Go workspace for CI (go.work is gitignored, must be regenerated)
source "$SCRIPT_DIR/setup-go-workspace.sh"
PLATFORM=${1:-linux/amd64}
ARCH=$(echo "$PLATFORM" | cut -d'/' -f2)
IMAGE_TAG="bifrost-test:ci-${GITHUB_SHA:-local}-${ARCH}"
CONTAINER_NAME="bifrost-test-${ARCH}"
TEST_PORT=8080
DOCKER_COMPOSE_FILE="$REPO_ROOT/tests/docker-compose.yml"
TEMP_DIR=$(mktemp -d)
CONFIG_FILE="$TEMP_DIR/config.json"
echo "=== Testing Docker image for ${PLATFORM} ==="
# Cleanup function
cleanup() {
local exit_code=$?
echo ""
echo "=== Cleaning up ==="
# Stop and remove Bifrost container
echo "Stopping Bifrost container..."
docker stop "${CONTAINER_NAME}" > /dev/null 2>&1 || true
docker rm "${CONTAINER_NAME}" > /dev/null 2>&1 || true
# Stop docker-compose services
echo "Stopping docker-compose services..."
docker compose -f "$DOCKER_COMPOSE_FILE" down -v > /dev/null 2>&1 || true
# Remove test image
echo "Removing test image..."
docker rmi "${IMAGE_TAG}" > /dev/null 2>&1 || true
# Remove temp directory
rm -rf "$TEMP_DIR"
exit $exit_code
}
trap cleanup EXIT
# Build the image using local module sources (pre-release CI builds)
echo "Building Docker image (local modules)..."
docker build \
--platform "${PLATFORM}" \
-f transports/Dockerfile.local \
-t "${IMAGE_TAG}" \
.
echo "Build complete: ${IMAGE_TAG}"
# Start docker-compose services (Postgres, Weaviate, Redis, Qdrant)
echo ""
echo "=== Starting docker-compose services ==="
docker compose -f "$DOCKER_COMPOSE_FILE" up -d
# Wait for Postgres to be ready
echo "Waiting for Postgres to be ready..."
MAX_WAIT=60
ELAPSED=0
while [ $ELAPSED -lt $MAX_WAIT ]; do
if docker compose -f "$DOCKER_COMPOSE_FILE" exec -T postgres pg_isready -U bifrost -d bifrost > /dev/null 2>&1; then
echo "Postgres is ready"
break
fi
sleep 2
ELAPSED=$((ELAPSED + 2))
done
if [ $ELAPSED -ge $MAX_WAIT ]; then
echo "ERROR: Postgres did not become ready within ${MAX_WAIT}s"
docker compose -f "$DOCKER_COMPOSE_FILE" logs postgres
exit 1
fi
# Get the docker network name
NETWORK_NAME=$(docker compose -f "$DOCKER_COMPOSE_FILE" ps --format json | head -1 | jq -r '.Networks' 2>/dev/null || echo "tests_bifrost_network")
if [ -z "$NETWORK_NAME" ] || [ "$NETWORK_NAME" = "null" ]; then
NETWORK_NAME="tests_bifrost_network"
fi
# Generate config.json with all providers and Postgres stores
echo ""
echo "=== Generating config.json ==="
cat > "$CONFIG_FILE" << 'CONFIGEOF'
{
"$schema": "https://www.getbifrost.ai/schema",
"providers": {
"openai": {
"keys": [{ "name": "OpenAI API Key", "value": "env.OPENAI_API_KEY", "weight": 1, "use_for_batch_api": true }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"elevenlabs": {
"keys": [{ "name": "ElevenLabs API Key", "value": "env.ELEVENLABS_API_KEY", "weight": 1, "use_for_batch_api": true }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"xai": {
"keys": [{ "name": "Xai API Key", "value": "env.XAI_API_KEY", "weight": 1, "use_for_batch_api": true }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"huggingface": {
"keys": [{ "name": "Hugging Face API Key", "value": "env.HUGGING_FACE_API_KEY", "weight": 1, "use_for_batch_api": true }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"anthropic": {
"keys": [{ "name": "Anthropic API Key", "value": "env.ANTHROPIC_API_KEY", "weight": 1, "use_for_batch_api": true }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"gemini": {
"keys": [{ "value": "env.GEMINI_API_KEY", "weight": 1, "use_for_batch_api": true, "name": "Gemini API Key" }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"vertex": {
"keys": [{ "name": "Vertex API Key", "vertex_key_config": { "project_id": "env.VERTEX_PROJECT_ID", "region": "env.GOOGLE_LOCATION", "auth_credentials": "env.VERTEX_CREDENTIALS" }, "weight": 1 }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"mistral": {
"keys": [{ "name": "Mistral API Key", "value": "env.MISTRAL_API_KEY", "weight": 1 }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"cohere": {
"keys": [{ "name": "Cohere API Key", "value": "env.COHERE_API_KEY", "weight": 1 }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"groq": {
"keys": [{ "name": "Groq API Key", "value": "env.GROQ_API_KEY", "weight": 1 }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"perplexity": {
"keys": [{ "name": "Perplexity API Key", "value": "env.PERPLEXITY_API_KEY", "weight": 1 }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"cerebras": {
"keys": [{ "name": "Cerebras API Key", "value": "env.CEREBRAS_API_KEY", "weight": 1 }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"openrouter": {
"keys": [{ "name": "OpenRouter API Key", "value": "env.OPENROUTER_API_KEY", "weight": 1 }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"parasail": {
"keys": [{ "name": "Parasail API Key", "value": "env.PARASAIL_API_KEY", "weight": 1 }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"azure": {
"keys": [{ "name": "Azure API Key", "value": "env.AZURE_API_KEY", "azure_key_config": { "endpoint": "env.AZURE_ENDPOINT", "api_version": "env.AZURE_API_VERSION" }, "weight": 1 }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"bedrock": {
"keys": [{ "name": "Bedrock API Key", "bedrock_key_config": { "access_key": "env.AWS_ACCESS_KEY_ID", "secret_key": "env.AWS_SECRET_ACCESS_KEY", "region": "env.AWS_REGION", "arn": "env.AWS_ARN" }, "weight": 1, "use_for_batch_api": true }],
"network_config": { "default_request_timeout_in_seconds": 300 }
},
"replicate": {
"keys": [{ "name": "Replicate API KEY", "value": "env.REPLICATE_API_KEY", "weight": 1.0, "use_for_batch_api": true }]
}
},
"config_store": {
"enabled": true,
"type": "postgres",
"config": {
"host": "postgres",
"port": "5432",
"user": "bifrost",
"password": "bifrost_password",
"db_name": "bifrost",
"ssl_mode": "disable"
}
},
"logs_store": {
"enabled": true,
"type": "postgres",
"config": {
"host": "postgres",
"port": "5432",
"user": "bifrost",
"password": "bifrost_password",
"db_name": "bifrost",
"ssl_mode": "disable"
}
},
"governance": {
"virtual_keys": [
{
"id": "vk-test",
"value": "sk-bf-test-key",
"is_active": true,
"name": "vk-test"
}
]
},
"client": {
"drop_excess_requests": false,
"initial_pool_size": 300,
"allowed_origins": ["http://localhost:3000", "https://localhost:3000"],
"enable_logging": true,
"enforce_governance_header": false,
"allow_direct_keys": false,
"max_request_body_size_mb": 100
},
"encryption_key": ""
}
CONFIGEOF
echo "Config file created at: $CONFIG_FILE"
# Run the Bifrost container connected to the docker-compose network
echo ""
echo "=== Starting Bifrost container ==="
docker run -d \
--name "${CONTAINER_NAME}" \
--platform "${PLATFORM}" \
--network "${NETWORK_NAME}" \
-p ${TEST_PORT}:8080 \
-e APP_PORT=8080 \
-e APP_HOST=0.0.0.0 \
-e OPENAI_API_KEY="${OPENAI_API_KEY:-}" \
-e ELEVENLABS_API_KEY="${ELEVENLABS_API_KEY:-}" \
-e XAI_API_KEY="${XAI_API_KEY:-}" \
-e HUGGING_FACE_API_KEY="${HUGGING_FACE_API_KEY:-}" \
-e ANTHROPIC_API_KEY="${ANTHROPIC_API_KEY:-}" \
-e GEMINI_API_KEY="${GEMINI_API_KEY:-}" \
-e VERTEX_PROJECT_ID="${VERTEX_PROJECT_ID:-}" \
-e VERTEX_CREDENTIALS="${VERTEX_CREDENTIALS:-}" \
-e GOOGLE_LOCATION="${GOOGLE_LOCATION:-us-central1}" \
-e MISTRAL_API_KEY="${MISTRAL_API_KEY:-}" \
-e COHERE_API_KEY="${COHERE_API_KEY:-}" \
-e GROQ_API_KEY="${GROQ_API_KEY:-}" \
-e PERPLEXITY_API_KEY="${PERPLEXITY_API_KEY:-}" \
-e CEREBRAS_API_KEY="${CEREBRAS_API_KEY:-}" \
-e OPENROUTER_API_KEY="${OPENROUTER_API_KEY:-}" \
-e PARASAIL_API_KEY="${PARASAIL_API_KEY:-}" \
-e AZURE_API_KEY="${AZURE_API_KEY:-}" \
-e AZURE_ENDPOINT="${AZURE_ENDPOINT:-}" \
-e AZURE_API_VERSION="${AZURE_API_VERSION:-}" \
-e AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-}" \
-e AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-}" \
-e AWS_REGION="${AWS_REGION:-us-east-1}" \
-e AWS_ARN="${AWS_ARN:-}" \
-e REPLICATE_API_KEY="${REPLICATE_API_KEY:-}" \
-v "$CONFIG_FILE:/app/data/config.json:ro" \
"${IMAGE_TAG}"
# Wait for Bifrost to be ready
echo "Waiting for Bifrost to start..."
MAX_WAIT=60
ELAPSED=0
HEALTH_OK=0
while [ $ELAPSED -lt $MAX_WAIT ]; do
if curl -sf "http://localhost:${TEST_PORT}/health" > /dev/null 2>&1; then
echo "Bifrost health check passed (attempt $((ELAPSED/2 + 1)))"
HEALTH_OK=1
break
fi
sleep 2
ELAPSED=$((ELAPSED + 2))
done
if [ $HEALTH_OK -eq 0 ]; then
echo "ERROR: Bifrost health check failed!"
echo "Container logs:"
docker logs "${CONTAINER_NAME}" 2>&1 | tail -100 || true
exit 1
fi
# # Run E2E API tests
# echo ""
# echo "=== Running E2E API tests ==="
# export BIFROST_BASE_URL="http://localhost:${TEST_PORT}"
# export CI=1
# echo pwd: $(pwd)
# # Run the E2E API test scripts (marked as flaky - failures are logged but don't block)
# if ! ./tests/e2e/api/runners/run-newman-inference-tests.sh; then
# echo "WARNING: runners/run-newman-inference-tests.sh failed (flaky test - continuing)"
# fi
# if ! ./tests/e2e/api/run-all-integrations.sh; then
# echo "WARNING: run-all-integrations.sh failed (flaky test - continuing)"
# fi
# if ! ./tests/e2e/api/runners/run-newman-api-tests.sh; then
# echo "WARNING: run-newman-api-tests.sh failed (flaky test - continuing)"
# fi
# echo ""
# echo "=== Docker image E2E API test passed for ${PLATFORM} ==="