302 lines
10 KiB
Bash
Executable File
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} ==="
|