From 12f05320deaf1e2d96229e7bb280ecf7c59b25ce Mon Sep 17 00:00:00 2001 From: Hector Castejon Diaz Date: Thu, 19 Mar 2026 09:08:02 +0000 Subject: [PATCH 1/5] Add test for GetWorkspaceClient with SPOG host Port of Go SDK #1518. Verifies that getWorkspaceClient() on a unified (SPOG) host clones the config rather than mutating the AccountClient's config, so multiple calls produce independent WorkspaceClients. Co-authored-by: Isaac --- .../com/databricks/sdk/AccountClientTest.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/AccountClientTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/AccountClientTest.java index ca20fe5a2..4c7049374 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/AccountClientTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/AccountClientTest.java @@ -72,4 +72,40 @@ public void testGetWorkspaceClientForUnifiedHostType() { assertEquals(HostType.UNIFIED, config.getHostType()); } + + @Test + public void testGetWorkspaceClientForSpogHostDoesNotMutateAccountConfig() { + String spogHost = "https://mycompany.databricks.com"; + DatabricksConfig accountConfig = + new DatabricksConfig() + .setHost(spogHost) + .setExperimentalIsUnifiedHost(true) + .setAccountId("test-account") + .setToken("test-token"); + + AccountClient accountClient = new AccountClient(accountConfig); + + // Get workspace client for first workspace + Workspace workspace1 = new Workspace(); + workspace1.setWorkspaceId(111L); + workspace1.setDeploymentName("ws-1"); + WorkspaceClient wc1 = accountClient.getWorkspaceClient(workspace1); + + // Get workspace client for second workspace + Workspace workspace2 = new Workspace(); + workspace2.setWorkspaceId(222L); + workspace2.setDeploymentName("ws-2"); + WorkspaceClient wc2 = accountClient.getWorkspaceClient(workspace2); + + // Each workspace client should have its own workspace ID + assertEquals("111", wc1.config().getWorkspaceId()); + assertEquals("222", wc2.config().getWorkspaceId()); + + // Account config should not have been mutated + assertNull(accountConfig.getWorkspaceId()); + + // Both should share the same SPOG host + assertEquals(spogHost, wc1.config().getHost()); + assertEquals(spogHost, wc2.config().getHost()); + } } From 56583c124756f5aef9dbd42d651719a80684101d Mon Sep 17 00:00:00 2001 From: Hector Castejon Diaz Date: Thu, 19 Mar 2026 09:14:57 +0000 Subject: [PATCH 2/5] Call resolveHostMetadata on Config init Port of Go SDK #1542. Calls resolveHostMetadata() during config resolve() to populate accountId, workspaceId, and discoveryUrl from the host's well-known endpoint. Failures are logged at debug level and do not block initialization. Also fixes clone() to skip static fields (needed for the new Logger field). Co-authored-by: Isaac --- .../databricks/sdk/core/DatabricksConfig.java | 23 +++++++++++ .../sdk/core/DatabricksConfigTest.java | 38 ++++++++++++++----- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java index 627b0ab2f..574bacef4 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java @@ -18,8 +18,12 @@ import java.time.Duration; import java.util.*; import org.apache.http.HttpMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class DatabricksConfig { + private static final Logger LOG = LoggerFactory.getLogger(DatabricksConfig.class); + private CredentialsProvider credentialsProvider = new DefaultCredentialsProvider(); @ConfigAttribute(env = "DATABRICKS_HOST") @@ -219,12 +223,28 @@ private synchronized DatabricksConfig innerResolve() { sortScopes(); ConfigLoader.fixHostIfNeeded(this); initHttp(); + tryResolveHostMetadata(); return this; } catch (DatabricksException e) { throw ConfigLoader.makeNicerError(e.getMessage(), e, this); } } + /** + * Attempts to resolve host metadata from the well-known endpoint. Logs a warning and continues if + * metadata resolution fails, since not all hosts support the discovery endpoint. + */ + private void tryResolveHostMetadata() { + if (host == null) { + return; + } + try { + resolveHostMetadata(); + } catch (Exception e) { + LOG.debug("Failed to resolve host metadata: {}", e.getMessage()); + } + } + // Sort scopes in-place for better de-duplication in the refresh token cache. private void sortScopes() { if (scopes != null && !scopes.isEmpty()) { @@ -962,6 +982,9 @@ private DatabricksConfig clone(Set fieldsToSkip) { if (fieldsToSkip.contains(f.getName())) { continue; } + if (java.lang.reflect.Modifier.isStatic(f.getModifiers())) { + continue; + } try { f.set(newConfig, f.get(this)); } catch (IllegalAccessException e) { diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksConfigTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksConfigTest.java index 378581195..b7f8dab02 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksConfigTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksConfigTest.java @@ -99,6 +99,7 @@ public void testToStringWithEnv() { public void testWorkspaceLevelOidcEndpointsWithAccountId() throws IOException { try (FixtureServer server = new FixtureServer() + .with("GET", "/.well-known/databricks-config", "{}", 404) .with( "GET", "/oidc/.well-known/oauth-authorization-server", @@ -118,6 +119,7 @@ public void testWorkspaceLevelOidcEndpointsWithAccountId() throws IOException { public void testWorkspaceLevelOidcEndpointsRetries() throws IOException { try (FixtureServer server = new FixtureServer() + .with("GET", "/.well-known/databricks-config", "{}", 404) .with("GET", "/oidc/.well-known/oauth-authorization-server", "", 429) .with( "GET", @@ -443,7 +445,9 @@ public void testGetHostMetadataWorkspaceStaticOidcEndpoint() throws IOException + DUMMY_WORKSPACE_ID + "\"}"; try (FixtureServer server = - new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer() + .with("GET", "/.well-known/databricks-config", response, 200) + .with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); HostMetadata meta = config.getHostMetadata(); @@ -458,7 +462,9 @@ public void testGetHostMetadataAccountRawOidcTemplate() throws IOException { String response = "{\"oidc_endpoint\":\"https://acc.databricks.com/oidc/accounts/{account_id}\"}"; try (FixtureServer server = - new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer() + .with("GET", "/.well-known/databricks-config", response, 200) + .with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); HostMetadata meta = config.getHostMetadata(); @@ -471,7 +477,9 @@ public void testGetHostMetadataAccountRawOidcTemplate() throws IOException { @Test public void testGetHostMetadataRaisesOnHttpError() throws IOException { try (FixtureServer server = - new FixtureServer().with("GET", "/.well-known/databricks-config", "{}", 404)) { + new FixtureServer() + .with("GET", "/.well-known/databricks-config", "{}", 404) + .with("GET", "/.well-known/databricks-config", "{}", 404)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); DatabricksException ex = @@ -493,7 +501,9 @@ public void testResolveHostMetadataWorkspacePopulatesAllFields() throws IOExcept + DUMMY_WORKSPACE_ID + "\"}"; try (FixtureServer server = - new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer() + .with("GET", "/.well-known/databricks-config", response, 200) + .with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); config.resolveHostMetadata(); @@ -508,7 +518,9 @@ public void testResolveHostMetadataAccountSubstitutesAccountId() throws IOExcept String response = "{\"oidc_endpoint\":\"https://acc.databricks.com/oidc/accounts/{account_id}\"}"; try (FixtureServer server = - new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer() + .with("GET", "/.well-known/databricks-config", response, 200) + .with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()).setAccountId(DUMMY_ACCOUNT_ID); config.resolve(emptyEnv()); @@ -527,7 +539,9 @@ public void testResolveHostMetadataDoesNotOverwriteExistingFields() throws IOExc + "\"account_id\":\"other-account\"," + "\"workspace_id\":\"other-ws\"}"; try (FixtureServer server = - new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer() + .with("GET", "/.well-known/databricks-config", response, 200) + .with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig() .setHost(server.getUrl()) @@ -545,7 +559,9 @@ public void testResolveHostMetadataRaisesWhenAccountIdUnresolvable() throws IOEx String response = "{\"oidc_endpoint\":\"https://acc.databricks.com/oidc/accounts/{account_id}\"}"; try (FixtureServer server = - new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer() + .with("GET", "/.well-known/databricks-config", response, 200) + .with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); DatabricksException ex = @@ -558,7 +574,9 @@ public void testResolveHostMetadataRaisesWhenAccountIdUnresolvable() throws IOEx public void testResolveHostMetadataRaisesWhenOidcEndpointMissing() throws IOException { String response = "{\"account_id\":\"" + DUMMY_ACCOUNT_ID + "\"}"; try (FixtureServer server = - new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer() + .with("GET", "/.well-known/databricks-config", response, 200) + .with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); DatabricksException ex = @@ -570,7 +588,9 @@ public void testResolveHostMetadataRaisesWhenOidcEndpointMissing() throws IOExce @Test public void testResolveHostMetadataRaisesOnHttpError() throws IOException { try (FixtureServer server = - new FixtureServer().with("GET", "/.well-known/databricks-config", "{}", 500)) { + new FixtureServer() + .with("GET", "/.well-known/databricks-config", "{}", 500) + .with("GET", "/.well-known/databricks-config", "{}", 500)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); DatabricksException ex = From 441c4275bf9aab20883f0c1693f1254f5206f801 Mon Sep 17 00:00:00 2001 From: Hector Castejon Diaz Date: Mon, 23 Mar 2026 10:06:39 +0000 Subject: [PATCH 3/5] fixes --- .../databricks/sdk/core/DatabricksConfig.java | 48 ++++-- .../sdk/core/DatabricksConfigTest.java | 152 +++++++++++++----- 2 files changed, 144 insertions(+), 56 deletions(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java index 574bacef4..46fd13e58 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java @@ -13,6 +13,7 @@ import com.databricks.sdk.core.utils.Environment; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; +import java.net.URI; import java.io.IOException; import java.lang.reflect.Field; import java.time.Duration; @@ -231,17 +232,21 @@ private synchronized DatabricksConfig innerResolve() { } /** - * Attempts to resolve host metadata from the well-known endpoint. Logs a warning and continues if - * metadata resolution fails, since not all hosts support the discovery endpoint. + * Attempts to resolve host metadata from the well-known endpoint. Only called for unified hosts. + * Logs a warning and continues if metadata resolution fails, since not all hosts support the + * discovery endpoint. */ private void tryResolveHostMetadata() { if (host == null) { return; } + if (experimentalIsUnifiedHost == null || !experimentalIsUnifiedHost) { + return; + } try { resolveHostMetadata(); } catch (Exception e) { - LOG.debug("Failed to resolve host metadata: {}", e.getMessage()); + LOG.warn("Failed to resolve host metadata: {}. Falling back to user config.", e.getMessage()); } } @@ -852,14 +857,15 @@ HostMetadata getHostMetadata() throws IOException { * discovery endpoint. * *

