Skip to main content

databricks-isv-testing

How to run and structure auth tests for Databricks ISV integrations: clean env per test, runner script patterns, U2M browser flows, and language-specific considerations.

Informations de source

Dépôt
databricks-solutions/partner-ai-dev-kit
Dernière activité de la source
15 avril 2026 à 00:36
Langue détectée de SKILL.md
anglais
Étoiles
5
Forks
1

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
databricks-isv-testing
description
How to run and structure auth tests for Databricks ISV integrations: clean env per test, runner script patterns, U2M browser flows, and language-specific considerations.
<!-- skill-version: 1.0.0 --> # Testing Auth for ISV Integrations Use this skill when **running or designing tests** for Databricks partner authentication (PAT, OAuth M2M, U2M). ## Core Principle: Clean Environment Per Test **Never run multiple auth types in one process** with mixed environment variables. SDKs and drivers error with "more than one authorization method configured" if conflicting credentials are set. ### Option A: `env -i` (Automated Test Runners) ```bash env -i PATH="$PATH" HOME="$HOME" \ DATABRICKS_HOST="https://myworkspace.cloud.databricks.com" \ DATABRICKS_TOKEN="dapi..." \ python your_pat_example.py ``` **Caveat:** In long interactive sessions, `env -i` may strip needed vars like `PYTHONPATH`. Use Option B for manual testing. ### Option B: Fresh Bash Subshell (Interactive Testing) ```bash /bin/bash -c ' export DATABRICKS_HOST="https://myworkspace.cloud.databricks.com" export DATABRICKS_TOKEN="dapi..." unset DATABRICKS_CLIENT_ID DATABRICKS_CLIENT_SECRET export PYTHONUNBUFFERED=1 python your_pat_example.py ' ``` Starts a completely clean child process. More reliable for interactive manual testing. --- ## Environment Variables by Auth Type | Auth Type | Selector Value | Required Variables | Must NOT Be Set | |-----------|----------------|--------------------|-----------------| | PAT | `pat` | `DATABRICKS_HOST`, `DATABRICKS_TOKEN` | `CLIENT_ID`, `CLIENT_SECRET` | | OAuth M2M | `oauth_m2m` | `DATABRICKS_HOST`, `DATABRICKS_CLIENT_ID`, `DATABRICKS_CLIENT_SECRET` | `DATABRICKS_TOKEN` | | U2M External Browser | `u2m_external_browser` | `DATABRICKS_HOST` | `CLIENT_ID`, `CLIENT_SECRET`, `TOKEN` | | U2M Custom OAuth App | `u2m_custom_oauth_app` | `DATABRICKS_HOST`, `DATABRICKS_U2M_CLIENT_ID` | `DATABRICKS_CLIENT_ID` | | U2M Token-Env | `u2m_token_env` | `DATABRICKS_HOST`, `DATABRICKS_ACCESS_TOKEN` | `CLIENT_ID`, `CLIENT_SECRET` | **Optional for all:** `DATABRICKS_HTTP_PATH` (SQL drivers), `DATABRICKS_WAREHOUSE_ID` (Statement Execution API). **Optional for U2M Custom OAuth App:** `DATABRICKS_U2M_CLIENT_SECRET` (if confidential app), `DATABRICKS_REDIRECT_URI` (default varies by connector). ### CLIENT_ID Distinction (Critical) | Env Var | Auth Type | What It Is | |---------|-----------|------------| | `DATABRICKS_CLIENT_ID` | `oauth_m2m` | M2M Service Principal UUID | | `DATABRICKS_U2M_CLIENT_ID` | `u2m_custom_oauth_app` | Custom OAuth App from App Connections | Using the wrong one causes `"OAuth application with client_id not available"`. --- ## Test Runner Script Pattern A well-structured test runner: 1. **Sources credentials once** from an env file 2. **Runs each test with isolated env** using `env -i` plus only required vars 3. **Records pass/fail** per test 4. **Prints summary** at the end ### Example Runner Structure ```bash #!/usr/bin/env bash set -euo pipefail # Load credentials source "${1:-credentials.env}" PASSED=0 FAILED=0 run_test() { local name="$1" local cmd="$2" echo "Running: $name" if eval "$cmd" > /dev/null 2>&1; then echo " PASS" ((PASSED++)) else echo " FAIL" ((FAILED++)) fi } # PAT Test run_test "PAT" "env -i PATH=\"$PATH\" HOME=\"$HOME\" \ DATABRICKS_HOST=\"$DATABRICKS_HOST\" \ DATABRICKS_TOKEN=\"$DATABRICKS_TOKEN\" \ python your_pat_example.py" # OAuth M2M Test run_test "OAuth M2M" "env -i PATH=\"$PATH\" HOME=\"$HOME\" \ DATABRICKS_HOST=\"$DATABRICKS_HOST\" \ DATABRICKS_CLIENT_ID=\"$DATABRICKS_CLIENT_ID\" \ DATABRICKS_CLIENT_SECRET=\"$DATABRICKS_CLIENT_SECRET\" \ python your_m2m_example.py" # Summary echo "" echo "Results: $PASSED passed, $FAILED failed" ``` --- ## U2M Browser Test Considerations ### Built-in OAuth App (External Browser) - Do NOT pass M2M credentials (`DATABRICKS_CLIENT_ID`/`DATABRICKS_CLIENT_SECRET`) - The SDK uses the built-in `databricks-cli` OAuth app - Redirect URI is typically `http://localhost:8020` ```bash env -i PATH="$PATH" HOME="$HOME" \ DATABRICKS_HOST="$DATABRICKS_HOST" \ USER="$USER" DISPLAY="${DISPLAY:-}" \ python your_u2m_browser_example.py ``` ### Custom OAuth App (PKCE) - Use `DATABRICKS_U2M_CLIENT_ID` (NOT `DATABRICKS_CLIENT_ID`) - Optionally set `DATABRICKS_U2M_CLIENT_SECRET` and `DATABRICKS_REDIRECT_URI` - Default redirect URI is typically `http://localhost:8040/callback` ```bash env -i PATH="$PATH" HOME="$HOME" \ DATABRICKS_HOST="$DATABRICKS_HOST" \ DATABRICKS_U2M_CLIENT_ID="$DATABRICKS_U2M_CLIENT_ID" \ DATABRICKS_U2M_CLIENT_SECRET="$DATABRICKS_U2M_CLIENT_SECRET" \ DATABRICKS_REDIRECT_URI="http://localhost:8040/callback" \ USER="$USER" DISPLAY="${DISPLAY:-}" \ python your_u2m_custom_app_example.py ``` ### Port Cleanup Before U2M Tests Before running custom OAuth app tests, kill any process holding the redirect port: ```bash lsof -ti:8040 | xargs kill -9 2>/dev/null || true ``` A previous hung test can leave the port bound. --- ## HTTPServer Pitfalls (PKCE Flow Implementation) When implementing the local callback server for PKCE: ### Python Implementation Pattern ```python import threading from http.server import HTTPServer, BaseHTTPRequestHandler class CallbackHandler(BaseHTTPRequestHandler): auth_code = None callback_received = threading.Event() def do_GET(self): if "/callback" in self.path: # Extract code from query params from urllib.parse import urlparse, parse_qs query = parse_qs(urlparse(self.path).query) CallbackHandler.auth_code = query.get("code", [None])[0] self.send_response(200) self.end_headers() self.wfile.write(b"Authentication complete. You can close this tab.") CallbackHandler.callback_received.set() else: # Ignore other requests (favicon, etc.) self.send_response(204) self.end_headers() def log_message(self, format, *args): pass # Suppress logging def run_callback_server(port=8040, timeout=120): server = HTTPServer(("localhost", port), CallbackHandler) server.timeout = timeout # CRITICAL: Set timeout # Handle requests until callback received or timeout while not CallbackHandler.callback_received.is_set(): server.handle_request() server.server_close() # Use server_close(), NOT shutdown() return CallbackHandler.auth_code ``` **Key Points:** - **Always set `server.timeout`** — Without it, `handle_request()` blocks forever - **Use `server.server_close()`** — NOT `server.shutdown()` (which hangs with `handle_request()`) - **Handle multiple requests** — Browser may send favicon requests before the callback - **Use `threading.Event`** — To signal when the actual callback is received --- ## Language-Specific Notes ### Python ```bash # PAT env -i PATH="$PATH" HOME="$HOME" PYTHONUNBUFFERED=1 \ DATABRICKS_HOST="$DATABRICKS_HOST" \ DATABRICKS_TOKEN="$DATABRICKS_TOKEN" \ python your_example.py # OAuth M2M env -i PATH="$PATH" HOME="$HOME" PYTHONUNBUFFERED=1 \ DATABRICKS_HOST="$DATABRICKS_HOST" \ DATABRICKS_CLIENT_ID="$DATABRICKS_CLIENT_ID" \ DATABRICKS_CLIENT_SECRET="$DATABRICKS_CLIENT_SECRET" \ python your_example.py # U2M (browser) env -i PATH="$PATH" HOME="$HOME" USER="$USER" DISPLAY="${DISPLAY:-}" \ DATABRICKS_HOST="$DATABRICKS_HOST" \ DATABRICKS_U2M_CLIENT_ID="$DATABRICKS_U2M_CLIENT_ID" \ python your_example.py ``` ### Java - **Environment isolation:** Run with `env -i` to prevent Java SDK auto-reading conflicting env vars - **Java 17+ JDBC:** Add `--add-opens=java.base/java.nio=ALL-UNNAMED` to JVM args for Arrow-based OSS JDBC driver - **SDK Workarounds (U2M):** Must call `config.setScopes(Arrays.asList("all-apis"))` and `config.resolve()` before `config.authenticate()` ```bash export MAVEN_OPTS="--add-opens=java.base/java.nio=ALL-UNNAMED" # PAT env -i PATH="$PATH" HOME="$HOME" JAVA_HOME="$JAVA_HOME" \ DATABRICKS_HOST="$DATABRICKS_HOST" \ DATABRICKS_TOKEN="$DATABRICKS_TOKEN" \ mvn -q exec:java -Dexec.mainClass="com.example.PatExample" # OAuth M2M env -i PATH="$PATH" HOME="$HOME" JAVA_HOME="$JAVA_HOME" \ DATABRICKS_HOST="$DATABRICKS_HOST" \ DATABRICKS_CLIENT_ID="$DATABRICKS_CLIENT_ID" \ DATABRICKS_CLIENT_SECRET="$DATABRICKS_CLIENT_SECRET" \ mvn -q exec:java -Dexec.mainClass="com.example.M2MExample" ``` ### Go - **Go SDK uses `APP_AUTH_TYPE`:** The SDK reads `DATABRICKS_AUTH_TYPE` internally, so use `APP_AUTH_TYPE` for your auth selector - **Go SQL Driver uses `DATABRICKS_AUTH_TYPE`:** Safe to use as the selector - **Build once, run with `env -i`:** Build the binary first, then run with isolated env ```bash # Build once (example for Go SDK with build tags) go build -tags all_auth_example -o ./my_example ./ # PAT (Go SDK uses APP_AUTH_TYPE) env -i PATH="$PATH" HOME="$HOME" \ APP_AUTH_TYPE=pat \ DATABRICKS_HOST="$DATABRICKS_HOST" \ DATABRICKS_TOKEN="$DATABRICKS_TOKEN" \ ./my_example # OAuth M2M env -i PATH="$PATH" HOME="$HOME" \ APP_AUTH_TYPE=oauth_m2m \ DATABRICKS_HOST="$DATABRICKS_HOST" \ DATABRICKS_CLIENT_ID="$DATABRICKS_CLIENT_ID" \ DATABRICKS_CLIENT_SECRET="$DATABRICKS_CLIENT_SECRET" \ ./my_example # U2M (browser) - needs USER and DISPLAY env -i PATH="$PATH" HOME="$HOME" USER="$USER" DISPLAY="${DISPLAY:-}" \ APP_AUTH_TYPE=u2m_custom_oauth_app \ DATABRICKS_HOST="$DATABRICKS_HOST" \ DATABRICKS_U2M_CLIENT_ID="$DATABRICKS_U2M_CLIENT_ID" \ ./my_example ``` ### Node.js ```bash # PAT env -i PATH="$PATH" HOME="$HOME" \ DATABRICKS_HOST="$DATABRICKS_HOST" \ DATABRICKS_HTTP_PATH="$DATABRICKS_HTTP_PATH" \ DATABRICKS_TOKEN="$DATABRICKS_TOKEN" \ node your_example.js # OAuth M2M env -i PATH="$PATH" HOME="$HOME" \ DATABRICKS_HOST="$DATABRICKS_HOST" \ DATABRICKS_HTTP_PATH="$DATABRICKS_HTTP_PATH" \ DATABRICKS_CLIENT_ID="$DATABRICKS_CLIENT_ID" \ DATABRICKS_CLIENT_SECRET="$DATABRICKS_CLIENT_SECRET" \ node your_example.js ``` --- ## Multi-Auth Example Pattern Support multiple auth types via an environment variable selector: ```python import os auth_type = os.environ.get("APP_AUTH_TYPE", "oauth_m2m")
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub