diff --git a/api/tests/unit_tests/models/test_tool_models.py b/api/tests/unit_tests/models/test_tool_models.py new file mode 100644 index 0000000000..1a75eb9a01 --- /dev/null +++ b/api/tests/unit_tests/models/test_tool_models.py @@ -0,0 +1,966 @@ +""" +Comprehensive unit tests for Tool models. + +This test suite covers: +- ToolProvider model validation (BuiltinToolProvider, ApiToolProvider) +- BuiltinToolProvider relationships and credential management +- ApiToolProvider credential storage and encryption +- Tool OAuth client models +- ToolLabelBinding relationships +""" + +import json +from uuid import uuid4 + +from core.tools.entities.tool_entities import ApiProviderSchemaType +from models.tools import ( + ApiToolProvider, + BuiltinToolProvider, + ToolLabelBinding, + ToolOAuthSystemClient, + ToolOAuthTenantClient, +) + + +class TestBuiltinToolProviderValidation: + """Test suite for BuiltinToolProvider model validation and operations.""" + + def test_builtin_tool_provider_creation_with_required_fields(self): + """Test creating a builtin tool provider with all required fields.""" + # Arrange + tenant_id = str(uuid4()) + user_id = str(uuid4()) + provider_name = "google" + credentials = {"api_key": "test_key_123"} + + # Act + builtin_provider = BuiltinToolProvider( + tenant_id=tenant_id, + user_id=user_id, + provider=provider_name, + encrypted_credentials=json.dumps(credentials), + name="Google API Key 1", + ) + + # Assert + assert builtin_provider.tenant_id == tenant_id + assert builtin_provider.user_id == user_id + assert builtin_provider.provider == provider_name + assert builtin_provider.name == "Google API Key 1" + assert builtin_provider.encrypted_credentials == json.dumps(credentials) + + def test_builtin_tool_provider_credentials_property(self): + """Test credentials property parses JSON correctly.""" + # Arrange + credentials_data = { + "api_key": "sk-test123", + "auth_type": "api_key", + "endpoint": "https://api.example.com", + } + builtin_provider = BuiltinToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + provider="custom_provider", + name="Custom Provider Key", + encrypted_credentials=json.dumps(credentials_data), + ) + + # Act + result = builtin_provider.credentials + + # Assert + assert result == credentials_data + assert result["api_key"] == "sk-test123" + assert result["auth_type"] == "api_key" + + def test_builtin_tool_provider_credentials_empty_when_none(self): + """Test credentials property returns empty dict when encrypted_credentials is None.""" + # Arrange + builtin_provider = BuiltinToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + provider="test_provider", + name="Test Provider", + encrypted_credentials=None, + ) + + # Act + result = builtin_provider.credentials + + # Assert + assert result == {} + + def test_builtin_tool_provider_credentials_empty_when_empty_string(self): + """Test credentials property returns empty dict when encrypted_credentials is empty.""" + # Arrange + builtin_provider = BuiltinToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + provider="test_provider", + name="Test Provider", + encrypted_credentials="", + ) + + # Act + result = builtin_provider.credentials + + # Assert + assert result == {} + + def test_builtin_tool_provider_default_values(self): + """Test builtin tool provider default values.""" + # Arrange & Act + builtin_provider = BuiltinToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + provider="test_provider", + name="Test Provider", + ) + + # Assert + assert builtin_provider.is_default is False + assert builtin_provider.credential_type == "api-key" + assert builtin_provider.expires_at == -1 + + def test_builtin_tool_provider_with_oauth_credential_type(self): + """Test builtin tool provider with OAuth credential type.""" + # Arrange + credentials = { + "access_token": "oauth_token_123", + "refresh_token": "refresh_token_456", + "token_type": "Bearer", + } + + # Act + builtin_provider = BuiltinToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + provider="google", + name="Google OAuth", + encrypted_credentials=json.dumps(credentials), + credential_type="oauth2", + expires_at=1735689600, + ) + + # Assert + assert builtin_provider.credential_type == "oauth2" + assert builtin_provider.expires_at == 1735689600 + assert builtin_provider.credentials["access_token"] == "oauth_token_123" + + def test_builtin_tool_provider_is_default_flag(self): + """Test is_default flag for builtin tool provider.""" + # Arrange + provider1 = BuiltinToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + provider="google", + name="Google Key 1", + is_default=True, + ) + provider2 = BuiltinToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + provider="google", + name="Google Key 2", + is_default=False, + ) + + # Assert + assert provider1.is_default is True + assert provider2.is_default is False + + def test_builtin_tool_provider_unique_constraint_fields(self): + """Test unique constraint fields (tenant_id, provider, name).""" + # Arrange + tenant_id = str(uuid4()) + provider_name = "google" + credential_name = "My Google Key" + + # Act + builtin_provider = BuiltinToolProvider( + tenant_id=tenant_id, + user_id=str(uuid4()), + provider=provider_name, + name=credential_name, + ) + + # Assert - these fields form unique constraint + assert builtin_provider.tenant_id == tenant_id + assert builtin_provider.provider == provider_name + assert builtin_provider.name == credential_name + + def test_builtin_tool_provider_multiple_credentials_same_provider(self): + """Test multiple credential sets for the same provider.""" + # Arrange + tenant_id = str(uuid4()) + user_id = str(uuid4()) + provider = "openai" + + # Act - create multiple credentials for same provider + provider1 = BuiltinToolProvider( + tenant_id=tenant_id, + user_id=user_id, + provider=provider, + name="OpenAI Key 1", + encrypted_credentials=json.dumps({"api_key": "key1"}), + ) + provider2 = BuiltinToolProvider( + tenant_id=tenant_id, + user_id=user_id, + provider=provider, + name="OpenAI Key 2", + encrypted_credentials=json.dumps({"api_key": "key2"}), + ) + + # Assert - different names allow multiple credentials + assert provider1.provider == provider2.provider + assert provider1.name != provider2.name + assert provider1.credentials != provider2.credentials + + +class TestApiToolProviderValidation: + """Test suite for ApiToolProvider model validation and operations.""" + + def test_api_tool_provider_creation_with_required_fields(self): + """Test creating an API tool provider with all required fields.""" + # Arrange + tenant_id = str(uuid4()) + user_id = str(uuid4()) + provider_name = "Custom API" + schema = '{"openapi": "3.0.0", "info": {"title": "Test API"}}' + tools = [{"name": "test_tool", "description": "A test tool"}] + credentials = {"auth_type": "api_key", "api_key_value": "test123"} + + # Act + api_provider = ApiToolProvider( + tenant_id=tenant_id, + user_id=user_id, + name=provider_name, + icon='{"type": "emoji", "value": "🔧"}', + schema=schema, + schema_type_str="openapi", + description="Custom API for testing", + tools_str=json.dumps(tools), + credentials_str=json.dumps(credentials), + ) + + # Assert + assert api_provider.tenant_id == tenant_id + assert api_provider.user_id == user_id + assert api_provider.name == provider_name + assert api_provider.schema == schema + assert api_provider.schema_type_str == "openapi" + assert api_provider.description == "Custom API for testing" + + def test_api_tool_provider_schema_type_property(self): + """Test schema_type property converts string to enum.""" + # Arrange + api_provider = ApiToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + name="Test API", + icon="{}", + schema="{}", + schema_type_str="openapi", + description="Test", + tools_str="[]", + credentials_str="{}", + ) + + # Act + result = api_provider.schema_type + + # Assert + assert result == ApiProviderSchemaType.OPENAPI + + def test_api_tool_provider_tools_property(self): + """Test tools property parses JSON and returns ApiToolBundle list.""" + # Arrange + tools_data = [ + { + "author": "test", + "server_url": "https://api.weather.com", + "method": "get", + "summary": "Get weather information", + "operation_id": "getWeather", + "parameters": [], + "openapi": { + "operation_id": "getWeather", + "parameters": [], + "method": "get", + "path": "/weather", + "server_url": "https://api.weather.com", + }, + }, + { + "author": "test", + "server_url": "https://api.location.com", + "method": "get", + "summary": "Get location data", + "operation_id": "getLocation", + "parameters": [], + "openapi": { + "operation_id": "getLocation", + "parameters": [], + "method": "get", + "path": "/location", + "server_url": "https://api.location.com", + }, + }, + ] + api_provider = ApiToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + name="Weather API", + icon="{}", + schema="{}", + schema_type_str="openapi", + description="Weather API", + tools_str=json.dumps(tools_data), + credentials_str="{}", + ) + + # Act + result = api_provider.tools + + # Assert + assert len(result) == 2 + assert result[0].operation_id == "getWeather" + assert result[1].operation_id == "getLocation" + + def test_api_tool_provider_credentials_property(self): + """Test credentials property parses JSON correctly.""" + # Arrange + credentials_data = { + "auth_type": "api_key_header", + "api_key_header": "Authorization", + "api_key_value": "Bearer test_token", + "api_key_header_prefix": "bearer", + } + api_provider = ApiToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + name="Secure API", + icon="{}", + schema="{}", + schema_type_str="openapi", + description="Secure API", + tools_str="[]", + credentials_str=json.dumps(credentials_data), + ) + + # Act + result = api_provider.credentials + + # Assert + assert result["auth_type"] == "api_key_header" + assert result["api_key_header"] == "Authorization" + assert result["api_key_value"] == "Bearer test_token" + + def test_api_tool_provider_with_privacy_policy(self): + """Test API tool provider with privacy policy.""" + # Arrange + privacy_policy_url = "https://example.com/privacy" + + # Act + api_provider = ApiToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + name="Privacy API", + icon="{}", + schema="{}", + schema_type_str="openapi", + description="API with privacy policy", + tools_str="[]", + credentials_str="{}", + privacy_policy=privacy_policy_url, + ) + + # Assert + assert api_provider.privacy_policy == privacy_policy_url + + def test_api_tool_provider_with_custom_disclaimer(self): + """Test API tool provider with custom disclaimer.""" + # Arrange + disclaimer = "This API is provided as-is without warranty." + + # Act + api_provider = ApiToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + name="Disclaimer API", + icon="{}", + schema="{}", + schema_type_str="openapi", + description="API with disclaimer", + tools_str="[]", + credentials_str="{}", + custom_disclaimer=disclaimer, + ) + + # Assert + assert api_provider.custom_disclaimer == disclaimer + + def test_api_tool_provider_default_custom_disclaimer(self): + """Test API tool provider default custom_disclaimer is empty string.""" + # Arrange & Act + api_provider = ApiToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + name="Default API", + icon="{}", + schema="{}", + schema_type_str="openapi", + description="API", + tools_str="[]", + credentials_str="{}", + ) + + # Assert + assert api_provider.custom_disclaimer == "" + + def test_api_tool_provider_unique_constraint_fields(self): + """Test unique constraint fields (name, tenant_id).""" + # Arrange + tenant_id = str(uuid4()) + provider_name = "Unique API" + + # Act + api_provider = ApiToolProvider( + tenant_id=tenant_id, + user_id=str(uuid4()), + name=provider_name, + icon="{}", + schema="{}", + schema_type_str="openapi", + description="Unique API", + tools_str="[]", + credentials_str="{}", + ) + + # Assert - these fields form unique constraint + assert api_provider.tenant_id == tenant_id + assert api_provider.name == provider_name + + def test_api_tool_provider_with_no_auth(self): + """Test API tool provider with no authentication.""" + # Arrange + credentials = {"auth_type": "none"} + + # Act + api_provider = ApiToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + name="Public API", + icon="{}", + schema="{}", + schema_type_str="openapi", + description="Public API with no auth", + tools_str="[]", + credentials_str=json.dumps(credentials), + ) + + # Assert + assert api_provider.credentials["auth_type"] == "none" + + def test_api_tool_provider_with_api_key_query_auth(self): + """Test API tool provider with API key in query parameter.""" + # Arrange + credentials = { + "auth_type": "api_key_query", + "api_key_query_param": "apikey", + "api_key_value": "my_secret_key", + } + + # Act + api_provider = ApiToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + name="Query Auth API", + icon="{}", + schema="{}", + schema_type_str="openapi", + description="API with query auth", + tools_str="[]", + credentials_str=json.dumps(credentials), + ) + + # Assert + assert api_provider.credentials["auth_type"] == "api_key_query" + assert api_provider.credentials["api_key_query_param"] == "apikey" + + +class TestToolOAuthModels: + """Test suite for OAuth client models (system and tenant level).""" + + def test_oauth_system_client_creation(self): + """Test creating a system-level OAuth client.""" + # Arrange + plugin_id = "builtin.google" + provider = "google" + oauth_params = json.dumps( + {"client_id": "system_client_id", "client_secret": "system_secret", "scope": "email profile"} + ) + + # Act + oauth_client = ToolOAuthSystemClient( + plugin_id=plugin_id, + provider=provider, + encrypted_oauth_params=oauth_params, + ) + + # Assert + assert oauth_client.plugin_id == plugin_id + assert oauth_client.provider == provider + assert oauth_client.encrypted_oauth_params == oauth_params + + def test_oauth_system_client_unique_constraint(self): + """Test unique constraint on plugin_id and provider.""" + # Arrange + plugin_id = "builtin.github" + provider = "github" + + # Act + oauth_client = ToolOAuthSystemClient( + plugin_id=plugin_id, + provider=provider, + encrypted_oauth_params="{}", + ) + + # Assert - these fields form unique constraint + assert oauth_client.plugin_id == plugin_id + assert oauth_client.provider == provider + + def test_oauth_tenant_client_creation(self): + """Test creating a tenant-level OAuth client.""" + # Arrange + tenant_id = str(uuid4()) + plugin_id = "builtin.google" + provider = "google" + + # Act + oauth_client = ToolOAuthTenantClient( + tenant_id=tenant_id, + plugin_id=plugin_id, + provider=provider, + ) + # Set encrypted_oauth_params after creation (it has init=False) + oauth_params = json.dumps({"client_id": "tenant_client_id", "client_secret": "tenant_secret"}) + oauth_client.encrypted_oauth_params = oauth_params + + # Assert + assert oauth_client.tenant_id == tenant_id + assert oauth_client.plugin_id == plugin_id + assert oauth_client.provider == provider + + def test_oauth_tenant_client_enabled_default(self): + """Test OAuth tenant client enabled flag has init=False and uses server default.""" + # Arrange & Act + oauth_client = ToolOAuthTenantClient( + tenant_id=str(uuid4()), + plugin_id="builtin.slack", + provider="slack", + ) + + # Assert - enabled has init=False, so it won't be set until saved to DB + # We can manually set it to test the field exists + oauth_client.enabled = True + assert oauth_client.enabled is True + + def test_oauth_tenant_client_oauth_params_property(self): + """Test oauth_params property parses JSON correctly.""" + # Arrange + params_data = { + "client_id": "test_client_123", + "client_secret": "secret_456", + "redirect_uri": "https://app.example.com/callback", + } + oauth_client = ToolOAuthTenantClient( + tenant_id=str(uuid4()), + plugin_id="builtin.dropbox", + provider="dropbox", + ) + # Set encrypted_oauth_params after creation (it has init=False) + oauth_client.encrypted_oauth_params = json.dumps(params_data) + + # Act + result = oauth_client.oauth_params + + # Assert + assert result == params_data + assert result["client_id"] == "test_client_123" + assert result["redirect_uri"] == "https://app.example.com/callback" + + def test_oauth_tenant_client_oauth_params_empty_when_none(self): + """Test oauth_params returns empty dict when encrypted_oauth_params is None.""" + # Arrange + oauth_client = ToolOAuthTenantClient( + tenant_id=str(uuid4()), + plugin_id="builtin.test", + provider="test", + ) + # encrypted_oauth_params has init=False, set it to None + oauth_client.encrypted_oauth_params = None + + # Act + result = oauth_client.oauth_params + + # Assert + assert result == {} + + def test_oauth_tenant_client_disabled_state(self): + """Test OAuth tenant client can be disabled.""" + # Arrange + oauth_client = ToolOAuthTenantClient( + tenant_id=str(uuid4()), + plugin_id="builtin.microsoft", + provider="microsoft", + ) + + # Act + oauth_client.enabled = False + + # Assert + assert oauth_client.enabled is False + + +class TestToolLabelBinding: + """Test suite for ToolLabelBinding model.""" + + def test_tool_label_binding_creation(self): + """Test creating a tool label binding.""" + # Arrange + tool_id = "google.search" + tool_type = "builtin" + label_name = "search" + + # Act + label_binding = ToolLabelBinding( + tool_id=tool_id, + tool_type=tool_type, + label_name=label_name, + ) + + # Assert + assert label_binding.tool_id == tool_id + assert label_binding.tool_type == tool_type + assert label_binding.label_name == label_name + + def test_tool_label_binding_unique_constraint(self): + """Test unique constraint on tool_id and label_name.""" + # Arrange + tool_id = "openai.text_generation" + label_name = "text" + + # Act + label_binding = ToolLabelBinding( + tool_id=tool_id, + tool_type="builtin", + label_name=label_name, + ) + + # Assert - these fields form unique constraint + assert label_binding.tool_id == tool_id + assert label_binding.label_name == label_name + + def test_tool_label_binding_multiple_labels_same_tool(self): + """Test multiple labels can be bound to the same tool.""" + # Arrange + tool_id = "google.search" + tool_type = "builtin" + + # Act + binding1 = ToolLabelBinding( + tool_id=tool_id, + tool_type=tool_type, + label_name="search", + ) + binding2 = ToolLabelBinding( + tool_id=tool_id, + tool_type=tool_type, + label_name="productivity", + ) + + # Assert + assert binding1.tool_id == binding2.tool_id + assert binding1.label_name != binding2.label_name + + def test_tool_label_binding_different_tool_types(self): + """Test label bindings for different tool types.""" + # Arrange + tool_types = ["builtin", "api", "workflow"] + + # Act & Assert + for tool_type in tool_types: + binding = ToolLabelBinding( + tool_id=f"test_tool_{tool_type}", + tool_type=tool_type, + label_name="test", + ) + assert binding.tool_type == tool_type + + +class TestCredentialStorage: + """Test suite for credential storage and encryption patterns.""" + + def test_builtin_provider_credential_storage_format(self): + """Test builtin provider stores credentials as JSON string.""" + # Arrange + credentials = { + "api_key": "sk-test123", + "endpoint": "https://api.example.com", + "timeout": 30, + } + + # Act + provider = BuiltinToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + provider="test", + name="Test Provider", + encrypted_credentials=json.dumps(credentials), + ) + + # Assert + assert isinstance(provider.encrypted_credentials, str) + assert provider.credentials == credentials + + def test_api_provider_credential_storage_format(self): + """Test API provider stores credentials as JSON string.""" + # Arrange + credentials = { + "auth_type": "api_key_header", + "api_key_header": "X-API-Key", + "api_key_value": "secret_key_789", + } + + # Act + provider = ApiToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + name="Test API", + icon="{}", + schema="{}", + schema_type_str="openapi", + description="Test", + tools_str="[]", + credentials_str=json.dumps(credentials), + ) + + # Assert + assert isinstance(provider.credentials_str, str) + assert provider.credentials == credentials + + def test_builtin_provider_complex_credential_structure(self): + """Test builtin provider with complex nested credential structure.""" + # Arrange + credentials = { + "auth_type": "oauth2", + "oauth_config": { + "access_token": "token123", + "refresh_token": "refresh456", + "expires_in": 3600, + "token_type": "Bearer", + }, + "additional_headers": {"X-Custom-Header": "value"}, + } + + # Act + provider = BuiltinToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + provider="oauth_provider", + name="OAuth Provider", + encrypted_credentials=json.dumps(credentials), + ) + + # Assert + assert provider.credentials["oauth_config"]["access_token"] == "token123" + assert provider.credentials["additional_headers"]["X-Custom-Header"] == "value" + + def test_api_provider_credential_update_pattern(self): + """Test pattern for updating API provider credentials.""" + # Arrange + original_credentials = {"auth_type": "api_key_header", "api_key_value": "old_key"} + provider = ApiToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + name="Update Test", + icon="{}", + schema="{}", + schema_type_str="openapi", + description="Test", + tools_str="[]", + credentials_str=json.dumps(original_credentials), + ) + + # Act - simulate credential update + new_credentials = {"auth_type": "api_key_header", "api_key_value": "new_key"} + provider.credentials_str = json.dumps(new_credentials) + + # Assert + assert provider.credentials["api_key_value"] == "new_key" + + def test_builtin_provider_credential_expiration(self): + """Test builtin provider credential expiration tracking.""" + # Arrange + future_timestamp = 1735689600 # Future date + past_timestamp = 1609459200 # Past date + + # Act + active_provider = BuiltinToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + provider="active", + name="Active Provider", + expires_at=future_timestamp, + ) + expired_provider = BuiltinToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + provider="expired", + name="Expired Provider", + expires_at=past_timestamp, + ) + never_expires_provider = BuiltinToolProvider( + tenant_id=str(uuid4()), + user_id=str(uuid4()), + provider="permanent", + name="Permanent Provider", + expires_at=-1, + ) + + # Assert + assert active_provider.expires_at == future_timestamp + assert expired_provider.expires_at == past_timestamp + assert never_expires_provider.expires_at == -1 + + def test_oauth_client_credential_storage(self): + """Test OAuth client credential storage pattern.""" + # Arrange + oauth_credentials = { + "client_id": "oauth_client_123", + "client_secret": "oauth_secret_456", + "authorization_url": "https://oauth.example.com/authorize", + "token_url": "https://oauth.example.com/token", + "scope": "read write", + } + + # Act + system_client = ToolOAuthSystemClient( + plugin_id="builtin.oauth_test", + provider="oauth_test", + encrypted_oauth_params=json.dumps(oauth_credentials), + ) + + tenant_client = ToolOAuthTenantClient( + tenant_id=str(uuid4()), + plugin_id="builtin.oauth_test", + provider="oauth_test", + ) + # Set encrypted_oauth_params after creation (it has init=False) + tenant_client.encrypted_oauth_params = json.dumps(oauth_credentials) + + # Assert + assert system_client.encrypted_oauth_params == json.dumps(oauth_credentials) + assert tenant_client.oauth_params == oauth_credentials + + +class TestToolProviderRelationships: + """Test suite for tool provider relationships and associations.""" + + def test_builtin_provider_tenant_relationship(self): + """Test builtin provider belongs to a tenant.""" + # Arrange + tenant_id = str(uuid4()) + + # Act + provider = BuiltinToolProvider( + tenant_id=tenant_id, + user_id=str(uuid4()), + provider="test", + name="Test Provider", + ) + + # Assert + assert provider.tenant_id == tenant_id + + def test_api_provider_user_relationship(self): + """Test API provider belongs to a user.""" + # Arrange + user_id = str(uuid4()) + + # Act + provider = ApiToolProvider( + tenant_id=str(uuid4()), + user_id=user_id, + name="User API", + icon="{}", + schema="{}", + schema_type_str="openapi", + description="Test", + tools_str="[]", + credentials_str="{}", + ) + + # Assert + assert provider.user_id == user_id + + def test_multiple_providers_same_tenant(self): + """Test multiple providers can belong to the same tenant.""" + # Arrange + tenant_id = str(uuid4()) + user_id = str(uuid4()) + + # Act + builtin1 = BuiltinToolProvider( + tenant_id=tenant_id, + user_id=user_id, + provider="google", + name="Google Key 1", + ) + builtin2 = BuiltinToolProvider( + tenant_id=tenant_id, + user_id=user_id, + provider="openai", + name="OpenAI Key 1", + ) + api1 = ApiToolProvider( + tenant_id=tenant_id, + user_id=user_id, + name="Custom API 1", + icon="{}", + schema="{}", + schema_type_str="openapi", + description="Test", + tools_str="[]", + credentials_str="{}", + ) + + # Assert + assert builtin1.tenant_id == tenant_id + assert builtin2.tenant_id == tenant_id + assert api1.tenant_id == tenant_id + + def test_tool_label_bindings_for_provider_tools(self): + """Test tool label bindings can be associated with provider tools.""" + # Arrange + provider_name = "google" + tool_id = f"{provider_name}.search" + + # Act + binding1 = ToolLabelBinding( + tool_id=tool_id, + tool_type="builtin", + label_name="search", + ) + binding2 = ToolLabelBinding( + tool_id=tool_id, + tool_type="builtin", + label_name="web", + ) + + # Assert + assert binding1.tool_id == tool_id + assert binding2.tool_id == tool_id + assert binding1.label_name != binding2.label_name