| #!/bin/bash |
| set -e |
|
|
| |
| |
| |
|
|
| |
| 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 |
|
|
| |
| REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd -P)" |
|
|
|
|
| |
| 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() { |
| local exit_code=$? |
| echo "" |
| echo "=== Cleaning up ===" |
| |
| |
| echo "Stopping Bifrost container..." |
| docker stop "${CONTAINER_NAME}" > /dev/null 2>&1 || true |
| docker rm "${CONTAINER_NAME}" > /dev/null 2>&1 || true |
| |
| |
| echo "Stopping docker-compose services..." |
| docker compose -f "$DOCKER_COMPOSE_FILE" down -v > /dev/null 2>&1 || true |
| |
| |
| echo "Removing test image..." |
| docker rmi "${IMAGE_TAG}" > /dev/null 2>&1 || true |
| |
| |
| rm -rf "$TEMP_DIR" |
| |
| exit $exit_code |
| } |
| trap cleanup EXIT |
|
|
| |
| echo "Building Docker image (local modules)..." |
| docker build \ |
| --platform "${PLATFORM}" \ |
| -f transports/Dockerfile.local \ |
| -t "${IMAGE_TAG}" \ |
| . |
|
|
| echo "Build complete: ${IMAGE_TAG}" |
|
|
| |
| echo "" |
| echo "=== Starting docker-compose services ===" |
| docker compose -f "$DOCKER_COMPOSE_FILE" up -d |
|
|
| |
| 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 |
|
|
| |
| 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 |
|
|
| |
| 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, |
| "enable_litellm_fallbacks": false |
| }, |
| "encryption_key": "" |
| } |
| CONFIGEOF |
|
|
| echo "Config file created at: $CONFIG_FILE" |
|
|
| |
| 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}" |
|
|
| |
| 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 |
|
|
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
|
|