Files
bifrost/transports/bifrost-http/lib/validator_test.go
Beyhan Oğur 880f412e2c first commit
2026-04-26 21:52:23 +03:00

1477 lines
36 KiB
Go

package lib
import (
"os"
"path/filepath"
"runtime"
"strings"
"testing"
)
// loadLocalSchema reads the local config.schema.json for use in tests,
// avoiding remote fetches during test execution.
func loadLocalSchema(t *testing.T) []byte {
t.Helper()
_, filename, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("failed to get current file path")
}
schemaPath := filepath.Join(filepath.Dir(filename), "..", "..", "config.schema.json")
data, err := os.ReadFile(schemaPath)
if err != nil {
t.Fatalf("failed to read config.schema.json: %v", err)
}
return data
}
func TestValidateConfigSchema_ValidConfig(t *testing.T) {
// Minimal valid config matching the schema
validConfig := `{
"providers": {
"openai": {
"keys": [
{
"name": "default",
"value": "sk-test-key",
"weight": 1.0,
"models": ["gpt-4"]
}
]
}
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_EmptyObject(t *testing.T) {
// Empty object should be valid (all properties are optional)
emptyConfig := `{}`
err := ValidateConfigSchema([]byte(emptyConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected empty config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_InvalidJSON(t *testing.T) {
invalidJSON := `{invalid json`
err := ValidateConfigSchema([]byte(invalidJSON), loadLocalSchema(t))
if err == nil {
t.Error("expected invalid JSON to fail validation")
}
if !strings.Contains(err.Error(), "invalid JSON") {
t.Errorf("expected error to mention 'invalid JSON', got: %v", err)
}
}
func TestValidateConfigSchema_InvalidType(t *testing.T) {
// client.initial_pool_size should be an integer, not a string
invalidConfig := `{
"client": {
"initial_pool_size": "not-a-number"
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config with wrong type to fail validation")
}
}
func TestValidateConfigSchema_InvalidEnum(t *testing.T) {
// vector_store.type must be one of: weaviate, redis, qdrant, pinecone
invalidConfig := `{
"vector_store": {
"enabled": true,
"type": "invalid-store-type"
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config with invalid enum value to fail validation")
}
}
func TestValidateConfigSchema_MissingRequiredField(t *testing.T) {
// governance.budgets items require id, max_limit, and reset_duration
invalidConfig := `{
"governance": {
"budgets": [
{
"id": "budget-1"
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing required fields to fail validation")
}
}
func TestValidateConfigSchema_ValidGovernanceConfig(t *testing.T) {
validConfig := `{
"governance": {
"budgets": [
{
"id": "budget-1",
"max_limit": 100.0,
"reset_duration": "1d"
}
],
"virtual_keys": [
{
"id": "vk-1",
"name": "Test Key",
"value": "vk_test123"
}
]
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid governance config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_ValidClientConfig(t *testing.T) {
// allowed_origins with "*" or URI strings (but not both in same array according to oneOf)
validConfig := `{
"client": {
"initial_pool_size": 500,
"drop_excess_requests": true,
"enable_logging": true,
"log_retention_days": 30,
"allowed_origins": ["https://example.com"]
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid client config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_InvalidMinimum(t *testing.T) {
// initial_pool_size has minimum: 1
invalidConfig := `{
"client": {
"initial_pool_size": 0
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config with value below minimum to fail validation")
}
}
// =============================================================================
// Provider Key Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_ProviderKey_Valid(t *testing.T) {
// Valid provider key with all required fields: name, value, weight
validConfig := `{
"providers": {
"openai": {
"keys": [
{
"name": "my-key",
"value": "sk-test-key-12345",
"weight": 1.0
}
]
}
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid provider key config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_ProviderKey_MissingName(t *testing.T) {
// Missing required field: name
invalidConfig := `{
"providers": {
"openai": {
"keys": [
{
"value": "sk-test-key-12345",
"weight": 1.0
}
]
}
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'name' in provider key to fail validation")
}
}
func TestValidateConfigSchema_ProviderKey_MissingWeight(t *testing.T) {
// Missing required field: weight
invalidConfig := `{
"providers": {
"openai": {
"keys": [
{
"name": "my-key",
"value": "sk-test-key-12345"
}
]
}
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'weight' in provider key to fail validation")
}
}
// =============================================================================
// Governance Budget Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_Budget_Valid(t *testing.T) {
// Valid budget with all required fields: id, max_limit, reset_duration
validConfig := `{
"governance": {
"budgets": [
{
"id": "budget-1",
"max_limit": 100.0,
"reset_duration": "30d"
}
]
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid budget config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_Budget_MissingId(t *testing.T) {
// Missing required field: id
invalidConfig := `{
"governance": {
"budgets": [
{
"max_limit": 100.0,
"reset_duration": "30d"
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'id' in budget to fail validation")
}
}
func TestValidateConfigSchema_Budget_MissingMaxLimit(t *testing.T) {
// Missing required field: max_limit
invalidConfig := `{
"governance": {
"budgets": [
{
"id": "budget-1",
"reset_duration": "30d"
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'max_limit' in budget to fail validation")
}
}
func TestValidateConfigSchema_Budget_MissingResetDuration(t *testing.T) {
// Missing required field: reset_duration
invalidConfig := `{
"governance": {
"budgets": [
{
"id": "budget-1",
"max_limit": 100.0
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'reset_duration' in budget to fail validation")
}
}
// =============================================================================
// Governance Rate Limit Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_RateLimit_Valid(t *testing.T) {
// Valid rate limit with required field: id
validConfig := `{
"governance": {
"rate_limits": [
{
"id": "rate-limit-1",
"token_max_limit": 10000,
"token_reset_duration": "1h"
}
]
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid rate limit config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_RateLimit_MissingId(t *testing.T) {
// Missing required field: id
invalidConfig := `{
"governance": {
"rate_limits": [
{
"token_max_limit": 10000,
"token_reset_duration": "1h"
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'id' in rate limit to fail validation")
}
}
// =============================================================================
// Governance Customer Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_Customer_Valid(t *testing.T) {
// Valid customer with all required fields: id, name
validConfig := `{
"governance": {
"customers": [
{
"id": "customer-1",
"name": "Acme Corp"
}
]
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid customer config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_Customer_MissingId(t *testing.T) {
// Missing required field: id
invalidConfig := `{
"governance": {
"customers": [
{
"name": "Acme Corp"
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'id' in customer to fail validation")
}
}
func TestValidateConfigSchema_Customer_MissingName(t *testing.T) {
// Missing required field: name
invalidConfig := `{
"governance": {
"customers": [
{
"id": "customer-1"
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'name' in customer to fail validation")
}
}
// =============================================================================
// Governance Team Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_Team_Valid(t *testing.T) {
// Valid team with all required fields: id, name
validConfig := `{
"governance": {
"teams": [
{
"id": "team-1",
"name": "Engineering"
}
]
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid team config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_Team_MissingId(t *testing.T) {
// Missing required field: id
invalidConfig := `{
"governance": {
"teams": [
{
"name": "Engineering"
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'id' in team to fail validation")
}
}
func TestValidateConfigSchema_Team_MissingName(t *testing.T) {
// Missing required field: name
invalidConfig := `{
"governance": {
"teams": [
{
"id": "team-1"
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'name' in team to fail validation")
}
}
// =============================================================================
// Governance Virtual Key Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_VirtualKey_Valid(t *testing.T) {
// Valid virtual key with all required fields: id, name, value
validConfig := `{
"governance": {
"virtual_keys": [
{
"id": "vk-1",
"name": "Test Virtual Key",
"value": "vk_test_123456"
}
]
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid virtual key config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_VirtualKey_MissingId(t *testing.T) {
// Missing required field: id
invalidConfig := `{
"governance": {
"virtual_keys": [
{
"name": "Test Virtual Key",
"value": "vk_test_123456"
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'id' in virtual key to fail validation")
}
}
func TestValidateConfigSchema_VirtualKey_MissingName(t *testing.T) {
// Missing required field: name
invalidConfig := `{
"governance": {
"virtual_keys": [
{
"id": "vk-1",
"value": "vk_test_123456"
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'name' in virtual key to fail validation")
}
}
// =============================================================================
// Virtual Key Provider Config Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_VirtualKeyProviderConfig_Valid(t *testing.T) {
// Valid virtual key provider config with required field: provider
validConfig := `{
"governance": {
"virtual_keys": [
{
"id": "vk-1",
"name": "Test Virtual Key",
"value": "vk_test_123456",
"provider_configs": [
{
"provider": "openai"
}
]
}
]
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid virtual key provider config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_VirtualKeyProviderConfig_MissingProvider(t *testing.T) {
// Missing required field: provider
invalidConfig := `{
"governance": {
"virtual_keys": [
{
"id": "vk-1",
"name": "Test Virtual Key",
"value": "vk_test_123456",
"provider_configs": [
{
"weight": 1.0
}
]
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'provider' in virtual key provider config to fail validation")
}
}
// =============================================================================
// Virtual Key MCP Config Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_VirtualKeyMCPConfig_Valid(t *testing.T) {
// Valid virtual key MCP config identifying the MCP client by mcp_client_id (DB form)
validConfig := `{
"governance": {
"virtual_keys": [
{
"id": "vk-1",
"name": "Test Virtual Key",
"value": "vk_test_123456",
"mcp_configs": [
{
"mcp_client_id": 1
}
]
}
]
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid virtual key MCP config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_VirtualKeyMCPConfig_ValidWithClientName(t *testing.T) {
// Valid virtual key MCP config identifying the MCP client by mcp_client_name
// (config-file form — resolved to mcp_client_id at startup). Either identifier
// alone is sufficient; neither is required at the JSON Schema level.
validConfig := `{
"governance": {
"virtual_keys": [
{
"id": "vk-1",
"name": "Test Virtual Key",
"value": "vk_test_123456",
"mcp_configs": [
{
"mcp_client_name": "my-mcp-client",
"tools_to_execute": ["tool1"]
}
]
}
]
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected virtual key MCP config with mcp_client_name to pass validation, got error: %v", err)
}
}
// =============================================================================
// MCP Client Config Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_MCPClientConfig_Valid_Stdio(t *testing.T) {
// Valid MCP client config with stdio connection type
validConfig := `{
"mcp": {
"client_configs": [
{
"name": "my-mcp-client",
"connection_type": "stdio",
"stdio_config": {
"command": "/usr/bin/my-tool"
}
}
]
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid MCP client config (stdio) to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_MCPClientConfig_Valid_Sse(t *testing.T) {
// Valid MCP client config with sse connection type
validConfig := `{
"mcp": {
"client_configs": [
{
"name": "my-mcp-client",
"connection_type": "sse",
"connection_string": "http://localhost:8080"
}
]
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid MCP client config (sse) to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_MCPClientConfig_Valid_Http(t *testing.T) {
// Valid MCP client config with http connection type
validConfig := `{
"mcp": {
"client_configs": [
{
"name": "my-mcp-client",
"connection_type": "http",
"connection_string": "http://localhost:8080"
}
]
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid MCP client config (http) to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_MCPClientConfig_MissingName(t *testing.T) {
// Missing required field: name
invalidConfig := `{
"mcp": {
"client_configs": [
{
"connection_type": "stdio",
"stdio_config": {
"command": "/usr/bin/my-tool"
}
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'name' in MCP client config to fail validation")
}
}
func TestValidateConfigSchema_MCPClientConfig_MissingConnectionType(t *testing.T) {
// Missing required field: connection_type
invalidConfig := `{
"mcp": {
"client_configs": [
{
"name": "my-mcp-client",
"stdio_config": {
"command": "/usr/bin/my-tool"
}
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'connection_type' in MCP client config to fail validation")
}
}
func TestValidateConfigSchema_MCPClientConfig_MissingStdioConfig(t *testing.T) {
// Missing conditional required field: stdio_config when connection_type is stdio
invalidConfig := `{
"mcp": {
"client_configs": [
{
"name": "my-mcp-client",
"connection_type": "stdio"
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'stdio_config' for stdio connection type to fail validation")
}
}
func TestValidateConfigSchema_MCPClientConfig_MissingWebsocketConfig(t *testing.T) {
// Missing conditional required field: websocket_config when connection_type is websocket
invalidConfig := `{
"mcp": {
"client_configs": [
{
"name": "my-mcp-client",
"connection_type": "websocket"
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'websocket_config' for websocket connection type to fail validation")
}
}
func TestValidateConfigSchema_MCPClientConfig_MissingHttpConfig(t *testing.T) {
// Missing conditional required field: http_config when connection_type is http
invalidConfig := `{
"mcp": {
"client_configs": [
{
"name": "my-mcp-client",
"connection_type": "http"
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'http_config' for http connection type to fail validation")
}
}
func TestValidateConfigSchema_MCPClientConfig_StdioConfig_MissingCommand(t *testing.T) {
// Missing required field in stdio_config: command
invalidConfig := `{
"mcp": {
"client_configs": [
{
"name": "my-mcp-client",
"connection_type": "stdio",
"stdio_config": {
"args": ["--help"]
}
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'command' in stdio_config to fail validation")
}
}
func TestValidateConfigSchema_MCPClientConfig_WebsocketConfig_MissingUrl(t *testing.T) {
// Missing required field in websocket_config: url
invalidConfig := `{
"mcp": {
"client_configs": [
{
"name": "my-mcp-client",
"connection_type": "websocket",
"websocket_config": {}
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'url' in websocket_config to fail validation")
}
}
func TestValidateConfigSchema_MCPClientConfig_HttpConfig_MissingUrl(t *testing.T) {
// Missing required field in http_config: url
invalidConfig := `{
"mcp": {
"client_configs": [
{
"name": "my-mcp-client",
"connection_type": "http",
"http_config": {}
}
]
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'url' in http_config to fail validation")
}
}
// =============================================================================
// Concurrency Config Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_ConcurrencyConfig_Valid(t *testing.T) {
// Valid concurrency config with all required fields: concurrency, buffer_size
validConfig := `{
"providers": {
"openai": {
"keys": [
{
"name": "my-key",
"value": "sk-test-key",
"weight": 1.0
}
],
"concurrency_and_buffer_size": {
"concurrency": 10,
"buffer_size": 100
}
}
}
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid concurrency config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_ConcurrencyConfig_MissingConcurrency(t *testing.T) {
// Missing required field: concurrency
invalidConfig := `{
"providers": {
"openai": {
"keys": [
{
"name": "my-key",
"value": "sk-test-key",
"weight": 1.0
}
],
"concurrency_and_buffer_size": {
"buffer_size": 100
}
}
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'concurrency' in concurrency config to fail validation")
}
}
func TestValidateConfigSchema_ConcurrencyConfig_MissingBufferSize(t *testing.T) {
// Missing required field: buffer_size
invalidConfig := `{
"providers": {
"openai": {
"keys": [
{
"name": "my-key",
"value": "sk-test-key",
"weight": 1.0
}
],
"concurrency_and_buffer_size": {
"concurrency": 10
}
}
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'buffer_size' in concurrency config to fail validation")
}
}
// =============================================================================
// Plugin Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_Plugin_Valid(t *testing.T) {
// Valid plugin with all required fields: enabled, name, config
// Note: telemetry plugin requires config object
validConfig := `{
"plugins": [
{
"enabled": true,
"name": "telemetry",
"config": {}
}
]
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid plugin config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_Plugin_MissingEnabled(t *testing.T) {
// Missing required field: enabled
invalidConfig := `{
"plugins": [
{
"name": "telemetry"
}
]
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'enabled' in plugin to fail validation")
}
}
func TestValidateConfigSchema_Plugin_MissingName(t *testing.T) {
// Missing required field: name
invalidConfig := `{
"plugins": [
{
"enabled": true
}
]
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'name' in plugin to fail validation")
}
}
// =============================================================================
// Semantic Cache Plugin Config Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_SemanticCachePlugin_Valid(t *testing.T) {
// Valid semantic cache plugin with provider, embedding model, and dimension. Keys are injected at runtime.
validConfig := `{
"plugins": [
{
"enabled": true,
"name": "semantic_cache",
"config": {
"provider": "openai",
"embedding_model": "text-embedding-3-small",
"dimension": 1536
}
}
]
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid semantic cache plugin config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_SemanticCachePlugin_MissingProvider(t *testing.T) {
// Missing required field: provider for semantic mode (dimension > 1)
invalidConfig := `{
"plugins": [
{
"enabled": true,
"name": "semantic_cache",
"config": {
"dimension": 1536
}
}
]
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'provider' in semantic cache plugin to fail validation")
}
}
func TestValidateConfigSchema_SemanticCachePlugin_ProviderWithoutKeys(t *testing.T) {
// Keys are not required at schema level for provider-backed config.
validConfig := `{
"plugins": [
{
"enabled": true,
"name": "semantic_cache",
"config": {
"provider": "openai",
"embedding_model": "text-embedding-3-small",
"dimension": 1536
}
}
]
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected provider-backed semantic cache config without plugin keys to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_SemanticCachePlugin_ProviderWithoutEmbeddingModel(t *testing.T) {
invalidConfig := `{
"plugins": [
{
"enabled": true,
"name": "semantic_cache",
"config": {
"provider": "openai",
"dimension": 1536
}
}
]
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected provider-backed semantic cache config without embedding_model to fail validation")
}
}
func TestValidateConfigSchema_SemanticCachePlugin_DirectModeValid(t *testing.T) {
validConfig := `{
"plugins": [
{
"enabled": true,
"name": "semantic_cache",
"config": {
"dimension": 1
}
}
]
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected direct-only semantic cache config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_SemanticCachePlugin_DirectModeWithEmbeddingModelInvalid(t *testing.T) {
invalidConfig := `{
"plugins": [
{
"enabled": true,
"name": "semantic_cache",
"config": {
"dimension": 1,
"embedding_model": "text-embedding-3-small"
}
}
]
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected direct-only semantic cache config with embedding_model to fail validation")
}
}
func TestValidateConfigSchema_SemanticCachePlugin_DimensionOneWithProviderInvalid(t *testing.T) {
invalidConfig := `{
"plugins": [
{
"enabled": true,
"name": "semantic_cache",
"config": {
"provider": "openai",
"embedding_model": "text-embedding-3-small",
"dimension": 1
}
}
]
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected dimension: 1 with provider in semantic cache plugin to fail validation")
}
}
func TestValidateConfigSchema_SemanticCachePlugin_MissingDimension(t *testing.T) {
// Missing required field: dimension
invalidConfig := `{
"plugins": [
{
"enabled": true,
"name": "semantic_cache",
"config": {
"provider": "openai",
"embedding_model": "text-embedding-3-small"
}
}
]
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'dimension' in semantic cache plugin to fail validation")
}
}
// =============================================================================
// OTEL Plugin Config Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_OtelPlugin_Valid(t *testing.T) {
// Valid OTEL plugin with all required fields: collector_url, trace_type, protocol
validConfig := `{
"plugins": [
{
"enabled": true,
"name": "otel",
"config": {
"collector_url": "http://localhost:4318",
"trace_type": "genai_extension",
"protocol": "http"
}
}
]
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid OTEL plugin config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_OtelPlugin_MissingCollectorUrl(t *testing.T) {
// Missing required field: collector_url
invalidConfig := `{
"plugins": [
{
"enabled": true,
"name": "otel",
"config": {
"trace_type": "genai_extension",
"protocol": "http"
}
}
]
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'collector_url' in OTEL plugin to fail validation")
}
}
func TestValidateConfigSchema_OtelPlugin_MissingTraceType(t *testing.T) {
// Missing required field: trace_type
invalidConfig := `{
"plugins": [
{
"enabled": true,
"name": "otel",
"config": {
"collector_url": "http://localhost:4318",
"protocol": "http"
}
}
]
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'trace_type' in OTEL plugin to fail validation")
}
}
func TestValidateConfigSchema_OtelPlugin_MissingProtocol(t *testing.T) {
// Missing required field: protocol
invalidConfig := `{
"plugins": [
{
"enabled": true,
"name": "otel",
"config": {
"collector_url": "http://localhost:4318",
"trace_type": "genai_extension"
}
}
]
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'protocol' in OTEL plugin to fail validation")
}
}
// =============================================================================
// Maxim Plugin Config Required Fields Tests
// =============================================================================
func TestValidateConfigSchema_MaximPlugin_Valid(t *testing.T) {
// Valid Maxim plugin with required field: api_key
validConfig := `{
"plugins": [
{
"enabled": true,
"name": "maxim",
"config": {
"api_key": "maxim-api-key-12345"
}
}
]
}`
err := ValidateConfigSchema([]byte(validConfig), loadLocalSchema(t))
if err != nil {
t.Errorf("expected valid Maxim plugin config to pass validation, got error: %v", err)
}
}
func TestValidateConfigSchema_MaximPlugin_MissingApiKey(t *testing.T) {
// Missing required field: api_key
invalidConfig := `{
"plugins": [
{
"enabled": true,
"name": "maxim",
"config": {
"log_repo_id": "my-log-repo"
}
}
]
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'api_key' in Maxim plugin to fail validation")
}
}
// =============================================================================
// Azure Key Config Required Fields Tests
// Note: Azure provider uses a special key schema that extends base_key
// The azure_key_config is only valid within the azure provider's keys array
// =============================================================================
func TestValidateConfigSchema_AzureKeyConfig_MissingEndpoint(t *testing.T) {
// Missing required field: endpoint in azure_key_config
// This test validates that when azure_key_config is present, endpoint is required
invalidConfig := `{
"providers": {
"azure": {
"keys": [
{
"name": "azure-key",
"value": "azure-api-key",
"weight": 1.0,
"azure_key_config": {
"api_version": "2024-02-15-preview"
}
}
]
}
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'endpoint' in Azure key config to fail validation")
}
}
func TestValidateConfigSchema_AzureKeyConfig_MissingApiVersion(t *testing.T) {
// Missing required field: api_version in azure_key_config
invalidConfig := `{
"providers": {
"azure": {
"keys": [
{
"name": "azure-key",
"value": "azure-api-key",
"weight": 1.0,
"azure_key_config": {
"endpoint": "https://my-resource.openai.azure.com"
}
}
]
}
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'api_version' in Azure key config to fail validation")
}
}
// =============================================================================
// Vertex Key Config Required Fields Tests
// Note: Vertex provider uses a special key schema that extends base_key
// =============================================================================
func TestValidateConfigSchema_VertexKeyConfig_MissingProjectId(t *testing.T) {
// Missing required field: project_id in vertex_key_config
invalidConfig := `{
"providers": {
"vertex": {
"keys": [
{
"name": "vertex-key",
"value": "vertex-api-key",
"weight": 1.0,
"vertex_key_config": {
"region": "us-central1"
}
}
]
}
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'project_id' in Vertex key config to fail validation")
}
}
func TestValidateConfigSchema_VertexKeyConfig_MissingRegion(t *testing.T) {
// Missing required field: region in vertex_key_config
invalidConfig := `{
"providers": {
"vertex": {
"keys": [
{
"name": "vertex-key",
"value": "vertex-api-key",
"weight": 1.0,
"vertex_key_config": {
"project_id": "my-gcp-project"
}
}
]
}
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'region' in Vertex key config to fail validation")
}
}
// =============================================================================
// Bedrock Key Config Required Fields Tests
// Note: Bedrock provider uses a special key schema that extends base_key
// =============================================================================
func TestValidateConfigSchema_BedrockKeyConfig_MissingRegion(t *testing.T) {
// Missing required field: region in bedrock_key_config
invalidConfig := `{
"providers": {
"bedrock": {
"keys": [
{
"name": "bedrock-key",
"value": "bedrock-api-key",
"weight": 1.0,
"bedrock_key_config": {
"access_key": "AKIAIOSFODNN7EXAMPLE"
}
}
]
}
}
}`
err := ValidateConfigSchema([]byte(invalidConfig), loadLocalSchema(t))
if err == nil {
t.Error("expected config missing 'region' in Bedrock key config to fail validation")
}
}
// =============================================================================
// Guardrails Config Tests
// Note: Guardrails is an enterprise feature. The guardrails_config schema
// validation is tested but the detailed rules/providers validation is only
// available in the enterprise version. The public schema validates that the
// guardrails_config exists but doesn't expose detailed structure.
// =============================================================================
// Guardrails tests are skipped for the public schema as guardrails_config
// is an enterprise feature with a different schema structure.
// Enterprise-specific tests should be added to the enterprise test suite.