Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
160865d
Add OBO credential flow integration tests
dhruv0811 Mar 2, 2026
f7ab1ca
Fix: use Config(credentials_strategy=...) for ModelServingUserCredent…
dhruv0811 Mar 2, 2026
a21ad4b
Fix: use credentials_strategy (with 's') — the correct WorkspaceClien…
dhruv0811 Mar 2, 2026
1f189c1
Fix whoami assertions: compare deployer vs end-user SQL results directly
dhruv0811 Mar 2, 2026
1b5a825
Format test file with ruff
dhruv0811 Mar 2, 2026
d6a6208
Fix type checker errors: add None guards for SDK optional types
dhruv0811 Mar 2, 2026
8876ea4
Replace simulated OBO tests with end-to-end agent invocation tests
dhruv0811 Mar 2, 2026
0aafbae
Add databricks-openai to test dependencies for OBO e2e tests
dhruv0811 Mar 2, 2026
d363450
Add app fixture, serving deploy script, and warm-start for OBO e2e tests
dhruv0811 Mar 3, 2026
11609a9
Fix app fixture: add hatch wheel packages config
dhruv0811 Mar 3, 2026
2f6ae09
Add serving agent and deploy script matching working notebook pattern
dhruv0811 Mar 4, 2026
7fc4ca3
Fix lint, format, and core_test failures
dhruv0811 Mar 4, 2026
eefadf0
Fix SP-B identity check: use OBO_TEST_CLIENT_ID directly
dhruv0811 Mar 4, 2026
a4701f7
Move whoami_serving_agent.py into model_serving_fixture/
dhruv0811 Mar 4, 2026
fe4feca
Exclude OBO fixture/deploy files from type checking
dhruv0811 Mar 4, 2026
47bb76b
Inject warehouse ID at deploy time instead of reading env at import
dhruv0811 Mar 4, 2026
363611d
Fix app whoami tool: return user_name (UUID for SPs) for parity with …
dhruv0811 Mar 4, 2026
c3ef9e3
Fix serving deploy: drop endpoint_name, add input_example
dhruv0811 Mar 4, 2026
5d2787c
Fix ruff: remove unused imports (shutil, os)
dhruv0811 Mar 5, 2026
54494aa
Merge remote-tracking branch 'origin/main' into obo-integration-tests
dhruv0811 Mar 5, 2026
cfa0e31
Fix langchain integration test failures
dhruv0811 Mar 5, 2026
304a958
Fix langchain integration test failures
dhruv0811 Mar 5, 2026
0b05cd2
Skip remaining 4 failing tests (streaming usage + mock unit test)
dhruv0811 Mar 5, 2026
9be86fc
Add DBSQL and raw streamable_http_client MCP integration tests
dhruv0811 Mar 6, 2026
de92531
Add Genie raw streamable_http_client integration test
dhruv0811 Mar 6, 2026
4f388de
Refactor raw streamable tests to use pytest.mark.asyncio
dhruv0811 Mar 6, 2026
0833363
Fix langchain integration tests (comprehensive)
dhruv0811 Mar 9, 2026
dcbaad7
Remove RUN_DOGFOOD_TESTS gates — run all tests for evaluation
dhruv0811 Mar 9, 2026
72248ef
Remove RUN_ST_ENDPOINT_TESTS gates — run all tests for evaluation
dhruv0811 Mar 9, 2026
39fac87
Fix langchain integration tests (clean diff from main)
dhruv0811 Mar 9, 2026
3669477
Fix timeout_and_retries unit test: patch get_openai_client directly
dhruv0811 Mar 9, 2026
2663b4c
Revert stream_options, fix remaining issues
dhruv0811 Mar 9, 2026
2c58255
Fix streaming usage tests: find usage chunk instead of assuming last
dhruv0811 Mar 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions databricks_mcp/tests/integration_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,35 @@ def cached_vs_call_result(vs_mcp_client, cached_vs_tools_list):
return vs_mcp_client.call_tool(tool.name, {param_name: "test"})


# =============================================================================
# DBSQL Fixtures
# =============================================================================


@pytest.fixture(scope="session")
def dbsql_mcp_url(workspace_client):
"""Construct MCP URL for the DBSQL server."""
base_url = workspace_client.config.host
return f"{base_url}/api/2.0/mcp/sql"


@pytest.fixture(scope="session")
def dbsql_mcp_client(dbsql_mcp_url, workspace_client):
"""DatabricksMCPClient pointed at the DBSQL server."""
return DatabricksMCPClient(dbsql_mcp_url, workspace_client)


@pytest.fixture(scope="session")
def cached_dbsql_tools_list(dbsql_mcp_client):
"""Cache the DBSQL list_tools() result; skip if DBSQL MCP endpoint unavailable."""
try:
tools = dbsql_mcp_client.list_tools()
except ExceptionGroup as e: # ty: ignore[unresolved-reference]
_skip_if_not_found(e, "DBSQL MCP endpoint not available in workspace")
assert tools, "DBSQL list_tools() returned no tools"
return tools


