Compare commits

..

3 Commits

Author SHA1 Message Date
Averi Kitsch
a678886ee3 docs: update prebuilt tools ref (#2459)
## Description

> Should include a concise description of the changes (bug or feature),
it's
> impact, along with a summary of the solution

## PR Checklist

> Thank you for opening a Pull Request! Before submitting your PR, there
are a
> few things you can do to make sure it goes smoothly:

- [ ] Make sure you reviewed

[CONTRIBUTING.md](https://github.com/googleapis/genai-toolbox/blob/main/CONTRIBUTING.md)
- [ ] Make sure to open an issue as a

[bug/issue](https://github.com/googleapis/genai-toolbox/issues/new/choose)
  before writing your code! That way we can discuss the change, evaluate
  designs, and agree on the general idea
- [ ] Ensure the tests and linter pass
- [ ] Code coverage does not decrease (if any source code was changed)
- [ ] Appropriate docs were updated (if necessary)
- [ ] Make sure to add `!` if this involve a breaking change

🛠️ Fixes #<issue_number_goes_here>
2026-02-13 18:57:55 +00:00
Averi Kitsch
6602abd059 docs: update diagram (#2461)
## Description

> Should include a concise description of the changes (bug or feature),
it's
> impact, along with a summary of the solution

## PR Checklist

> Thank you for opening a Pull Request! Before submitting your PR, there
are a
> few things you can do to make sure it goes smoothly:

- [ ] Make sure you reviewed

[CONTRIBUTING.md](https://github.com/googleapis/genai-toolbox/blob/main/CONTRIBUTING.md)
- [ ] Make sure to open an issue as a

[bug/issue](https://github.com/googleapis/genai-toolbox/issues/new/choose)
  before writing your code! That way we can discuss the change, evaluate
  designs, and agree on the general idea
- [ ] Ensure the tests and linter pass
- [ ] Code coverage does not decrease (if any source code was changed)
- [ ] Appropriate docs were updated (if necessary)
- [ ] Make sure to add `!` if this involve a breaking change

🛠️ Fixes #<issue_number_goes_here>
2026-02-13 10:25:34 -08:00
Binh Tran
62b830987d fix: Deflake alloydb omni (#2431)
## Description

Improve logic to check that database is up.

**IMPORTANT** DO NOT MERGE until I have reverted
f7d7d9e708

## PR Checklist

- [x] Make sure you reviewed

[CONTRIBUTING.md](https://github.com/googleapis/genai-toolbox/blob/main/CONTRIBUTING.md)
- [x] https://github.com/googleapis/genai-toolbox/issues/2422
- [ ] Ensure the tests and linter pass
- [ ] Code coverage does not decrease (if any source code was changed)
- [ ] Appropriate docs were updated (if necessary)
- [ ] Make sure to add `!` if this involve a breaking change

🛠️ Fixes #2422

Co-authored-by: Averi Kitsch <akitsch@google.com>
2026-02-13 09:55:53 -08:00
15 changed files with 139 additions and 1486 deletions

View File

@@ -943,7 +943,7 @@ steps:
# Install the C compiler and Oracle SDK headers needed for cgo
dnf install -y gcc oracle-instantclient-devel
# Install Go
curl -L -o go.tar.gz "https://go.dev/dl/go1.25.5.linux-amd64.tar.gz"
curl -L -o go.tar.gz "https://go.dev/dl/go1.25.1.linux-amd64.tar.gz"
tar -C /usr/local -xzf go.tar.gz
export PATH="/usr/local/go/bin:$$PATH"

View File

@@ -37,7 +37,6 @@ extraFiles: [
"docs/en/how-to/connect-ide/postgres_mcp.md",
"docs/en/how-to/connect-ide/neo4j_mcp.md",
"docs/en/how-to/connect-ide/sqlite_mcp.md",
"docs/en/how-to/connect-ide/oracle_mcp.md",
"gemini-extension.json",
{
"type": "json",

View File

@@ -618,505 +618,6 @@ func TestSingleEdit(t *testing.T) {
}
}
func TestPrebuiltTools(t *testing.T) {
// Get prebuilt configs
alloydb_omni_config, _ := prebuiltconfigs.Get("alloydb-omni")
alloydb_admin_config, _ := prebuiltconfigs.Get("alloydb-postgres-admin")
alloydb_config, _ := prebuiltconfigs.Get("alloydb-postgres")
bigquery_config, _ := prebuiltconfigs.Get("bigquery")
clickhouse_config, _ := prebuiltconfigs.Get("clickhouse")
cloudsqlpg_config, _ := prebuiltconfigs.Get("cloud-sql-postgres")
cloudsqlpg_admin_config, _ := prebuiltconfigs.Get("cloud-sql-postgres-admin")
cloudsqlmysql_config, _ := prebuiltconfigs.Get("cloud-sql-mysql")
cloudsqlmysql_admin_config, _ := prebuiltconfigs.Get("cloud-sql-mysql-admin")
cloudsqlmssql_config, _ := prebuiltconfigs.Get("cloud-sql-mssql")
cloudsqlmssql_admin_config, _ := prebuiltconfigs.Get("cloud-sql-mssql-admin")
dataplex_config, _ := prebuiltconfigs.Get("dataplex")
firestoreconfig, _ := prebuiltconfigs.Get("firestore")
mysql_config, _ := prebuiltconfigs.Get("mysql")
mssql_config, _ := prebuiltconfigs.Get("mssql")
looker_config, _ := prebuiltconfigs.Get("looker")
lookerca_config, _ := prebuiltconfigs.Get("looker-conversational-analytics")
postgresconfig, _ := prebuiltconfigs.Get("postgres")
spanner_config, _ := prebuiltconfigs.Get("spanner")
spannerpg_config, _ := prebuiltconfigs.Get("spanner-postgres")
mindsdb_config, _ := prebuiltconfigs.Get("mindsdb")
sqlite_config, _ := prebuiltconfigs.Get("sqlite")
neo4jconfig, _ := prebuiltconfigs.Get("neo4j")
alloydbobsvconfig, _ := prebuiltconfigs.Get("alloydb-postgres-observability")
cloudsqlpgobsvconfig, _ := prebuiltconfigs.Get("cloud-sql-postgres-observability")
cloudsqlmysqlobsvconfig, _ := prebuiltconfigs.Get("cloud-sql-mysql-observability")
cloudsqlmssqlobsvconfig, _ := prebuiltconfigs.Get("cloud-sql-mssql-observability")
serverless_spark_config, _ := prebuiltconfigs.Get("serverless-spark")
cloudhealthcare_config, _ := prebuiltconfigs.Get("cloud-healthcare")
snowflake_config, _ := prebuiltconfigs.Get("snowflake")
// Set environment variables
t.Setenv("API_KEY", "your_api_key")
t.Setenv("BIGQUERY_PROJECT", "your_gcp_project_id")
t.Setenv("DATAPLEX_PROJECT", "your_gcp_project_id")
t.Setenv("FIRESTORE_PROJECT", "your_gcp_project_id")
t.Setenv("FIRESTORE_DATABASE", "your_firestore_db_name")
t.Setenv("SPANNER_PROJECT", "your_gcp_project_id")
t.Setenv("SPANNER_INSTANCE", "your_spanner_instance")
t.Setenv("SPANNER_DATABASE", "your_spanner_db")
t.Setenv("ALLOYDB_POSTGRES_PROJECT", "your_gcp_project_id")
t.Setenv("ALLOYDB_POSTGRES_REGION", "your_gcp_region")
t.Setenv("ALLOYDB_POSTGRES_CLUSTER", "your_alloydb_cluster")
t.Setenv("ALLOYDB_POSTGRES_INSTANCE", "your_alloydb_instance")
t.Setenv("ALLOYDB_POSTGRES_DATABASE", "your_alloydb_db")
t.Setenv("ALLOYDB_POSTGRES_USER", "your_alloydb_user")
t.Setenv("ALLOYDB_POSTGRES_PASSWORD", "your_alloydb_password")
t.Setenv("ALLOYDB_OMNI_HOST", "localhost")
t.Setenv("ALLOYDB_OMNI_PORT", "5432")
t.Setenv("ALLOYDB_OMNI_DATABASE", "your_alloydb_db")
t.Setenv("ALLOYDB_OMNI_USER", "your_alloydb_user")
t.Setenv("ALLOYDB_OMNI_PASSWORD", "your_alloydb_password")
t.Setenv("CLICKHOUSE_PROTOCOL", "your_clickhouse_protocol")
t.Setenv("CLICKHOUSE_DATABASE", "your_clickhouse_database")
t.Setenv("CLICKHOUSE_PASSWORD", "your_clickhouse_password")
t.Setenv("CLICKHOUSE_USER", "your_clickhouse_user")
t.Setenv("CLICKHOUSE_HOST", "your_clickhosue_host")
t.Setenv("CLICKHOUSE_PORT", "8123")
t.Setenv("CLOUD_SQL_POSTGRES_PROJECT", "your_pg_project")
t.Setenv("CLOUD_SQL_POSTGRES_INSTANCE", "your_pg_instance")
t.Setenv("CLOUD_SQL_POSTGRES_DATABASE", "your_pg_db")
t.Setenv("CLOUD_SQL_POSTGRES_REGION", "your_pg_region")
t.Setenv("CLOUD_SQL_POSTGRES_USER", "your_pg_user")
t.Setenv("CLOUD_SQL_POSTGRES_PASS", "your_pg_pass")
t.Setenv("CLOUD_SQL_MYSQL_PROJECT", "your_gcp_project_id")
t.Setenv("CLOUD_SQL_MYSQL_REGION", "your_gcp_region")
t.Setenv("CLOUD_SQL_MYSQL_INSTANCE", "your_instance")
t.Setenv("CLOUD_SQL_MYSQL_DATABASE", "your_cloudsql_mysql_db")
t.Setenv("CLOUD_SQL_MYSQL_USER", "your_cloudsql_mysql_user")
t.Setenv("CLOUD_SQL_MYSQL_PASSWORD", "your_cloudsql_mysql_password")
t.Setenv("CLOUD_SQL_MSSQL_PROJECT", "your_gcp_project_id")
t.Setenv("CLOUD_SQL_MSSQL_REGION", "your_gcp_region")
t.Setenv("CLOUD_SQL_MSSQL_INSTANCE", "your_cloudsql_mssql_instance")
t.Setenv("CLOUD_SQL_MSSQL_DATABASE", "your_cloudsql_mssql_db")
t.Setenv("CLOUD_SQL_MSSQL_IP_ADDRESS", "127.0.0.1")
t.Setenv("CLOUD_SQL_MSSQL_USER", "your_cloudsql_mssql_user")
t.Setenv("CLOUD_SQL_MSSQL_PASSWORD", "your_cloudsql_mssql_password")
t.Setenv("CLOUD_SQL_POSTGRES_PASSWORD", "your_cloudsql_pg_password")
t.Setenv("SERVERLESS_SPARK_PROJECT", "your_gcp_project_id")
t.Setenv("SERVERLESS_SPARK_LOCATION", "your_gcp_location")
t.Setenv("POSTGRES_HOST", "localhost")
t.Setenv("POSTGRES_PORT", "5432")
t.Setenv("POSTGRES_DATABASE", "your_postgres_db")
t.Setenv("POSTGRES_USER", "your_postgres_user")
t.Setenv("POSTGRES_PASSWORD", "your_postgres_password")
t.Setenv("MYSQL_HOST", "localhost")
t.Setenv("MYSQL_PORT", "3306")
t.Setenv("MYSQL_DATABASE", "your_mysql_db")
t.Setenv("MYSQL_USER", "your_mysql_user")
t.Setenv("MYSQL_PASSWORD", "your_mysql_password")
t.Setenv("MSSQL_HOST", "localhost")
t.Setenv("MSSQL_PORT", "1433")
t.Setenv("MSSQL_DATABASE", "your_mssql_db")
t.Setenv("MSSQL_USER", "your_mssql_user")
t.Setenv("MSSQL_PASSWORD", "your_mssql_password")
t.Setenv("MINDSDB_HOST", "localhost")
t.Setenv("MINDSDB_PORT", "47334")
t.Setenv("MINDSDB_DATABASE", "your_mindsdb_db")
t.Setenv("MINDSDB_USER", "your_mindsdb_user")
t.Setenv("MINDSDB_PASS", "your_mindsdb_password")
t.Setenv("LOOKER_BASE_URL", "https://your_company.looker.com")
t.Setenv("LOOKER_CLIENT_ID", "your_looker_client_id")
t.Setenv("LOOKER_CLIENT_SECRET", "your_looker_client_secret")
t.Setenv("LOOKER_VERIFY_SSL", "true")
t.Setenv("LOOKER_PROJECT", "your_project_id")
t.Setenv("LOOKER_LOCATION", "us")
t.Setenv("SQLITE_DATABASE", "test.db")
t.Setenv("NEO4J_URI", "bolt://localhost:7687")
t.Setenv("NEO4J_DATABASE", "neo4j")
t.Setenv("NEO4J_USERNAME", "your_neo4j_user")
t.Setenv("NEO4J_PASSWORD", "your_neo4j_password")
t.Setenv("CLOUD_HEALTHCARE_PROJECT", "your_gcp_project_id")
t.Setenv("CLOUD_HEALTHCARE_REGION", "your_gcp_region")
t.Setenv("CLOUD_HEALTHCARE_DATASET", "your_healthcare_dataset")
t.Setenv("SNOWFLAKE_ACCOUNT", "your_account")
t.Setenv("SNOWFLAKE_USER", "your_username")
t.Setenv("SNOWFLAKE_PASSWORD", "your_pass")
t.Setenv("SNOWFLAKE_DATABASE", "your_db")
t.Setenv("SNOWFLAKE_SCHEMA", "your_schema")
t.Setenv("SNOWFLAKE_WAREHOUSE", "your_wh")
t.Setenv("SNOWFLAKE_ROLE", "your_role")
t.Setenv("ORACLE_USERNAME", "your_oracle_db_username")
t.Setenv("ORACLE_PASS", "your_oracle_db_password")
t.Setenv("ORACLE_HOST", "your_oracle_db_host")
t.Setenv("ORACLE_PORT", "your_oracle_db_port")
t.Setenv("ORACLE_SERVICE_NAME", "your_oracle_service_name")
t.Setenv("ORACLE_USE_OCI", "your_oracle_db_use_oci")
t.Setenv("ORACLE_WALLET_LOCATION", "your_path_to_oracldb_wallet")
t.Setenv("ORACLE_TNS_ADMIN", "your_path_to_tns_admin")
ctx, err := testutils.ContextWithNewLogger()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
tcs := []struct {
name string
in []byte
wantToolset server.ToolsetConfigs
}{
{
name: "alloydb omni prebuilt tools",
in: alloydb_omni_config,
wantToolset: server.ToolsetConfigs{
"alloydb_omni_database_tools": tools.ToolsetConfig{
Name: "alloydb_omni_database_tools",
ToolNames: []string{"execute_sql", "list_tables", "list_active_queries", "list_available_extensions", "list_installed_extensions", "list_autovacuum_configurations", "list_columnar_configurations", "list_columnar_recommended_columns", "list_memory_configurations", "list_top_bloated_tables", "list_replication_slots", "list_invalid_indexes", "get_query_plan", "list_views", "list_schemas", "database_overview", "list_triggers", "list_indexes", "list_sequences", "long_running_transactions", "list_locks", "replication_stats", "list_query_stats", "get_column_cardinality", "list_publication_tables", "list_tablespaces", "list_pg_settings", "list_database_stats", "list_roles", "list_table_stats", "list_stored_procedure"},
},
},
},
{
name: "alloydb postgres admin prebuilt tools",
in: alloydb_admin_config,
wantToolset: server.ToolsetConfigs{
"alloydb_postgres_admin_tools": tools.ToolsetConfig{
Name: "alloydb_postgres_admin_tools",
ToolNames: []string{"create_cluster", "wait_for_operation", "create_instance", "list_clusters", "list_instances", "list_users", "create_user", "get_cluster", "get_instance", "get_user"},
},
},
},
{
name: "cloudsql pg admin prebuilt tools",
in: cloudsqlpg_admin_config,
wantToolset: server.ToolsetConfigs{
"cloud_sql_postgres_admin_tools": tools.ToolsetConfig{
Name: "cloud_sql_postgres_admin_tools",
ToolNames: []string{"create_instance", "get_instance", "list_instances", "create_database", "list_databases", "create_user", "wait_for_operation", "postgres_upgrade_precheck", "clone_instance", "create_backup", "restore_backup"},
},
},
},
{
name: "cloudsql mysql admin prebuilt tools",
in: cloudsqlmysql_admin_config,
wantToolset: server.ToolsetConfigs{
"cloud_sql_mysql_admin_tools": tools.ToolsetConfig{
Name: "cloud_sql_mysql_admin_tools",
ToolNames: []string{"create_instance", "get_instance", "list_instances", "create_database", "list_databases", "create_user", "wait_for_operation", "clone_instance", "create_backup", "restore_backup"},
},
},
},
{
name: "cloudsql mssql admin prebuilt tools",
in: cloudsqlmssql_admin_config,
wantToolset: server.ToolsetConfigs{
"cloud_sql_mssql_admin_tools": tools.ToolsetConfig{
Name: "cloud_sql_mssql_admin_tools",
ToolNames: []string{"create_instance", "get_instance", "list_instances", "create_database", "list_databases", "create_user", "wait_for_operation", "clone_instance", "create_backup", "restore_backup"},
},
},
},
{
name: "alloydb prebuilt tools",
in: alloydb_config,
wantToolset: server.ToolsetConfigs{
"alloydb_postgres_database_tools": tools.ToolsetConfig{
Name: "alloydb_postgres_database_tools",
ToolNames: []string{"execute_sql", "list_tables", "list_active_queries", "list_available_extensions", "list_installed_extensions", "list_autovacuum_configurations", "list_memory_configurations", "list_top_bloated_tables", "list_replication_slots", "list_invalid_indexes", "get_query_plan", "list_views", "list_schemas", "database_overview", "list_triggers", "list_indexes", "list_sequences", "long_running_transactions", "list_locks", "replication_stats", "list_query_stats", "get_column_cardinality", "list_publication_tables", "list_tablespaces", "list_pg_settings", "list_database_stats", "list_roles", "list_table_stats", "list_stored_procedure"},
},
},
},
{
name: "bigquery prebuilt tools",
in: bigquery_config,
wantToolset: server.ToolsetConfigs{
"bigquery_database_tools": tools.ToolsetConfig{
Name: "bigquery_database_tools",
ToolNames: []string{"analyze_contribution", "ask_data_insights", "execute_sql", "forecast", "get_dataset_info", "get_table_info", "list_dataset_ids", "list_table_ids", "search_catalog"},
},
},
},
{
name: "clickhouse prebuilt tools",
in: clickhouse_config,
wantToolset: server.ToolsetConfigs{
"clickhouse_database_tools": tools.ToolsetConfig{
Name: "clickhouse_database_tools",
ToolNames: []string{"execute_sql", "list_databases", "list_tables"},
},
},
},
{
name: "cloudsqlpg prebuilt tools",
in: cloudsqlpg_config,
wantToolset: server.ToolsetConfigs{
"cloud_sql_postgres_database_tools": tools.ToolsetConfig{
Name: "cloud_sql_postgres_database_tools",
ToolNames: []string{"execute_sql", "list_tables", "list_active_queries", "list_available_extensions", "list_installed_extensions", "list_autovacuum_configurations", "list_memory_configurations", "list_top_bloated_tables", "list_replication_slots", "list_invalid_indexes", "get_query_plan", "list_views", "list_schemas", "database_overview", "list_triggers", "list_indexes", "list_sequences", "long_running_transactions", "list_locks", "replication_stats", "list_query_stats", "get_column_cardinality", "list_publication_tables", "list_tablespaces", "list_pg_settings", "list_database_stats", "list_roles", "list_table_stats", "list_stored_procedure"},
},
},
},
{
name: "cloudsqlmysql prebuilt tools",
in: cloudsqlmysql_config,
wantToolset: server.ToolsetConfigs{
"cloud_sql_mysql_database_tools": tools.ToolsetConfig{
Name: "cloud_sql_mysql_database_tools",
ToolNames: []string{"execute_sql", "list_tables", "get_query_plan", "list_active_queries", "list_tables_missing_unique_indexes", "list_table_fragmentation"},
},
},
},
{
name: "cloudsqlmssql prebuilt tools",
in: cloudsqlmssql_config,
wantToolset: server.ToolsetConfigs{
"cloud_sql_mssql_database_tools": tools.ToolsetConfig{
Name: "cloud_sql_mssql_database_tools",
ToolNames: []string{"execute_sql", "list_tables"},
},
},
},
{
name: "dataplex prebuilt tools",
in: dataplex_config,
wantToolset: server.ToolsetConfigs{
"dataplex_tools": tools.ToolsetConfig{
Name: "dataplex_tools",
ToolNames: []string{"search_entries", "lookup_entry", "search_aspect_types"},
},
},
},
{
name: "serverless spark prebuilt tools",
in: serverless_spark_config,
wantToolset: server.ToolsetConfigs{
"serverless_spark_tools": tools.ToolsetConfig{
Name: "serverless_spark_tools",
ToolNames: []string{"list_batches", "get_batch", "cancel_batch", "create_pyspark_batch", "create_spark_batch"},
},
},
},
{
name: "firestore prebuilt tools",
in: firestoreconfig,
wantToolset: server.ToolsetConfigs{
"firestore_database_tools": tools.ToolsetConfig{
Name: "firestore_database_tools",
ToolNames: []string{"get_documents", "add_documents", "update_document", "list_collections", "delete_documents", "query_collection", "get_rules", "validate_rules"},
},
},
},
{
name: "mysql prebuilt tools",
in: mysql_config,
wantToolset: server.ToolsetConfigs{
"mysql_database_tools": tools.ToolsetConfig{
Name: "mysql_database_tools",
ToolNames: []string{"execute_sql", "list_tables", "get_query_plan", "list_active_queries", "list_tables_missing_unique_indexes", "list_table_fragmentation"},
},
},
},
{
name: "mssql prebuilt tools",
in: mssql_config,
wantToolset: server.ToolsetConfigs{
"mssql_database_tools": tools.ToolsetConfig{
Name: "mssql_database_tools",
ToolNames: []string{"execute_sql", "list_tables"},
},
},
},
{
name: "looker prebuilt tools",
in: looker_config,
wantToolset: server.ToolsetConfigs{
"looker_tools": tools.ToolsetConfig{
Name: "looker_tools",
ToolNames: []string{"get_models", "get_explores", "get_dimensions", "get_measures", "get_filters", "get_parameters", "query", "query_sql", "query_url", "get_looks", "run_look", "make_look", "get_dashboards", "run_dashboard", "make_dashboard", "add_dashboard_element", "add_dashboard_filter", "generate_embed_url", "health_pulse", "health_analyze", "health_vacuum", "dev_mode", "get_projects", "get_project_files", "get_project_file", "create_project_file", "update_project_file", "delete_project_file", "validate_project", "get_connections", "get_connection_schemas", "get_connection_databases", "get_connection_tables", "get_connection_table_columns"},
},
},
},
{
name: "looker-conversational-analytics prebuilt tools",
in: lookerca_config,
wantToolset: server.ToolsetConfigs{
"looker_conversational_analytics_tools": tools.ToolsetConfig{
Name: "looker_conversational_analytics_tools",
ToolNames: []string{"ask_data_insights", "get_models", "get_explores"},
},
},
},
{
name: "postgres prebuilt tools",
in: postgresconfig,
wantToolset: server.ToolsetConfigs{
"postgres_database_tools": tools.ToolsetConfig{
Name: "postgres_database_tools",
ToolNames: []string{"execute_sql", "list_tables", "list_active_queries", "list_available_extensions", "list_installed_extensions", "list_autovacuum_configurations", "list_memory_configurations", "list_top_bloated_tables", "list_replication_slots", "list_invalid_indexes", "get_query_plan", "list_views", "list_schemas", "database_overview", "list_triggers", "list_indexes", "list_sequences", "long_running_transactions", "list_locks", "replication_stats", "list_query_stats", "get_column_cardinality", "list_publication_tables", "list_tablespaces", "list_pg_settings", "list_database_stats", "list_roles", "list_table_stats", "list_stored_procedure"},
},
},
},
{
name: "spanner prebuilt tools",
in: spanner_config,
wantToolset: server.ToolsetConfigs{
"spanner-database-tools": tools.ToolsetConfig{
Name: "spanner-database-tools",
ToolNames: []string{"execute_sql", "execute_sql_dql", "list_tables", "list_graphs"},
},
},
},
{
name: "spanner pg prebuilt tools",
in: spannerpg_config,
wantToolset: server.ToolsetConfigs{
"spanner_postgres_database_tools": tools.ToolsetConfig{
Name: "spanner_postgres_database_tools",
ToolNames: []string{"execute_sql", "execute_sql_dql", "list_tables"},
},
},
},
{
name: "mindsdb prebuilt tools",
in: mindsdb_config,
wantToolset: server.ToolsetConfigs{
"mindsdb-tools": tools.ToolsetConfig{
Name: "mindsdb-tools",
ToolNames: []string{"mindsdb-execute-sql", "mindsdb-sql"},
},
},
},
{
name: "sqlite prebuilt tools",
in: sqlite_config,
wantToolset: server.ToolsetConfigs{
"sqlite_database_tools": tools.ToolsetConfig{
Name: "sqlite_database_tools",
ToolNames: []string{"execute_sql", "list_tables"},
},
},
},
{
name: "neo4j prebuilt tools",
in: neo4jconfig,
wantToolset: server.ToolsetConfigs{
"neo4j_database_tools": tools.ToolsetConfig{
Name: "neo4j_database_tools",
ToolNames: []string{"execute_cypher", "get_schema"},
},
},
},
{
name: "alloydb postgres observability prebuilt tools",
in: alloydbobsvconfig,
wantToolset: server.ToolsetConfigs{
"alloydb_postgres_cloud_monitoring_tools": tools.ToolsetConfig{
Name: "alloydb_postgres_cloud_monitoring_tools",
ToolNames: []string{"get_system_metrics", "get_query_metrics"},
},
},
},
{
name: "cloudsql postgres observability prebuilt tools",
in: cloudsqlpgobsvconfig,
wantToolset: server.ToolsetConfigs{
"cloud_sql_postgres_cloud_monitoring_tools": tools.ToolsetConfig{
Name: "cloud_sql_postgres_cloud_monitoring_tools",
ToolNames: []string{"get_system_metrics", "get_query_metrics"},
},
},
},
{
name: "cloudsql mysql observability prebuilt tools",
in: cloudsqlmysqlobsvconfig,
wantToolset: server.ToolsetConfigs{
"cloud_sql_mysql_cloud_monitoring_tools": tools.ToolsetConfig{
Name: "cloud_sql_mysql_cloud_monitoring_tools",
ToolNames: []string{"get_system_metrics", "get_query_metrics"},
},
},
},
{
name: "cloudsql mssql observability prebuilt tools",
in: cloudsqlmssqlobsvconfig,
wantToolset: server.ToolsetConfigs{
"cloud_sql_mssql_cloud_monitoring_tools": tools.ToolsetConfig{
Name: "cloud_sql_mssql_cloud_monitoring_tools",
ToolNames: []string{"get_system_metrics"},
},
},
},
{
name: "cloud healthcare prebuilt tools",
in: cloudhealthcare_config,
wantToolset: server.ToolsetConfigs{
"cloud_healthcare_dataset_tools": tools.ToolsetConfig{
Name: "cloud_healthcare_dataset_tools",
ToolNames: []string{"get_dataset", "list_dicom_stores", "list_fhir_stores"},
},
"cloud_healthcare_fhir_tools": tools.ToolsetConfig{
Name: "cloud_healthcare_fhir_tools",
ToolNames: []string{"get_fhir_store", "get_fhir_store_metrics", "get_fhir_resource", "fhir_patient_search", "fhir_patient_everything", "fhir_fetch_page"},
},
"cloud_healthcare_dicom_tools": tools.ToolsetConfig{
Name: "cloud_healthcare_dicom_tools",
ToolNames: []string{"get_dicom_store", "get_dicom_store_metrics", "search_dicom_studies", "search_dicom_series", "search_dicom_instances", "retrieve_rendered_dicom_instance"},
},
},
},
{
name: "Snowflake prebuilt tool",
in: snowflake_config,
wantToolset: server.ToolsetConfigs{
"snowflake_tools": tools.ToolsetConfig{
Name: "snowflake_tools",
ToolNames: []string{"execute_sql", "list_tables"},
},
},
},
{
name: "Oracle prebuilt tool",
in: oracle_config,
wantToolset: server.ToolsetConfigs{
"oracle_tools": tools.ToolsetConfig{
Name: "oracle_tools",
ToolNames: []string{"execute_sql", "list_tables","list_active_sessions","list_top_sql_by_resource","get_query_plan","list_tablespace_usage"},
},
},
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
toolsFile, err := parseToolsFile(ctx, tc.in)
if err != nil {
t.Fatalf("failed to parse input: %v", err)
}
if diff := cmp.Diff(tc.wantToolset, toolsFile.Toolsets); diff != "" {
t.Fatalf("incorrect tools parse: diff %v", diff)
}
// Prebuilt configs do not have prompts, so assert empty maps.
if len(toolsFile.Prompts) != 0 {
t.Fatalf("expected empty prompts map for prebuilt config, got: %v", toolsFile.Prompts)
}
})
}
}
func TestMutuallyExclusiveFlags(t *testing.T) {
testCases := []struct {
desc string

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 271 KiB

View File

@@ -1,335 +0,0 @@
---
title: "Oracle using MCP"
type: docs
weight: 2
description: >
Connect your IDE to Oracle using Toolbox.
---
[Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is
an open protocol for connecting Large Language Models (LLMs) to data sources
like Oracle. This guide covers how to use [MCP Toolbox for Databases][toolbox]
to expose your developer assistant tools to an Oracle instance:
* [Cursor][cursor]
* [Windsurf][windsurf] (Codium)
* [Visual Studio Code][vscode] (Copilot)
* [Cline][cline] (VS Code extension)
* [Claude desktop][claudedesktop]
* [Claude code][claudecode]
* [Gemini CLI][geminicli]
* [Gemini Code Assist][geminicodeassist]
[toolbox]: https://github.com/googleapis/genai-toolbox
[cursor]: #configure-your-mcp-client
[windsurf]: #configure-your-mcp-client
[vscode]: #configure-your-mcp-client
[cline]: #configure-your-mcp-client
[claudedesktop]: #configure-your-mcp-client
[claudecode]: #configure-your-mcp-client
[geminicli]: #configure-your-mcp-client
[geminicodeassist]: #configure-your-mcp-client
## Set up the database
1. Create or select an Oracle instance.
1. Create or reuse a database user and have the username and password ready.
## Install MCP Toolbox
1. Download the latest version of Toolbox as a binary. Select the [correct
binary](https://github.com/googleapis/genai-toolbox/releases) corresponding
to your OS and CPU architecture. You are required to use Toolbox version
V0.26.0+:
<!-- {x-release-please-start-version} -->
{{< tabpane persist=header >}}
{{< tab header="linux/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.26.0/linux/amd64/toolbox
{{< /tab >}}
{{< tab header="darwin/arm64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.26.0/darwin/arm64/toolbox
{{< /tab >}}
{{< tab header="darwin/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.26.0/darwin/amd64/toolbox
{{< /tab >}}
{{< tab header="windows/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.26.0/windows/amd64/toolbox.exe
{{< /tab >}}
{{< /tabpane >}}
<!-- {x-release-please-end} -->
1. Make the binary executable:
```bash
chmod +x toolbox
```
1. Verify the installation:
```bash
./toolbox --version
```
## Configure your MCP Client
{{< tabpane text=true >}}
{{% tab header="Claude code" lang="en" %}}
1. Install [Claude
Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
1. Create a `.mcp.json` file in your project root if it doesn't exist.
1. Add the following configuration, replace the environment variables with your
values, and save:
```json
{
"mcpServers": {
"oracle": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","oracledb","--stdio"],
"env": {
"ORACLE_HOST": "",
"ORACLE_PORT": "1521",
"ORACLE_SERVICE": "",
"ORACLE_USER": "",
"ORACLE_PASSWORD": "",
"ORACLE_WALLET_LOCATION": "",
"ORACLE_USE_OCI": ""
}
}
}
}
```
1. Restart Claude code to apply the new configuration.
{{% /tab %}}
{{% tab header="Claude desktop" lang="en" %}}
1. Open Claude desktop and navigate to Settings.
1. Under the Developer tab, tap Edit Config to open the configuration file.
1. Add the following configuration, replace the environment variables with your
values, and save:
```json
{
"mcpServers": {
"oracle": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","oracledb","--stdio"],
"env": {
"ORACLE_HOST": "",
"ORACLE_PORT": "1521",
"ORACLE_SERVICE": "",
"ORACLE_USER": "",
"ORACLE_PASSWORD": "",
"ORACLE_WALLET_LOCATION": "",
"ORACLE_USE_OCI": ""
}
}
}
}
```
1. Restart Claude desktop.
1. From the new chat screen, you should see a hammer (MCP) icon appear with the
new MCP server available.
{{% /tab %}}
{{% tab header="Cline" lang="en" %}}
1. Open the Cline extension in VS Code and tap
the **MCP Servers** icon.
1. Tap Configure MCP Servers to open the configuration file.
1. Add the following configuration, replace the environment variables with your
values, and save:
```json
{
"mcpServers": {
"oracle": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","oracledb","--stdio"],
"env": {
"ORACLE_HOST": "",
"ORACLE_PORT": "1521",
"ORACLE_SERVICE": "",
"ORACLE_USER": "",
"ORACLE_PASSWORD": "",
"ORACLE_WALLET_LOCATION": "",
"ORACLE_USE_OCI": ""
}
}
}
}
```
1. You should see a green active status after the server is successfully
connected.
{{% /tab %}}
{{% tab header="Cursor" lang="en" %}}
1. Create a `.cursor` directory in your project root if it doesn't exist.
1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your
values, and save:
```json
{
"mcpServers": {
"oracle": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","oracledb","--stdio"],
"env": {
"ORACLE_HOST": "",
"ORACLE_PORT": "1521",
"ORACLE_SERVICE": "",
"ORACLE_USER": "",
"ORACLE_PASSWORD": "",
"ORACLE_WALLET_LOCATION": "",
"ORACLE_USE_OCI": ""
}
}
}
}
```
1. Cursor and navigate to **Settings > Cursor
Settings > MCP**. You should see a green active status after the server is
successfully connected.
{{% /tab %}}
{{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
1. Open VS Code and
create a `.vscode` directory in your project root if it doesn't exist.
1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your
values, and save:
```json
{
"servers": {
"oracle": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","oracle","--stdio"],
"env": {
"ORACLE_HOST": "",
"ORACLE_PORT": "1521",
"ORACLE_SERVICE": "",
"ORACLE_USER": "",
"ORACLE_PASSWORD": ""
}
}
}
}
```
{{% /tab %}}
{{% tab header="Windsurf" lang="en" %}}
1. Open Windsurf and navigate to the
Cascade assistant.
1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
1. Add the following configuration, replace the environment variables with your
values, and save:
```json
{
"mcpServers": {
"oracle": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","oracledb","--stdio"],
"env": {
"ORACLE_HOST": "",
"ORACLE_PORT": "1521",
"ORACLE_SERVICE": "",
"ORACLE_USER": "",
"ORACLE_PASSWORD": "",
"ORACLE_WALLET": "",
"ORACLE_WALLET_PASSWORD": ""
}
}
}
}
```
{{% /tab %}}
{{% tab header="Gemini CLI" lang="en" %}}
1. Install the Gemini CLI.
1. In your working directory, create a folder named `.gemini`. Within it, create a `settings.json` file.
1. Add the following configuration, replace the environment variables with your values, and then save:
```json
{
"mcpServers": {
"oracle": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","oracledb","--stdio"],
"env": {
"ORACLE_HOST": "",
"ORACLE_PORT": "1521",
"ORACLE_SERVICE": "",
"ORACLE_USER": "",
"ORACLE_PASSWORD": ""
}
}
}
}
```
{{% /tab %}}
{{% tab header="Gemini Code Assist" lang="en" %}}
1. Install the Gemini Code Assist extension in Visual Studio Code.
1. Enable Agent Mode in Gemini Code Assist chat.
1. In your working directory, create a folder named `.gemini`. Within it, create a `settings.json` file.
1. Add the following configuration, replace the environment variables with your values, and then save:
```json
{
"mcpServers": {
"oracle": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","oracledb","--stdio"],
"env": {
"ORACLE_HOST": "",
"ORACLE_PORT": "1521",
"ORACLE_SERVICE": "",
"ORACLE_USER": "",
"ORACLE_PASSWORD": ""
}
}
}
}
```
{{% /tab %}}
{{< /tabpane >}}
## Use Tools
Your AI tool is now connected to Oracle using MCP. Try asking your AI
assistant to list tables, create a table, or define and execute other SQL
statements.
The following tools are available to the LLM:
1. **list_tables**: lists tables and descriptions
1. **execute_sql**: execute any SQL statement
{{< notice note >}}
Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs
will adapt to the tools available, so this shouldn't affect most users.
{{< /notice >}}

View File

@@ -44,6 +44,12 @@ See [Usage Examples](../reference/cli.md#examples).
* **Tools:**
* `execute_sql`: Executes a SQL query.
* `list_tables`: Lists tables in the database.
* `list_active_queries`: Lists ongoing queries.
* `list_available_extensions`: Discover all PostgreSQL extensions available for installation.
* `list_installed_extensions`: List all installed PostgreSQL extensions.
* `long_running_transactions`: Identifies and lists database transactions that exceed a specified time limit.
* `list_locks`: Identifies all locks held by active processes.
* `replication_stats`: Lists each replica's process ID and sync state.
* `list_autovacuum_configurations`: Lists autovacuum configurations in the
database.
* `list_memory_configurations`: Lists memory-related configurations in the
@@ -59,12 +65,16 @@ See [Usage Examples](../reference/cli.md#examples).
* `list_triggers`: Lists triggers in the database.
* `list_indexes`: List available user indexes in a PostgreSQL database.
* `list_sequences`: List sequences in a PostgreSQL database.
* `list_query_stats`: Lists query statistics.
* `get_column_cardinality`: Gets column cardinality.
* `list_table_stats`: Lists table statistics.
* `list_publication_tables`: List publication tables in a PostgreSQL database.
* `list_tablespaces`: Lists tablespaces in the database.
* `list_pg_settings`: List configuration parameters for the PostgreSQL server.
* `list_database_stats`: Lists the key performance and activity statistics for
each database in the AlloyDB instance.
* `list_roles`: Lists all the user-created roles in PostgreSQL database.
* `list_stored_procedure`: Lists stored procedures.
## AlloyDB Postgres Admin
@@ -113,6 +123,12 @@ See [Usage Examples](../reference/cli.md#examples).
* **Tools:**
* `execute_sql`: Executes a SQL query.
* `list_tables`: Lists tables in the database.
* `list_active_queries`: Lists ongoing queries.
* `list_available_extensions`: Discover all PostgreSQL extensions available for installation.
* `list_installed_extensions`: List all installed PostgreSQL extensions.
* `long_running_transactions`: Identifies and lists database transactions that exceed a specified time limit.
* `list_locks`: Identifies all locks held by active processes.
* `replication_stats`: Lists each replica's process ID and sync state.
* `list_autovacuum_configurations`: Lists autovacuum configurations in the
database.
* `list_columnar_configurations`: List AlloyDB Omni columnar-related configurations.
@@ -130,12 +146,16 @@ See [Usage Examples](../reference/cli.md#examples).
* `list_triggers`: Lists triggers in the database.
* `list_indexes`: List available user indexes in a PostgreSQL database.
* `list_sequences`: List sequences in a PostgreSQL database.
* `list_query_stats`: Lists query statistics.
* `get_column_cardinality`: Gets column cardinality.
* `list_table_stats`: Lists table statistics.
* `list_publication_tables`: List publication tables in a PostgreSQL database.
* `list_tablespaces`: Lists tablespaces in the database.
* `list_pg_settings`: List configuration parameters for the PostgreSQL server.
* `list_database_stats`: Lists the key performance and activity statistics for
each database in the AlloyDB instance.
* `list_roles`: Lists all the user-created roles in PostgreSQL database.
* `list_stored_procedure`: Lists stored procedures.
## BigQuery
@@ -173,6 +193,21 @@ See [Usage Examples](../reference/cli.md#examples).
* `list_table_ids`: Lists tables.
* `search_catalog`: Search for entries based on the provided query.
## ClickHouse
* `--prebuilt` value: `clickhouse`
* **Environment Variables:**
* `CLICKHOUSE_HOST`: The hostname or IP address of the ClickHouse server.
* `CLICKHOUSE_PORT`: The port number of the ClickHouse server.
* `CLICKHOUSE_USER`: The database username.
* `CLICKHOUSE_PASSWORD`: The password for the database user.
* `CLICKHOUSE_DATABASE`: The name of the database to connect to.
* `CLICKHOUSE_PROTOCOL`: The protocol to use (e.g., http).
* **Tools:**
* `execute_sql`: Use this tool to execute SQL.
* `list_databases`: Use this tool to list all databases in ClickHouse.
* `list_tables`: Use this tool to list all tables in a specific ClickHouse database.
## Cloud SQL for MySQL
* `--prebuilt` value: `cloud-sql-mysql`
@@ -270,6 +305,12 @@ See [Usage Examples](../reference/cli.md#examples).
* **Tools:**
* `execute_sql`: Executes a SQL query.
* `list_tables`: Lists tables in the database.
* `list_active_queries`: Lists ongoing queries.
* `list_available_extensions`: Discover all PostgreSQL extensions available for installation.
* `list_installed_extensions`: List all installed PostgreSQL extensions.
* `long_running_transactions`: Identifies and lists database transactions that exceed a specified time limit.
* `list_locks`: Identifies all locks held by active processes.
* `replication_stats`: Lists each replica's process ID and sync state.
* `list_autovacuum_configurations`: Lists autovacuum configurations in the
database.
* `list_memory_configurations`: Lists memory-related configurations in the
@@ -285,12 +326,16 @@ See [Usage Examples](../reference/cli.md#examples).
* `list_triggers`: Lists triggers in the database.
* `list_indexes`: List available user indexes in a PostgreSQL database.
* `list_sequences`: List sequences in a PostgreSQL database.
* `list_query_stats`: Lists query statistics.
* `get_column_cardinality`: Gets column cardinality.
* `list_table_stats`: Lists table statistics.
* `list_publication_tables`: List publication tables in a PostgreSQL database.
* `list_tablespaces`: Lists tablespaces in the database.
* `list_pg_settings`: List configuration parameters for the PostgreSQL server.
* `list_database_stats`: Lists the key performance and activity statistics for
each database in the postgreSQL instance.
* `list_roles`: Lists all the user-created roles in PostgreSQL database.
* `list_stored_procedure`: Lists stored procedures.
## Cloud SQL for PostgreSQL Observability
@@ -336,6 +381,7 @@ See [Usage Examples](../reference/cli.md#examples).
* `create_user`: Creates a new user in a Cloud SQL instance.
* `wait_for_operation`: Waits for a Cloud SQL operation to complete.
* `clone_instance`: Creates a clone for an existing Cloud SQL for PostgreSQL instance.
* `postgres_upgrade_precheck`: Performs a precheck for a major version upgrade of a Cloud SQL for PostgreSQL instance.
* `create_backup`: Creates a backup on a Cloud SQL instance.
* `restore_backup`: Restores a backup of a Cloud SQL instance.
@@ -420,6 +466,15 @@ See [Usage Examples](../reference/cli.md#examples).
* `search_aspect_types`: Finds aspect types relevant to the
query.
## Elasticsearch
* `--prebuilt` value: `elasticsearch`
* **Environment Variables:**
* `ELASTICSEARCH_HOST`: The hostname or IP address of the Elasticsearch server.
* `ELASTICSEARCH_APIKEY`: The API key for authentication.
* **Tools:**
* `execute_esql_query`: Use this tool to execute ES|QL queries.
## Firestore
* `--prebuilt` value: `firestore`
@@ -537,6 +592,19 @@ See [Usage Examples](../reference/cli.md#examples).
* `execute_sql`: Executes a SQL query.
* `list_tables`: Lists tables in the database.
## MindsDB
* `--prebuilt` value: `mindsdb`
* **Environment Variables:**
* `MINDSDB_HOST`: The hostname or IP address of the MindsDB server.
* `MINDSDB_PORT`: The port number of the MindsDB server.
* `MINDSDB_DATABASE`: The name of the database to connect to.
* `MINDSDB_USER`: The database username.
* `MINDSDB_PASS`: The password for the database user.
* **Tools:**
* `mindsdb-execute-sql`: Execute SQL queries directly on MindsDB database.
* `mindsdb-sql`: Execute parameterized SQL queries on MindsDB database.
## MySQL
* `--prebuilt` value: `mysql`
@@ -592,6 +660,12 @@ See [Usage Examples](../reference/cli.md#examples).
* **Tools:**
* `execute_sql`: Executes a SQL query.
* `list_tables`: Lists tables in the database.
* `list_active_queries`: Lists ongoing queries.
* `list_available_extensions`: Discover all PostgreSQL extensions available for installation.
* `list_installed_extensions`: List all installed PostgreSQL extensions.
* `long_running_transactions`: Identifies and lists database transactions that exceed a specified time limit.
* `list_locks`: Identifies all locks held by active processes.
* `replication_stats`: Lists each replica's process ID and sync state.
* `list_autovacuum_configurations`: Lists autovacuum configurations in the
database.
* `list_memory_configurations`: Lists memory-related configurations in the
@@ -607,12 +681,16 @@ See [Usage Examples](../reference/cli.md#examples).
* `list_triggers`: Lists triggers in the database.
* `list_indexes`: List available user indexes in a PostgreSQL database.
* `list_sequences`: List sequences in a PostgreSQL database.
* `list_query_stats`: Lists query statistics.
* `get_column_cardinality`: Gets column cardinality.
* `list_table_stats`: Lists table statistics.
* `list_publication_tables`: List publication tables in a PostgreSQL database.
* `list_tablespaces`: Lists tablespaces in the database.
* `list_pg_settings`: List configuration parameters for the PostgreSQL server.
* `list_database_stats`: Lists the key performance and activity statistics for
each database in the PostgreSQL server.
* `list_roles`: Lists all the user-created roles in PostgreSQL database.
* `list_stored_procedure`: Lists stored procedures.
## Google Cloud Serverless for Apache Spark
@@ -627,6 +705,38 @@ See [Usage Examples](../reference/cli.md#examples).
view serverless batches.
* **Tools:**
* `list_batches`: Lists Spark batches.
* `get_batch`: Gets information about a Spark batch.
* `cancel_batch`: Cancels a Spark batch.
* `create_pyspark_batch`: Creates a PySpark batch.
* `create_spark_batch`: Creates a Spark batch.
## SingleStore
* `--prebuilt` value: `singlestore`
* **Environment Variables:**
* `SINGLESTORE_HOST`: The hostname or IP address of the SingleStore server.
* `SINGLESTORE_PORT`: The port number of the SingleStore server.
* `SINGLESTORE_DATABASE`: The name of the database to connect to.
* `SINGLESTORE_USER`: The database username.
* `SINGLESTORE_PASSWORD`: The password for the database user.
* **Tools:**
* `execute_sql`: Use this tool to execute SQL.
* `list_tables`: Lists detailed schema information for user-created tables.
## Snowflake
* `--prebuilt` value: `snowflake`
* **Environment Variables:**
* `SNOWFLAKE_ACCOUNT`: The Snowflake account.
* `SNOWFLAKE_USER`: The database username.
* `SNOWFLAKE_PASSWORD`: The password for the database user.
* `SNOWFLAKE_DATABASE`: The name of the database to connect to.
* `SNOWFLAKE_SCHEMA`: The schema name.
* `SNOWFLAKE_WAREHOUSE`: The warehouse name.
* `SNOWFLAKE_ROLE`: The role name.
* **Tools:**
* `execute_sql`: Use this tool to execute SQL.
* `list_tables`: Lists detailed schema information for user-created tables.
## Spanner (GoogleSQL dialect)
@@ -692,34 +802,6 @@ See [Usage Examples](../reference/cli.md#examples).
* `execute_cypher`: Executes a Cypher query.
* `get_schema`: Retrieves the schema of the Neo4j database.
## Oracle
* `--prebuilt` value: `oracle`
* **Environment Variables:**
* `ORACLE_HOST`: The hostname or IP address of the Oracle server.
* `ORACLE_PORT`: The port number for the Oracle server (Default: 1521).
* `ORACLE_CONNECTION_STRING`: The
* `ORACLE_USER`: The username for the Oracle DB instance.
* `ORACLE_PASSWORD`: The password for the Oracle DB instance
* `ORACLE_WALLET`: The path to Oracle DB Wallet file for the databases that support this authentication type
* `ORACLE_USE_OCI`: true or false, The flag if the Oracle Database is deployed in cloud deployment. Default is false.
* **Permissions:**
* Database-level permissions (e.g., `SELECT`, `INSERT`) are required to execute queries.
* **Tools:**
* `execute_sql`: Executes a SQL query.
* `list_tables`: Lists tables in the database.
* `list_active_sessions`: Lists active database sessions.
* `get_query_plan`: Gets the execution plan for a SQL statement.
* `list_top_sql_by_resource`: Lists top SQL statements by resource usage.
* `list_tablespace_usage`: Lists tablespace usage.
* `list_invalid_objects`: Lists invalid objects.
* `list_active_sessions`: Lists active database sessions.
* `get_query_plan`: Gets the execution plan for a SQL statement.
* `list_top_sql_by_resource`: Lists top SQL statements by resource usage.
* `list_tablespace_usage`: Lists tablespace usage.
* `list_invalid_objects`: Lists invalid objects.
## Google Cloud Healthcare API
* `--prebuilt` value: `cloud-healthcare`
* **Environment Variables:**

View File

@@ -87,41 +87,28 @@ using a TNS (Transparent Network Substrate) alias.
## Examples
### 1. Basic Connection (Host, Port, and Service Name)
This example demonstrates the four connection methods you could choose from:
```yaml
sources:
my-oracle-source:
kind: oracle
host: 127.0.0.1
port: 1521
serviceName: XEPDB1
user: ${USER_NAME}
password: ${PASSWORD}
```
kind: sources
name: my-oracle-source
type: oracle
### 2. Direct Connection String
# --- Choose one connection method ---
# 1. Host, Port, and Service Name
host: 127.0.0.1
port: 1521
serviceName: XEPDB1
```yaml
sources:
my-oracle-source:
kind: oracle
connectionString: "127.0.0.1:1521/XEPDB1"
user: ${USER_NAME}
password: ${PASSWORD}
```
# 2. Direct Connection String
connectionString: "127.0.0.1:1521/XEPDB1"
### 3. TNS Alias (requires tnsnames.ora)
# 3. TNS Alias (requires tnsnames.ora)
tnsAlias: "MY_DB_ALIAS"
tnsAdmin: "/opt/oracle/network/admin" # Optional: overrides TNS_ADMIN env var
```yaml
sources:
my-oracle-source:
kind: oracle
tnsAlias: "MY_DB_ALIAS"
tnsAdmin: "/opt/oracle/network/admin" # Optional: overrides TNS_ADMIN env var
user: ${USER_NAME}
password: ${PASSWORD}
useOCI: true # tnsAlias requires useOCI to be true
user: ${USER_NAME}
password: ${PASSWORD}
# Optional: Set to true to use the OCI-based driver for advanced features (Requires Oracle Instant Client)
```
@@ -181,4 +168,3 @@ instead of hardcoding your secrets into the configuration file.
| tnsAlias | string | false | A TNS alias from a `tnsnames.ora` file. Use as an alternative to `host`/`port` or `connectionString`. |
| tnsAdmin | string | false | Path to the directory containing the `tnsnames.ora` file. This overrides the `TNS_ADMIN` environment variable if it is set. |
| useOCI | bool | false | If true, uses the OCI-based driver (godror) which supports Oracle Wallet/Kerberos but requires the Oracle Instant Client libraries to be installed. Defaults to false (pure Go driver). |
| walletLocation | string | false | Path to the directory containing the wallet files for the pure Go driver (`useOCI: false`). |

View File

@@ -1,7 +0,0 @@
---
title: "OracleDB"
type: docs
weight: 1
description: >
How to get started with Toolbox using Oracle Database.
---

View File

@@ -47,7 +47,6 @@ var expectedToolSources = []string{
"mysql",
"neo4j",
"oceanbase",
"oracledb",
"postgres",
"serverless-spark",
"singlestore",
@@ -132,8 +131,6 @@ func TestGetPrebuiltTool(t *testing.T) {
neo4jconfig := getOrFatal(t, "neo4j")
healthcare_config := getOrFatal(t, "cloud-healthcare")
snowflake_config := getOrFatal(t, "snowflake")
oracle_config := getOrFatal(t,"oracledb")
if len(alloydb_omni_config) <= 0 {
t.Fatalf("unexpected error: could not fetch alloydb omni prebuilt tools yaml")
}
@@ -233,10 +230,6 @@ func TestGetPrebuiltTool(t *testing.T) {
if len(snowflake_config) <= 0 {
t.Fatalf("unexpected error: could not fetch snowflake prebuilt tools yaml")
}
if len(oracle_config) <= 0 {
t.Fatalf("unexpected error: could not fetch oracle prebuilt tools yaml")
}
}
func TestFailGetPrebuiltTool(t *testing.T) {

View File

@@ -1,121 +0,0 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
sources:
oracle-source:
kind: "oracle"
connectionString: ${ORACLE_CONNECTION_STRING}
walletLocation: ${ORACLE_WALLET:}
user: ${ORACLE_USER}
password: ${ORACLE_PASSWORD}
useOCI: ${ORACLE_USE_OCI:false}
tools:
list_tables:
kind: oracle-sql
source: oracle-source
description: "Lists all user tables in the connected schema, including segment size, row count, and last analyzed date. Filters by a comma-separated list of names. If names are omitted, lists all tables in the current user's schema."
statement: SELECT table_name from user_tables;
list_active_sessions:
kind: oracle-sql
source: oracle-source
description: "List the top N (default 50) currently running database sessions (STATUS='ACTIVE'), showing SID, OS User, Program, and the current SQL statement text."
statement: SELECT
s.sid,
s.serial#,
s.username,
s.osuser,
s.program,
s.status,
s.wait_class,
s.event,
sql.sql_text
FROM
v$session s,
v$sql sql
WHERE
s.status = 'ACTIVE'
AND s.sql_id = sql.sql_id (+)
AND s.audsid != userenv('sessionid') -- Exclude current session
ORDER BY s.last_call_et DESC
FETCH FIRST COALESCE(10) ROWS ONLY;
get_query_plan:
kind: oracle-sql
source: oracle-source
description: "Generate a full execution plan for a single SQL statement. This can be used to analyze query performance without execution. Requires the SQL statement as input. following is an example EXPLAIN PLAN FOR {{&query}};"
statement: SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
list_top_sql_by_resource:
kind: oracle-sql
source: oracle-source
description: "List the top N SQL statements from the library cache based on a chosen resource metric (CPU, I/O, or Elapsed Time), following is an example of the sql"
statement: SELECT
sql_id,
executions,
buffer_gets,
disk_reads,
cpu_time / 1000000 AS cpu_seconds,
elapsed_time / 1000000 AS elapsed_seconds
FROM
v$sql
FETCH FIRST 5 ROWS ONLY;
list_tablespace_usage:
kind: oracle-sql
source: oracle-source
description: "List tablespace names, total size, free space, and used percentage to monitor storage utilization."
statement: SELECT
t.tablespace_name,
TO_CHAR(t.total_bytes / 1024 / 1024, '99,999.00') AS total_mb,
TO_CHAR(SUM(d.bytes) / 1024 / 1024, '99,999.00') AS free_mb,
TO_CHAR((t.total_bytes - SUM(d.bytes)) / t.total_bytes * 100, '99.00') AS used_pct
FROM
(SELECT tablespace_name, SUM(bytes) AS total_bytes FROM dba_data_files GROUP BY tablespace_name) t,
dba_free_space d
WHERE
t.tablespace_name = d.tablespace_name (+)
GROUP BY
t.tablespace_name, t.total_bytes
ORDER BY
used_pct DESC;
list_invalid_objects:
kind: oracle-sql
source: oracle-source
description: "Lists all database objects that are in an invalid state, requiring recompilation (e.g., procedures, functions, views)."
statement: SELECT
owner,
object_type,
object_name,
status
FROM
dba_objects
WHERE
status = 'INVALID'
AND owner NOT IN ('SYS', 'SYSTEM') -- Exclude system schemas for clarity
ORDER BY
owner, object_type, object_name;
toolsets:
oracle_database_tools:
- execute_sql
- list_tables
- list_active_sessions
- get_query_plan
- list_top_sql_by_resource
- list_tablespace_usage
- list_invalid_objects

View File

@@ -1,5 +1,4 @@
// Copyright © 2025, Oracle and/or its affiliates.
package oracle
import (

View File

@@ -190,4 +190,4 @@ func TestFailParseFromYaml(t *testing.T) {
}
})
}
}
}

View File

@@ -36,15 +36,17 @@ var (
AlloyDBDatabase = "postgres"
)
// Copied over from postgres.go
func initPostgresConnectionPool(host, port, user, pass, dbname string) (*pgxpool.Pool, error) {
// urlExample := "postgres:dd//username:password@localhost:5432/database_name"
url := &url.URL{
func buildPostgresURL(host, port, user, pass, dbname string) *url.URL {
return &url.URL{
Scheme: "postgres",
User: url.UserPassword(user, pass),
Host: fmt.Sprintf("%s:%s", host, port),
Path: dbname,
}
}
func initPostgresConnectionPool(host, port, user, pass, dbname string) (*pgxpool.Pool, error) {
url := buildPostgresURL(host, port, user, pass, dbname)
pool, err := pgxpool.New(context.Background(), url.String())
if err != nil {
return nil, fmt.Errorf("Unable to create connection pool: %w", err)
@@ -63,7 +65,8 @@ func setupAlloyDBContainer(ctx context.Context, t *testing.T) (string, string, f
"POSTGRES_PASSWORD": AlloyDBPass,
},
WaitingFor: wait.ForAll(
wait.ForLog("Post Startup: Successfully reinstalled extensions"),
wait.ForLog("database system was shut down at"),
wait.ForLog("database system is ready to accept connections"),
wait.ForExposedPort(),
),
}

View File

@@ -9,31 +9,23 @@ import (
"os"
"regexp"
"strings"
"strconv"
"testing"
"time"
"github.com/google/uuid"
"github.com/googleapis/genai-toolbox/internal/sources/oracle"
"github.com/googleapis/genai-toolbox/internal/testutils"
"github.com/googleapis/genai-toolbox/tests"
)
var (
OracleSourceType = "oracle"
OracleToolType = "oracle-sql"
OracleHost = os.Getenv("ORACLE_HOST")
OraclePort = os.Getenv("ORACLE_PORT")
OracleUser = os.Getenv("ORACLE_USER")
OraclePass = os.Getenv("ORACLE_PASS")
OracleServerName = os.Getenv("ORACLE_SERVER_NAME")
OracleUseOCI = os.Getenv("ORACLE_USE_OCI")
OracleWalletLocation = os.Getenv("ORACLE_WALLET_LOCATION")
OracleTnsAdmin = os.Getenv("ORACLE_TNS_ADMIN")
OracleConnStr = fmt.Sprintf(
"%s:%s/%s", OracleHost, "1521", OracleServerName) // Default port 1521??
"%s:%s/%s", OracleHost, "1521", OracleServerName)
)
func getOracleVars(t *testing.T) map[string]any {
@@ -51,77 +43,12 @@ func getOracleVars(t *testing.T) map[string]any {
return map[string]any{
"type": OracleSourceType,
"connectionString": OracleConnStr,
"useOCI": OracleUseOCI,
"walletLocation": OracleWalletLocation,
"tnsAdmin": OracleTnsAdmin,
"host": OracleHost,
"port": OraclePort,
"service": OracleServerName,
"useOCI": true,
"user": OracleUser,
"password": OraclePass,
}
}
// getOracleConfigFromEnv constructs an oracle.Config from environment variables.
func getOracleConfigFromEnv(t *testing.T) oracle.Config {
t.Helper()
vars := getOracleVars(t)
port, err := strconv.Atoi(vars["port"].(string))
if err != nil && vars["port"].(string) != "" {
t.Fatalf("invalid ORACLE_PORT: %v", err)
}
useOCI, err := strconv.ParseBool(vars["useOCI"].(string))
if err != nil && vars["useOCI"].(string) != "" {
useOCI = false
}
return oracle.Config{
Name: "test-oracle-instance",
Kind: vars["type"].(string),
User: vars["user"].(string),
Password: vars["password"].(string),
Host: vars["host"].(string),
Port: port,
ServiceName: vars["service"].(string),
WalletLocation: vars["walletLocation"].(string),
TnsAdmin: vars["tnsAdmin"].(string),
UseOCI: useOCI,
}
}
// setOracleEnv sets Oracle-related environment variables for testing and returns a cleanup function.
func setOracleEnv(t *testing.T, host, user, password, service, port, connStr, tnsAlias, tnsAdmin, walletLocation string, useOCI bool) func() {
t.Helper()
original := map[string]string{
"ORACLE_HOST": os.Getenv("ORACLE_HOST"),
"ORACLE_USER": os.Getenv("ORACLE_USER"),
"ORACLE_PASSWORD": os.Getenv("ORACLE_PASSWORD"),
"ORACLE_SERVICE": os.Getenv("ORACLE_SERVICE"),
"ORACLE_PORT": os.Getenv("ORACLE_PORT"),
"ORACLE_TNS_ADMIN": os.Getenv("ORACLE_TNS_ADMIN"),
"ORACLE_WALLET_LOCATION": os.Getenv("ORACLE_WALLET_LOCATION"),
"ORACLE_USE_OCI": os.Getenv("ORACLE_USE_OCI"),
}
os.Setenv("ORACLE_HOST", host)
os.Setenv("ORACLE_USER", user)
os.Setenv("ORACLE_PASSWORD", password)
os.Setenv("ORACLE_SERVICE", service)
os.Setenv("ORACLE_PORT", port)
os.Setenv("ORACLE_TNS_ADMIN", tnsAdmin)
os.Setenv("ORACLE_WALLET_LOCATION", walletLocation)
os.Setenv("ORACLE_USE_OCI", fmt.Sprintf("%v", useOCI))
return func() {
for k, v := range original {
os.Setenv(k, v)
}
}
}
// Copied over from oracle.go
func initOracleConnection(ctx context.Context, user, pass, connStr string) (*sql.DB, error) {
// Build the full Oracle connection string for godror driver
@@ -141,9 +68,7 @@ func initOracleConnection(ctx context.Context, user, pass, connStr string) (*sql
return db, nil
}
// TestOracleSimpleToolEndpoints tests Oracle SQL tool endpoints
func TestOracleSimpleToolEndpoints(t *testing.T) {
sourceConfig := getOracleVars(t)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
@@ -210,130 +135,6 @@ func TestOracleSimpleToolEndpoints(t *testing.T) {
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam)
}
// TestOracleConnectionPureGoWithWallet tests pure Go driver connection with wallet
func TestOracleConnectionPureGoWithWallet(t *testing.T) {
t.Parallel()
// This test expects the connection to fail because the wallet file won't exist.
// It verifies that the walletLocation parameter is correctly passed to the pure Go driver.
// Save original env vars and restore them at the end
cleanup := setOracleEnv(t,
OracleHost, OracleUser, OraclePass, OracleServerName, OraclePort, // Use existing base connection details
"", // connectionString
"", // tnsAlias
"", // tnsAdmin
"/tmp/nonexistent_wallet", // walletLocation
false, // useOCI
)
defer cleanup()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cfg := getOracleConfigFromEnv(t)
_, err := cfg.Initialize(ctx, nil) // Pass nil for tracer as it's not critical for this test
if err == nil {
t.Fatalf("Expected connection to fail with non-existent wallet, but it succeeded")
}
// Check for error message indicating wallet usage or connection failure related to wallet
// The exact error message might vary depending on the go-ora version and OS.
// We are looking for an error that suggests the wallet path was attempted.
expectedErrorSubstring := "wallet"
if !strings.Contains(strings.ToLower(err.Error()), expectedErrorSubstring) {
t.Errorf("Expected error message to contain '%s' (case-insensitive) but got: %v", expectedErrorSubstring, err)
}
t.Logf("Connection failed as expected (Pure Go with Wallet): %v", err)
}
// TestOracleConnectionOCI tests OCI driver connection without wallet
func TestOracleConnectionOCI(t *testing.T) {
t.Parallel()
// This test verifies that the useOCI=true parameter is correctly passed to the OCI driver.
// It will likely fail if Oracle Instant Client is not installed or configured.
// Save original env vars and restore them at the end
cleanup := setOracleEnv(t,
OracleHost, OracleUser, OraclePass, OracleServerName, OraclePort, // Use existing base connection details
"", // connectionString
"", // tnsAlias
"", // tnsAdmin
"", // walletLocation
true, // useOCI
)
defer cleanup()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cfg := getOracleConfigFromEnv(t)
_, err := cfg.Initialize(ctx, nil)
if err == nil {
t.Fatalf("Expected connection to fail (OCI driver without Instant Client), but it succeeded")
}
// Check for error message indicating OCI driver usage or connection failure related to OCI.
// Common errors include "OCI environment not initialized", "driver: bad connection", etc.
expectedErrorSubstrings := []string{"oci", "driver", "connection"}
foundExpectedError := false
for _, sub := range expectedErrorSubstrings {
if strings.Contains(strings.ToLower(err.Error()), sub) {
foundExpectedError = true
break
}
}
if !foundExpectedError {
t.Errorf("Expected error message to contain one of %v (case-insensitive) but got: %v", expectedErrorSubstrings, err)
}
t.Logf("Connection failed as expected (OCI Driver): %v", err)
}
// TestOracleConnectionOCIWithWallet tests OCI driver connection with TNS Admin and Wallet
func TestOracleConnectionOCIWithWallet(t *testing.T) {
t.Parallel()
// This test verifies that useOCI=true and tnsAdmin parameters are correctly passed for OCI wallet.
// It will likely fail due to missing tnsnames.ora and wallet files.
// Save original env vars and restore them at the end
cleanup := setOracleEnv(t,
"", OracleUser, OraclePass, "", "", // Unset host/port/service for TNS alias, but keep user/pass
"", // connectionString
"MY_TNS_ALIAS", // tnsAlias
"/tmp/nonexistent_tns_admin", // tnsAdmin
"", // walletLocation
true, // useOCI
)
defer cleanup()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cfg := getOracleConfigFromEnv(t)
_, err := cfg.Initialize(ctx, nil)
if err == nil {
t.Fatalf("Expected connection to fail (OCI driver with TNS Admin/Wallet), but it succeeded")
}
// Check for error message indicating TNS Admin/Wallet usage or connection failure.
expectedErrorSubstrings := []string{"tns", "wallet", "oci", "driver", "connection"}
foundExpectedError := false
for _, sub := range expectedErrorSubstrings {
if strings.Contains(strings.ToLower(err.Error()), sub) {
foundExpectedError = true
break
}
}
if !foundExpectedError {
t.Errorf("Expected error message to contain one of %v (case-insensitive) but got: %v", expectedErrorSubstrings, err)
}
t.Logf("Connection failed as expected (OCI Driver with TNS Admin/Wallet): %v", err)
}
//test utils
func setupOracleTable(t *testing.T, ctx context.Context, pool *sql.DB, createStatement, insertStatement, tableName string, params []any) func(*testing.T) {
err := pool.PingContext(ctx)
if err != nil {
@@ -440,4 +241,4 @@ func dropAllUserTables(t *testing.T, ctx context.Context, db *sql.DB) {
t.Logf("failed to drop table %s: %v", tableName, err)
}
}
}
}

View File

@@ -1,248 +0,0 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package oracle_test
import (
"strings"
"testing"
yaml "github.com/goccy/go-yaml"
"github.com/google/go-cmp/cmp"
"github.com/googleapis/genai-toolbox/internal/server"
"github.com/googleapis/genai-toolbox/internal/sources/oracle"
"github.com/googleapis/genai-toolbox/internal/testutils"
)
func TestParseFromYamlOracle(t *testing.T) {
tcs := []struct {
desc string
in string
want server.SourceConfigs
}{
{
desc: "connection string and useOCI=true",
in: `
sources:
my-oracle-cs:
kind: oracle
connectionString: "my-host:1521/XEPDB1"
user: my_user
password: my_pass
useOCI: true
`,
want: server.SourceConfigs{
"my-oracle-cs": oracle.Config{
Name: "my-oracle-cs",
Kind: oracle.SourceKind,
ConnectionString: "my-host:1521/XEPDB1",
User: "my_user",
Password: "my_pass",
UseOCI: true,
},
},
},
{
desc: "host/port/serviceName and default useOCI=false",
in: `
sources:
my-oracle-host:
kind: oracle
host: my-host
port: 1521
serviceName: ORCLPDB
user: my_user
password: my_pass
`,
want: server.SourceConfigs{
"my-oracle-host": oracle.Config{
Name: "my-oracle-host",
Kind: oracle.SourceKind,
Host: "my-host",
Port: 1521,
ServiceName: "ORCLPDB",
User: "my_user",
Password: "my_pass",
UseOCI: false,
},
},
},
{
desc: "tnsAlias and TnsAdmin specified with explicit useOCI=true",
in: `
sources:
my-oracle-tns-oci:
kind: oracle
tnsAlias: FINANCE_DB
tnsAdmin: /opt/oracle/network/admin
user: my_user
password: my_pass
useOCI: true
`,
want: server.SourceConfigs{
"my-oracle-tns-oci": oracle.Config{
Name: "my-oracle-tns-oci",
Kind: oracle.SourceKind,
TnsAlias: "FINANCE_DB",
TnsAdmin: "/opt/oracle/network/admin",
User: "my_user",
Password: "my_pass",
UseOCI: true,
},
},
},
{
desc: "connection string and walletLocation",
in: `
sources:
my-oracle-wallet:
kind: oracle
connectionString: "my-host:1521/XEPDB1"
user: my_user
password: my_pass
walletLocation: "/path/to/wallet"
`,
want: server.SourceConfigs{
"my-oracle-wallet": oracle.Config{
Name: "my-oracle-wallet",
Kind: oracle.SourceKind,
ConnectionString: "my-host:1521/XEPDB1",
User: "my_user",
Password: "my_pass",
WalletLocation: "/path/to/wallet",
},
},
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
got := struct {
Sources server.SourceConfigs `yaml:"sources"`
}{}
err := yaml.Unmarshal(testutils.FormatYaml(tc.in), &got)
if err != nil {
t.Fatalf("unable to unmarshal: %s", err)
}
if !cmp.Equal(tc.want, got.Sources) {
t.Fatalf("incorrect parse:\nwant: %v\ngot: %v\ndiff: %s", tc.want, got.Sources, cmp.Diff(tc.want, got.Sources))
}
})
}
}
func TestFailParseFromYamlOracle(t *testing.T) {
tcs := []struct {
desc string
in string
err string
}{
{
desc: "extra field",
in: `
sources:
my-oracle-instance:
kind: oracle
host: my-host
serviceName: ORCL
user: my_user
password: my_pass
extraField: value
`,
err: "unable to parse source \"my-oracle-instance\" as \"oracle\": [1:1] unknown field \"extraField\"\n> 1 | extraField: value\n ^\n 2 | host: my-host\n 3 | kind: oracle\n 4 | password: my_pass\n 5 | ",
},
{
desc: "missing required password field",
in: `
sources:
my-oracle-instance:
kind: oracle
host: my-host
serviceName: ORCL
user: my_user
`,
err: "unable to parse source \"my-oracle-instance\" as \"oracle\": Key: 'Config.Password' Error:Field validation for 'Password' failed on the 'required' tag",
},
{
desc: "missing connection method fields (validate fails)",
in: `
sources:
my-oracle-instance:
kind: oracle
user: my_user
password: my_pass
`,
err: "unable to parse source \"my-oracle-instance\" as \"oracle\": invalid Oracle configuration: must provide one of: 'tns_alias', 'connection_string', or both 'host' and 'service_name'",
},
{
desc: "multiple connection methods provided (validate fails)",
in: `
sources:
my-oracle-instance:
kind: oracle
host: my-host
serviceName: ORCL
connectionString: "my-host:1521/XEPDB1"
user: my_user
password: my_pass
`,
err: "unable to parse source \"my-oracle-instance\" as \"oracle\": invalid Oracle configuration: provide only one connection method: 'tns_alias', 'connection_string', or 'host'+'service_name'",
},
{
desc: "fail on tnsAdmin with useOCI=false",
in: `
sources:
my-oracle-fail:
kind: oracle
tnsAlias: FINANCE_DB
tnsAdmin: /opt/oracle/network/admin
user: my_user
password: my_pass
useOCI: false
`,
err: "unable to parse source \"my-oracle-fail\" as \"oracle\": invalid Oracle configuration: `tnsAdmin` can only be used when `UseOCI` is true, or use `walletLocation` instead",
},
{
desc: "fail on walletLocation with useOCI=true",
in: `
sources:
my-oracle-fail:
kind: oracle
connectionString: "my-host:1521/XEPDB1"
user: my_user
password: my_pass
walletLocation: "/path/to/wallet"
useOCI: true
`,
err: "unable to parse source \"my-oracle-fail\" as \"oracle\": invalid Oracle configuration: when using an OCI driver, use `tnsAdmin` to specify credentials file location instead",
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
got := struct {
Sources server.SourceConfigs `yaml:"sources"`
}{}
err := yaml.Unmarshal(testutils.FormatYaml(tc.in), &got)
if err == nil {
t.Fatalf("expect parsing to fail")
}
errStr := strings.ReplaceAll(err.Error(), "\r", "")
if errStr != tc.err {
t.Fatalf("unexpected error:\ngot:\n%q\nwant:\n%q\n", errStr, tc.err)
}
})
}
}