Fills in {@code accountId}, {@code workspaceId}, and {@code discoveryUrl} (derived from - * {@code oidc_endpoint}, with any {@code {account_id}} placeholder substituted) if not already - * set. + * {@code oidc_endpoint}, with {@code /.well-known/oauth-authorization-server} appended and any + * {@code {account_id}} placeholder substituted) if not already set. + * + *

Errors from the metadata endpoint are non-fatal: a warning is logged and the method returns + * without modifying the config. This mirrors the Go SDK behavior where metadata resolution is + * best-effort during config init. * *

Note: This API is experimental and may change or be removed in future releases * without notice. - * - * @throws DatabricksException if {@code accountId} cannot be resolved or {@code oidc_endpoint} is - * missing from the host metadata. */ void resolveHostMetadata() throws IOException { if (host == null) { @@ -867,22 +873,30 @@ void resolveHostMetadata() throws IOException { } HostMetadata meta = getHostMetadata(); if (accountId == null && meta.getAccountId() != null) { + LOG.debug("Resolved account_id from host metadata: \"{}\"", meta.getAccountId()); accountId = meta.getAccountId(); } - if (accountId == null) { - throw new DatabricksException( - "account_id is not configured and could not be resolved from host metadata"); - } if (workspaceId == null && meta.getWorkspaceId() != null) { + LOG.debug("Resolved workspace_id from host metadata: \"{}\"", meta.getWorkspaceId()); workspaceId = meta.getWorkspaceId(); } if (discoveryUrl == null) { - if (meta.getOidcEndpoint() != null && !meta.getOidcEndpoint().isEmpty()) { - discoveryUrl = meta.getOidcEndpoint().replace("{account_id}", accountId); - } else { - throw new DatabricksException( - "discovery_url is not configured and could not be resolved from host metadata"); + if (meta.getOidcEndpoint() == null || meta.getOidcEndpoint().isEmpty()) { + LOG.warn("Host metadata missing oidc_endpoint; skipping discovery URL resolution"); + return; + } + String oidcRoot = meta.getOidcEndpoint(); + if (oidcRoot.contains("{account_id}")) { + if (accountId == null || accountId.isEmpty()) { + LOG.warn( + "Host metadata oidc_endpoint contains {account_id} placeholder but account_id is not set; skipping discovery URL resolution"); + return; + } + oidcRoot = oidcRoot.replace("{account_id}", accountId); } + URI oidcUri = URI.create(oidcRoot.endsWith("/") ? oidcRoot : oidcRoot + "/"); + discoveryUrl = oidcUri.resolve(".well-known/oauth-authorization-server").toString(); + LOG.debug("Resolved discovery_url from host metadata: \"{}\"", discoveryUrl); } } diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksConfigTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksConfigTest.java index b7f8dab02..fbc128a96 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksConfigTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksConfigTest.java @@ -99,7 +99,6 @@ public void testToStringWithEnv() { public void testWorkspaceLevelOidcEndpointsWithAccountId() throws IOException { try (FixtureServer server = new FixtureServer() - .with("GET", "/.well-known/databricks-config", "{}", 404) .with( "GET", "/oidc/.well-known/oauth-authorization-server", @@ -119,7 +118,6 @@ public void testWorkspaceLevelOidcEndpointsWithAccountId() throws IOException { public void testWorkspaceLevelOidcEndpointsRetries() throws IOException { try (FixtureServer server = new FixtureServer() - .with("GET", "/.well-known/databricks-config", "{}", 404) .with("GET", "/oidc/.well-known/oauth-authorization-server", "", 429) .with( "GET", @@ -445,9 +443,7 @@ public void testGetHostMetadataWorkspaceStaticOidcEndpoint() throws IOException + DUMMY_WORKSPACE_ID + "\"}"; try (FixtureServer server = - new FixtureServer() - .with("GET", "/.well-known/databricks-config", response, 200) - .with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); HostMetadata meta = config.getHostMetadata(); @@ -462,9 +458,7 @@ public void testGetHostMetadataAccountRawOidcTemplate() throws IOException { String response = "{\"oidc_endpoint\":\"https://acc.databricks.com/oidc/accounts/{account_id}\"}"; try (FixtureServer server = - new FixtureServer() - .with("GET", "/.well-known/databricks-config", response, 200) - .with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); HostMetadata meta = config.getHostMetadata(); @@ -477,9 +471,7 @@ public void testGetHostMetadataAccountRawOidcTemplate() throws IOException { @Test public void testGetHostMetadataRaisesOnHttpError() throws IOException { try (FixtureServer server = - new FixtureServer() - .with("GET", "/.well-known/databricks-config", "{}", 404) - .with("GET", "/.well-known/databricks-config", "{}", 404)) { + new FixtureServer().with("GET", "/.well-known/databricks-config", "{}", 404)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); DatabricksException ex = @@ -501,15 +493,15 @@ public void testResolveHostMetadataWorkspacePopulatesAllFields() throws IOExcept + DUMMY_WORKSPACE_ID + "\"}"; try (FixtureServer server = - new FixtureServer() - .with("GET", "/.well-known/databricks-config", response, 200) - .with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); config.resolveHostMetadata(); assertEquals(DUMMY_ACCOUNT_ID, config.getAccountId()); assertEquals(DUMMY_WORKSPACE_ID, config.getWorkspaceId()); - assertEquals("https://ws.databricks.com/oidc", config.getDiscoveryUrl()); + assertEquals( + "https://ws.databricks.com/oidc/.well-known/oauth-authorization-server", + config.getDiscoveryUrl()); } } @@ -518,15 +510,16 @@ public void testResolveHostMetadataAccountSubstitutesAccountId() throws IOExcept String response = "{\"oidc_endpoint\":\"https://acc.databricks.com/oidc/accounts/{account_id}\"}"; try (FixtureServer server = - new FixtureServer() - .with("GET", "/.well-known/databricks-config", response, 200) - .with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()).setAccountId(DUMMY_ACCOUNT_ID); config.resolve(emptyEnv()); config.resolveHostMetadata(); assertEquals( - "https://acc.databricks.com/oidc/accounts/" + DUMMY_ACCOUNT_ID, config.getDiscoveryUrl()); + "https://acc.databricks.com/oidc/accounts/" + + DUMMY_ACCOUNT_ID + + "/.well-known/oauth-authorization-server", + config.getDiscoveryUrl()); } } @@ -539,9 +532,7 @@ public void testResolveHostMetadataDoesNotOverwriteExistingFields() throws IOExc + "\"account_id\":\"other-account\"," + "\"workspace_id\":\"other-ws\"}"; try (FixtureServer server = - new FixtureServer() - .with("GET", "/.well-known/databricks-config", response, 200) - .with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig() .setHost(server.getUrl()) @@ -555,42 +546,38 @@ public void testResolveHostMetadataDoesNotOverwriteExistingFields() throws IOExc } @Test - public void testResolveHostMetadataRaisesWhenAccountIdUnresolvable() throws IOException { + public void testResolveHostMetadataMissingAccountIdWithPlaceholderSkipsDiscoveryUrl() + throws IOException { String response = "{\"oidc_endpoint\":\"https://acc.databricks.com/oidc/accounts/{account_id}\"}"; try (FixtureServer server = - new FixtureServer() - .with("GET", "/.well-known/databricks-config", response, 200) - .with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); - DatabricksException ex = - assertThrows(DatabricksException.class, () -> config.resolveHostMetadata()); - assertTrue(ex.getMessage().contains("account_id is not configured")); + config.resolveHostMetadata(); + // DiscoveryURL should not be set because account_id is empty and placeholder can't be + // substituted + assertNull(config.getDiscoveryUrl()); } } @Test - public void testResolveHostMetadataRaisesWhenOidcEndpointMissing() throws IOException { + public void testResolveHostMetadataNoOidcEndpointSkipsDiscoveryUrl() throws IOException { String response = "{\"account_id\":\"" + DUMMY_ACCOUNT_ID + "\"}"; try (FixtureServer server = - new FixtureServer() - .with("GET", "/.well-known/databricks-config", response, 200) - .with("GET", "/.well-known/databricks-config", response, 200)) { + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); - DatabricksException ex = - assertThrows(DatabricksException.class, () -> config.resolveHostMetadata()); - assertTrue(ex.getMessage().contains("discovery_url is not configured")); + config.resolveHostMetadata(); + assertEquals(DUMMY_ACCOUNT_ID, config.getAccountId()); + assertNull(config.getDiscoveryUrl()); } } @Test public void testResolveHostMetadataRaisesOnHttpError() throws IOException { try (FixtureServer server = - new FixtureServer() - .with("GET", "/.well-known/databricks-config", "{}", 500) - .with("GET", "/.well-known/databricks-config", "{}", 500)) { + new FixtureServer().with("GET", "/.well-known/databricks-config", "{}", 500)) { DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve(emptyEnv()); DatabricksException ex = @@ -599,6 +586,93 @@ public void testResolveHostMetadataRaisesOnHttpError() throws IOException { } } + // --- tryResolveHostMetadata (config init) tests --- + + @Test + public void testEnsureResolvedResolvesHostMetadataWhenUnifiedHost() throws IOException { + String response = + "{\"oidc_endpoint\":\"https://ws.databricks.com/oidc\"," + + "\"account_id\":\"" + + DUMMY_ACCOUNT_ID + + "\"," + + "\"workspace_id\":\"" + + DUMMY_WORKSPACE_ID + + "\"}"; + try (FixtureServer server = + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + DatabricksConfig config = + new DatabricksConfig() + .setHost(server.getUrl()) + .setExperimentalIsUnifiedHost(true); + config.resolve(emptyEnv()); + assertEquals(DUMMY_ACCOUNT_ID, config.getAccountId()); + assertEquals(DUMMY_WORKSPACE_ID, config.getWorkspaceId()); + assertEquals( + "https://ws.databricks.com/oidc/.well-known/oauth-authorization-server", + config.getDiscoveryUrl()); + } + } + + @Test + public void testEnsureResolvedSkipsHostMetadataWhenNotUnified() throws IOException { + // No metadata endpoint fixture — if it were called, the fixture server would fail + try (FixtureServer server = new FixtureServer()) { + DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); + config.resolve(emptyEnv()); + assertNull(config.getAccountId()); + assertNull(config.getWorkspaceId()); + } + } + + @Test + public void testEnsureResolvedHostMetadataFailureNonFatal() throws IOException { + try (FixtureServer server = + new FixtureServer() + .with("GET", "/.well-known/databricks-config", "{\"error\": \"internal error\"}", 500)) { + DatabricksConfig config = + new DatabricksConfig() + .setHost(server.getUrl()) + .setExperimentalIsUnifiedHost(true); + // Should not throw — metadata failure is non-fatal + config.resolve(emptyEnv()); + assertNull(config.getAccountId()); + assertNull(config.getWorkspaceId()); + } + } + + @Test + public void testEnsureResolvedHostMetadataNoOidcEndpointNonFatal() throws IOException { + String response = "{\"account_id\":\"" + DUMMY_ACCOUNT_ID + "\"}"; + try (FixtureServer server = + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + DatabricksConfig config = + new DatabricksConfig() + .setHost(server.getUrl()) + .setExperimentalIsUnifiedHost(true); + config.resolve(emptyEnv()); + assertEquals(DUMMY_ACCOUNT_ID, config.getAccountId()); + assertNull(config.getDiscoveryUrl()); + } + } + + @Test + public void testEnsureResolvedHostMetadataMissingAccountIdWithPlaceholderNonFatal() + throws IOException { + String response = + "{\"oidc_endpoint\":\"https://acc.databricks.com/oidc/accounts/{account_id}\"}"; + try (FixtureServer server = + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + DatabricksConfig config = + new DatabricksConfig() + .setHost(server.getUrl()) + .setExperimentalIsUnifiedHost(true); + config.resolve(emptyEnv()); + // DiscoveryURL should not be set because account_id is empty and placeholder can't be + // substituted + assertNull(config.getDiscoveryUrl()); + } + } + // --- discoveryUrl / OIDC endpoint tests --- @Test From 192e786622a864745b044dc6463b1ade6d8e518d Mon Sep 17 00:00:00 2001 From: Hector Castejon Diaz Date: Mon, 23 Mar 2026 10:20:13 +0000 Subject: [PATCH 4/5] fmt --- .../databricks/sdk/core/DatabricksConfig.java | 2 +- .../sdk/core/DatabricksConfigTest.java | 19 ++++++------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java index 46fd13e58..20104f972 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java @@ -13,9 +13,9 @@ import com.databricks.sdk.core.utils.Environment; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; -import java.net.URI; import java.io.IOException; import java.lang.reflect.Field; +import java.net.URI; import java.time.Duration; import java.util.*; import org.apache.http.HttpMessage; diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksConfigTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksConfigTest.java index fbc128a96..c6e149d76 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksConfigTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/DatabricksConfigTest.java @@ -601,9 +601,7 @@ public void testEnsureResolvedResolvesHostMetadataWhenUnifiedHost() throws IOExc try (FixtureServer server = new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = - new DatabricksConfig() - .setHost(server.getUrl()) - .setExperimentalIsUnifiedHost(true); + new DatabricksConfig().setHost(server.getUrl()).setExperimentalIsUnifiedHost(true); config.resolve(emptyEnv()); assertEquals(DUMMY_ACCOUNT_ID, config.getAccountId()); assertEquals(DUMMY_WORKSPACE_ID, config.getWorkspaceId()); @@ -628,11 +626,10 @@ public void testEnsureResolvedSkipsHostMetadataWhenNotUnified() throws IOExcepti public void testEnsureResolvedHostMetadataFailureNonFatal() throws IOException { try (FixtureServer server = new FixtureServer() - .with("GET", "/.well-known/databricks-config", "{\"error\": \"internal error\"}", 500)) { + .with( + "GET", "/.well-known/databricks-config", "{\"error\": \"internal error\"}", 500)) { DatabricksConfig config = - new DatabricksConfig() - .setHost(server.getUrl()) - .setExperimentalIsUnifiedHost(true); + new DatabricksConfig().setHost(server.getUrl()).setExperimentalIsUnifiedHost(true); // Should not throw — metadata failure is non-fatal config.resolve(emptyEnv()); assertNull(config.getAccountId()); @@ -646,9 +643,7 @@ public void testEnsureResolvedHostMetadataNoOidcEndpointNonFatal() throws IOExce try (FixtureServer server = new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = - new DatabricksConfig() - .setHost(server.getUrl()) - .setExperimentalIsUnifiedHost(true); + new DatabricksConfig().setHost(server.getUrl()).setExperimentalIsUnifiedHost(true); config.resolve(emptyEnv()); assertEquals(DUMMY_ACCOUNT_ID, config.getAccountId()); assertNull(config.getDiscoveryUrl()); @@ -663,9 +658,7 @@ public void testEnsureResolvedHostMetadataMissingAccountIdWithPlaceholderNonFata try (FixtureServer server = new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { DatabricksConfig config = - new DatabricksConfig() - .setHost(server.getUrl()) - .setExperimentalIsUnifiedHost(true); + new DatabricksConfig().setHost(server.getUrl()).setExperimentalIsUnifiedHost(true); config.resolve(emptyEnv()); // DiscoveryURL should not be set because account_id is empty and placeholder can't be // substituted From f5a4892cb3877c74bd8cff5979a3a2d177d304ff Mon Sep 17 00:00:00 2001 From: Hector Castejon Diaz Date: Mon, 23 Mar 2026 13:04:41 +0000 Subject: [PATCH 5/5] Add comment explaining static field skip in clone() --- .../src/main/java/com/databricks/sdk/core/DatabricksConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java index 20104f972..17ce54844 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java @@ -996,6 +996,7 @@ private DatabricksConfig clone(Set fieldsToSkip) { if (fieldsToSkip.contains(f.getName())) { continue; } + // Skip static fields (e.g. LOG) — they are shared across instances and cannot be set. if (java.lang.reflect.Modifier.isStatic(f.getModifiers())) { continue; }