# =============================================================================
# Genie Fixtures
# =============================================================================
Expand Down
164 changes: 164 additions & 0 deletions databricks_mcp/tests/integration_tests/test_mcp_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,170 @@ def test_call_tool_returns_result_with_content(self, cached_genie_call_result):
assert len(cached_genie_call_result.content) > 0


# =============================================================================
# DBSQL
# =============================================================================


@pytest.mark.integration
class TestMCPClientDBSQL:
"""Verify list_tools() and call_tool() against a live DBSQL MCP server."""

def test_list_tools_returns_expected_tools(self, cached_dbsql_tools_list):
tool_names = [t.name for t in cached_dbsql_tools_list]
for expected in ["execute_sql", "execute_sql_read_only", "poll_sql_result"]:
assert expected in tool_names, f"Expected tool '{expected}' not found in {tool_names}"

def test_call_tool_execute_sql_read_only(self, dbsql_mcp_client, cached_dbsql_tools_list):
"""execute_sql_read_only with SHOW CATALOGS should return results."""
result = dbsql_mcp_client.call_tool("execute_sql_read_only", {"query": "SHOW CATALOGS"})
assert isinstance(result, CallToolResult)
assert result.content, "SHOW CATALOGS should return content"
assert len(result.content) > 0


# =============================================================================
# Raw streamable_http_client
# =============================================================================


@pytest.mark.integration
class TestRawStreamableHttpClient:
"""Verify DatabricksOAuthClientProvider works with the raw MCP SDK streamable_http_client.

This tests the low-level path: httpx.AsyncClient + DatabricksOAuthClientProvider
+ streamable_http_client + ClientSession, without going through DatabricksMCPClient.
"""

@pytest.mark.asyncio
async def test_uc_function_list_and_call(self, uc_function_url, workspace_client):
"""list_tools + call_tool via raw streamable_http_client for UC functions."""
import httpx
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client

from databricks_mcp import DatabricksOAuthClientProvider

async with httpx.AsyncClient(
auth=DatabricksOAuthClientProvider(workspace_client),
follow_redirects=True,
timeout=httpx.Timeout(120.0, read=120.0),
) as http_client:
async with streamable_http_client(uc_function_url, http_client=http_client) as (
read_stream,
write_stream,
_,
):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()

# list_tools
tools_response = await session.list_tools()
tools = tools_response.tools
assert len(tools) > 0
tool_names = [t.name for t in tools]
assert any("echo_message" in name for name in tool_names)

# call_tool
tool_name = next(n for n in tool_names if "echo_message" in n)
result = await session.call_tool(tool_name, {"message": "raw_client_test"})
assert result.content
assert "raw_client_test" in str(result.content[0].text)

@pytest.mark.asyncio
async def test_vs_list_tools(self, vs_mcp_url, workspace_client):
"""list_tools via raw streamable_http_client for Vector Search."""
import httpx
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client

from databricks_mcp import DatabricksOAuthClientProvider

async with httpx.AsyncClient(
auth=DatabricksOAuthClientProvider(workspace_client),
follow_redirects=True,
timeout=httpx.Timeout(120.0, read=120.0),
) as http_client:
async with streamable_http_client(vs_mcp_url, http_client=http_client) as (
read_stream,
write_stream,
_,
):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
tools_response = await session.list_tools()
assert len(tools_response.tools) > 0

@pytest.mark.asyncio
async def test_dbsql_list_and_call(self, dbsql_mcp_url, workspace_client):
"""list_tools + call_tool via raw streamable_http_client for DBSQL."""
import httpx
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client

from databricks_mcp import DatabricksOAuthClientProvider

async with httpx.AsyncClient(
auth=DatabricksOAuthClientProvider(workspace_client),
follow_redirects=True,
timeout=httpx.Timeout(120.0, read=120.0),
) as http_client:
async with streamable_http_client(dbsql_mcp_url, http_client=http_client) as (
read_stream,
write_stream,
_,
):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()

tools_response = await session.list_tools()
tools = tools_response.tools
tool_names = [t.name for t in tools]
assert "execute_sql_read_only" in tool_names

result = await session.call_tool(
"execute_sql_read_only", {"query": "SHOW CATALOGS"}
)
assert result.content
assert len(result.content) > 0

@pytest.mark.asyncio
async def test_genie_list_and_call(self, genie_mcp_url, workspace_client):
"""list_tools + call_tool via raw streamable_http_client for Genie."""
import httpx
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client

from databricks_mcp import DatabricksOAuthClientProvider

async with httpx.AsyncClient(
auth=DatabricksOAuthClientProvider(workspace_client),
follow_redirects=True,
timeout=httpx.Timeout(120.0, read=120.0),
) as http_client:
async with streamable_http_client(genie_mcp_url, http_client=http_client) as (
read_stream,
write_stream,
_,
):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()

tools_response = await session.list_tools()
tools = tools_response.tools
assert len(tools) > 0

# Call the first tool (query_space_*)
tool = tools[0]
properties = tool.inputSchema.get("properties", {})
param_name = next(iter(properties), "query")
result = await session.call_tool(
tool.name, {param_name: "How many rows are there?"}
)
assert result.content
assert len(result.content) > 0


# =============================================================================
# Error paths
# =============================================================================
Expand Down
Loading
Loading