From c879465a3284eefb19646907ba21aef97b7a6f33 Mon Sep 17 00:00:00 2001 From: Tanmay Rustagi Date: Mon, 30 Mar 2026 16:56:16 +0200 Subject: [PATCH 01/10] Add HostType to HostMetadata Signed-off-by: Tanmay Rustagi --- .../databricks/sdk/core/DatabricksConfig.java | 24 +++++ .../com/databricks/sdk/core/HostType.java | 22 ++++- .../sdk/core/oauth/HostMetadata.java | 7 ++ .../sdk/core/DatabricksConfigTest.java | 88 +++++++++++++++++++ .../com/databricks/sdk/core/HostTypeTest.java | 46 ++++++++++ 5 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 databricks-sdk-java/src/test/java/com/databricks/sdk/core/HostTypeTest.java 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 43c1f5136..35e93fd28 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 @@ -162,6 +162,12 @@ public class DatabricksConfig { private DatabricksEnvironment databricksEnvironment; + /** + * The host type resolved from the /.well-known/databricks-config discovery endpoint. When set, + * this takes priority over URL-based host type detection in {@link #getHostType()}. + */ + private HostType resolvedHostType; + /** * When using Workload Identity Federation, the audience to specify when fetching an ID token from * the ID token supplier. @@ -723,6 +729,17 @@ public DatabricksConfig setDisableOauthRefreshToken(boolean disable) { return this; } + /** Returns the host type resolved from host metadata, or {@code null} if not yet resolved. */ + HostType getResolvedHostType() { + return resolvedHostType; + } + + /** Sets the resolved host type. Package-private for testing. */ + DatabricksConfig setResolvedHostType(HostType resolvedHostType) { + this.resolvedHostType = resolvedHostType; + return this; + } + public boolean isAzure() { if (azureWorkspaceResourceId != null) { return true; @@ -889,6 +906,13 @@ void resolveHostMetadata() throws IOException { LOG.debug("Resolved workspace_id from host metadata: \"{}\"", meta.getWorkspaceId()); workspaceId = meta.getWorkspaceId(); } + if (resolvedHostType == null && meta.getHostType() != null) { + HostType ht = HostType.fromApiValue(meta.getHostType()); + if (ht != null) { + LOG.debug("Resolved host_type from host metadata: \"{}\"", ht); + resolvedHostType = ht; + } + } if (discoveryUrl == null) { if (meta.getOidcEndpoint() == null || meta.getOidcEndpoint().isEmpty()) { LOG.warn("Host metadata missing oidc_endpoint; skipping discovery URL resolution"); diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HostType.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HostType.java index 005807839..5976ae345 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HostType.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/HostType.java @@ -12,5 +12,25 @@ public enum HostType { ACCOUNTS, /** Unified host supporting both workspace and account operations. */ - UNIFIED + UNIFIED; + + /** + * Converts an API-level host type string (e.g. "workspace", "account", "unified") to the + * corresponding enum value. Returns {@code null} for unknown or empty values. + */ + public static HostType fromApiValue(String value) { + if (value == null || value.isEmpty()) { + return null; + } + switch (value.toLowerCase()) { + case "workspace": + return WORKSPACE; + case "account": + return ACCOUNTS; + case "unified": + return UNIFIED; + default: + return null; + } + } } diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/HostMetadata.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/HostMetadata.java index 3962f75d9..dfbf91fa5 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/HostMetadata.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/HostMetadata.java @@ -23,6 +23,9 @@ public class HostMetadata { @JsonProperty("cloud") private String cloud; + @JsonProperty("host_type") + private String hostType; + public HostMetadata() {} public HostMetadata(String oidcEndpoint, String accountId, String workspaceId) { @@ -53,4 +56,8 @@ public String getWorkspaceId() { public String getCloud() { return cloud; } + + public String getHostType() { + return hostType; + } } 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 0e86b4ef4..b2a83392f 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 @@ -712,6 +712,94 @@ public void testEnsureResolvedHostMetadataMissingAccountIdWithPlaceholderNonFata } } + // --- resolveHostMetadata host type tests --- + + @Test + public void testResolveHostMetadataPopulatesResolvedHostType() throws IOException { + String response = + "{\"oidc_endpoint\":\"https://ws.databricks.com/oidc\"," + + "\"account_id\":\"" + + DUMMY_ACCOUNT_ID + + "\"," + + "\"host_type\":\"workspace\"}"; + try (FixtureServer server = + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); + config.resolve(emptyEnv()); + config.resolveHostMetadata(); + assertEquals(HostType.WORKSPACE, config.getResolvedHostType()); + } + } + + @Test + public void testResolveHostMetadataDoesNotOverwriteExistingHostType() throws IOException { + String response = + "{\"oidc_endpoint\":\"https://ws.databricks.com/oidc\"," + + "\"account_id\":\"" + + DUMMY_ACCOUNT_ID + + "\"," + + "\"host_type\":\"workspace\"}"; + try (FixtureServer server = + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); + config.resolve(emptyEnv()); + config.setResolvedHostType(HostType.UNIFIED); + config.resolveHostMetadata(); + assertEquals(HostType.UNIFIED, config.getResolvedHostType()); + } + } + + @Test + public void testResolveHostMetadataUnknownHostTypeIgnored() throws IOException { + String response = + "{\"oidc_endpoint\":\"https://ws.databricks.com/oidc\"," + + "\"account_id\":\"" + + DUMMY_ACCOUNT_ID + + "\"," + + "\"host_type\":\"unknown_value\"}"; + try (FixtureServer server = + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); + config.resolve(emptyEnv()); + config.resolveHostMetadata(); + assertNull(config.getResolvedHostType()); + } + } + + @Test + public void testResolveHostMetadataHostTypeAccount() throws IOException { + String response = + "{\"oidc_endpoint\":\"https://ws.databricks.com/oidc\"," + + "\"account_id\":\"" + + DUMMY_ACCOUNT_ID + + "\"," + + "\"host_type\":\"account\"}"; + try (FixtureServer server = + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); + config.resolve(emptyEnv()); + config.resolveHostMetadata(); + assertEquals(HostType.ACCOUNTS, config.getResolvedHostType()); + } + } + + @Test + public void testResolveHostMetadataHostTypeUnified() throws IOException { + String response = + "{\"oidc_endpoint\":\"https://ws.databricks.com/oidc\"," + + "\"account_id\":\"" + + DUMMY_ACCOUNT_ID + + "\"," + + "\"host_type\":\"unified\"}"; + try (FixtureServer server = + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); + config.resolve(emptyEnv()); + config.resolveHostMetadata(); + assertEquals(HostType.UNIFIED, config.getResolvedHostType()); + } + } + // --- discoveryUrl / OIDC endpoint tests --- @Test diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/HostTypeTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/HostTypeTest.java new file mode 100644 index 000000000..63cd9b100 --- /dev/null +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/HostTypeTest.java @@ -0,0 +1,46 @@ +package com.databricks.sdk.core; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class HostTypeTest { + + @Test + public void testFromApiValueWorkspace() { + assertEquals(HostType.WORKSPACE, HostType.fromApiValue("workspace")); + } + + @Test + public void testFromApiValueAccount() { + assertEquals(HostType.ACCOUNTS, HostType.fromApiValue("account")); + } + + @Test + public void testFromApiValueUnified() { + assertEquals(HostType.UNIFIED, HostType.fromApiValue("unified")); + } + + @Test + public void testFromApiValueCaseInsensitive() { + assertEquals(HostType.WORKSPACE, HostType.fromApiValue("WORKSPACE")); + assertEquals(HostType.ACCOUNTS, HostType.fromApiValue("Account")); + assertEquals(HostType.UNIFIED, HostType.fromApiValue("UNIFIED")); + } + + @Test + public void testFromApiValueNull() { + assertNull(HostType.fromApiValue(null)); + } + + @Test + public void testFromApiValueEmpty() { + assertNull(HostType.fromApiValue("")); + } + + @Test + public void testFromApiValueUnknown() { + assertNull(HostType.fromApiValue("unknown")); + assertNull(HostType.fromApiValue("something_else")); + } +} From 2aec9e4c0fd69fdcc9489d70adaa9735beac0549 Mon Sep 17 00:00:00 2001 From: Tanmay Rustagi Date: Mon, 30 Mar 2026 18:42:28 +0200 Subject: [PATCH 02/10] Regenerate lockfile for commons-configuration2 2.13.0 Signed-off-by: Tanmay Rustagi --- databricks-sdk-java/lockfile.json | 62 +++++++++++++++---------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/databricks-sdk-java/lockfile.json b/databricks-sdk-java/lockfile.json index 8ba1d918d..d9ab2d94c 100644 --- a/databricks-sdk-java/lockfile.json +++ b/databricks-sdk-java/lockfile.json @@ -735,68 +735,68 @@ { "groupId": "org.apache.commons", "artifactId": "commons-configuration2", - "version": "2.11.0", + "version": "2.13.0", "checksumAlgorithm": "SHA-256", - "checksum": "48957fc3a0d9fbd221fe4f5ff6d0294ce6646ea139793c36706703da59402683", + "checksum": "7622799663317f95c81019b32b39e0c82e42b388f00abe6e5ab26489d90d9a6b", "scope": "compile", - "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-configuration2/2.11.0/commons-configuration2-2.11.0.jar", - "selectedVersion": "2.11.0", + "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-configuration2/2.13.0/commons-configuration2-2.13.0.jar", + "selectedVersion": "2.13.0", "included": true, - "id": "org.apache.commons:commons-configuration2:2.11.0", + "id": "org.apache.commons:commons-configuration2:2.13.0", "children": [ { "groupId": "commons-logging", "artifactId": "commons-logging", - "version": "1.3.2", + "version": "1.3.5", "checksumAlgorithm": "SHA-256", - "checksum": "6b858424f518015f32bfcd1183a373f4a827d72d026b6031da0c91cf0e8f3489", + "checksum": "6d7a744e4027649fbb50895df9497d109f98c766a637062fe8d2eabbb3140ba4", "scope": "compile", - "resolved": "https://repo.maven.apache.org/maven2/commons-logging/commons-logging/1.3.2/commons-logging-1.3.2.jar", - "selectedVersion": "1.3.2", + "resolved": "https://repo.maven.apache.org/maven2/commons-logging/commons-logging/1.3.5/commons-logging-1.3.5.jar", + "selectedVersion": "1.3.5", "included": true, - "id": "commons-logging:commons-logging:1.3.2", - "parent": "org.apache.commons:commons-configuration2:2.11.0", + "id": "commons-logging:commons-logging:1.3.5", + "parent": "org.apache.commons:commons-configuration2:2.13.0", "children": [] }, { "groupId": "org.apache.commons", "artifactId": "commons-lang3", - "version": "3.14.0", + "version": "3.20.0", "checksumAlgorithm": "SHA-256", - "checksum": "7b96bf3ee68949abb5bc465559ac270e0551596fa34523fddf890ec418dde13c", + "checksum": "69e5c9fa35da7a51a5fd2099dfe56a2d8d32cf233e2f6d770e796146440263f4", "scope": "compile", - "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.14.0/commons-lang3-3.14.0.jar", - "selectedVersion": "3.14.0", + "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.20.0/commons-lang3-3.20.0.jar", + "selectedVersion": "3.20.0", "included": true, - "id": "org.apache.commons:commons-lang3:3.14.0", - "parent": "org.apache.commons:commons-configuration2:2.11.0", + "id": "org.apache.commons:commons-lang3:3.20.0", + "parent": "org.apache.commons:commons-configuration2:2.13.0", "children": [] }, { "groupId": "org.apache.commons", "artifactId": "commons-text", - "version": "1.12.0", + "version": "1.14.0", "checksumAlgorithm": "SHA-256", - "checksum": "de023257ff166044a56bd1aa9124e843cd05dac5806cc705a9311f3556d5a15f", + "checksum": "121fce2282910c8f0c3ba793a5436b31beb710423cbe2d574a3fb7a73c508e92", "scope": "compile", - "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-text/1.12.0/commons-text-1.12.0.jar", - "selectedVersion": "1.12.0", + "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-text/1.14.0/commons-text-1.14.0.jar", + "selectedVersion": "1.14.0", "included": true, - "id": "org.apache.commons:commons-text:1.12.0", - "parent": "org.apache.commons:commons-configuration2:2.11.0", + "id": "org.apache.commons:commons-text:1.14.0", + "parent": "org.apache.commons:commons-configuration2:2.13.0", "children": [ { "groupId": "org.apache.commons", "artifactId": "commons-lang3", - "version": "3.14.0", + "version": "3.18.0", "checksumAlgorithm": "SHA-256", - "checksum": "7b96bf3ee68949abb5bc465559ac270e0551596fa34523fddf890ec418dde13c", + "checksum": "4eeeae8d20c078abb64b015ec158add383ac581571cddc45c68f0c9ae0230720", "scope": "compile", - "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.14.0/commons-lang3-3.14.0.jar", - "selectedVersion": "3.14.0", + "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar", + "selectedVersion": "3.20.0", "included": false, - "id": "org.apache.commons:commons-lang3:3.14.0", - "parent": "org.apache.commons:commons-text:1.12.0", + "id": "org.apache.commons:commons-lang3:3.18.0", + "parent": "org.apache.commons:commons-text:1.14.0", "children": [] } ] @@ -837,7 +837,7 @@ "checksum": "daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636", "scope": "compile", "resolved": "https://repo.maven.apache.org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2.jar", - "selectedVersion": "1.3.2", + "selectedVersion": "1.3.5", "included": false, "id": "commons-logging:commons-logging:1.2", "parent": "org.apache.httpcomponents:httpclient:4.5.14", @@ -1287,4 +1287,4 @@ "checksumAlgorithm": "SHA-256" } } -} \ No newline at end of file +} From dff706f0a48511e44fefdc8a46d6631c008b5dfb Mon Sep 17 00:00:00 2001 From: Tanmay Rustagi Date: Mon, 30 Mar 2026 18:59:53 +0200 Subject: [PATCH 03/10] Revert lockfile.json to main state Signed-off-by: Tanmay Rustagi --- databricks-sdk-java/lockfile.json | 62 +++++++++++++++---------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/databricks-sdk-java/lockfile.json b/databricks-sdk-java/lockfile.json index d9ab2d94c..8ba1d918d 100644 --- a/databricks-sdk-java/lockfile.json +++ b/databricks-sdk-java/lockfile.json @@ -735,68 +735,68 @@ { "groupId": "org.apache.commons", "artifactId": "commons-configuration2", - "version": "2.13.0", + "version": "2.11.0", "checksumAlgorithm": "SHA-256", - "checksum": "7622799663317f95c81019b32b39e0c82e42b388f00abe6e5ab26489d90d9a6b", + "checksum": "48957fc3a0d9fbd221fe4f5ff6d0294ce6646ea139793c36706703da59402683", "scope": "compile", - "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-configuration2/2.13.0/commons-configuration2-2.13.0.jar", - "selectedVersion": "2.13.0", + "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-configuration2/2.11.0/commons-configuration2-2.11.0.jar", + "selectedVersion": "2.11.0", "included": true, - "id": "org.apache.commons:commons-configuration2:2.13.0", + "id": "org.apache.commons:commons-configuration2:2.11.0", "children": [ { "groupId": "commons-logging", "artifactId": "commons-logging", - "version": "1.3.5", + "version": "1.3.2", "checksumAlgorithm": "SHA-256", - "checksum": "6d7a744e4027649fbb50895df9497d109f98c766a637062fe8d2eabbb3140ba4", + "checksum": "6b858424f518015f32bfcd1183a373f4a827d72d026b6031da0c91cf0e8f3489", "scope": "compile", - "resolved": "https://repo.maven.apache.org/maven2/commons-logging/commons-logging/1.3.5/commons-logging-1.3.5.jar", - "selectedVersion": "1.3.5", + "resolved": "https://repo.maven.apache.org/maven2/commons-logging/commons-logging/1.3.2/commons-logging-1.3.2.jar", + "selectedVersion": "1.3.2", "included": true, - "id": "commons-logging:commons-logging:1.3.5", - "parent": "org.apache.commons:commons-configuration2:2.13.0", + "id": "commons-logging:commons-logging:1.3.2", + "parent": "org.apache.commons:commons-configuration2:2.11.0", "children": [] }, { "groupId": "org.apache.commons", "artifactId": "commons-lang3", - "version": "3.20.0", + "version": "3.14.0", "checksumAlgorithm": "SHA-256", - "checksum": "69e5c9fa35da7a51a5fd2099dfe56a2d8d32cf233e2f6d770e796146440263f4", + "checksum": "7b96bf3ee68949abb5bc465559ac270e0551596fa34523fddf890ec418dde13c", "scope": "compile", - "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.20.0/commons-lang3-3.20.0.jar", - "selectedVersion": "3.20.0", + "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.14.0/commons-lang3-3.14.0.jar", + "selectedVersion": "3.14.0", "included": true, - "id": "org.apache.commons:commons-lang3:3.20.0", - "parent": "org.apache.commons:commons-configuration2:2.13.0", + "id": "org.apache.commons:commons-lang3:3.14.0", + "parent": "org.apache.commons:commons-configuration2:2.11.0", "children": [] }, { "groupId": "org.apache.commons", "artifactId": "commons-text", - "version": "1.14.0", + "version": "1.12.0", "checksumAlgorithm": "SHA-256", - "checksum": "121fce2282910c8f0c3ba793a5436b31beb710423cbe2d574a3fb7a73c508e92", + "checksum": "de023257ff166044a56bd1aa9124e843cd05dac5806cc705a9311f3556d5a15f", "scope": "compile", - "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-text/1.14.0/commons-text-1.14.0.jar", - "selectedVersion": "1.14.0", + "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-text/1.12.0/commons-text-1.12.0.jar", + "selectedVersion": "1.12.0", "included": true, - "id": "org.apache.commons:commons-text:1.14.0", - "parent": "org.apache.commons:commons-configuration2:2.13.0", + "id": "org.apache.commons:commons-text:1.12.0", + "parent": "org.apache.commons:commons-configuration2:2.11.0", "children": [ { "groupId": "org.apache.commons", "artifactId": "commons-lang3", - "version": "3.18.0", + "version": "3.14.0", "checksumAlgorithm": "SHA-256", - "checksum": "4eeeae8d20c078abb64b015ec158add383ac581571cddc45c68f0c9ae0230720", + "checksum": "7b96bf3ee68949abb5bc465559ac270e0551596fa34523fddf890ec418dde13c", "scope": "compile", - "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar", - "selectedVersion": "3.20.0", + "resolved": "https://repo.maven.apache.org/maven2/org/apache/commons/commons-lang3/3.14.0/commons-lang3-3.14.0.jar", + "selectedVersion": "3.14.0", "included": false, - "id": "org.apache.commons:commons-lang3:3.18.0", - "parent": "org.apache.commons:commons-text:1.14.0", + "id": "org.apache.commons:commons-lang3:3.14.0", + "parent": "org.apache.commons:commons-text:1.12.0", "children": [] } ] @@ -837,7 +837,7 @@ "checksum": "daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636", "scope": "compile", "resolved": "https://repo.maven.apache.org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2.jar", - "selectedVersion": "1.3.5", + "selectedVersion": "1.3.2", "included": false, "id": "commons-logging:commons-logging:1.2", "parent": "org.apache.httpcomponents:httpclient:4.5.14", @@ -1287,4 +1287,4 @@ "checksumAlgorithm": "SHA-256" } } -} +} \ No newline at end of file From acb210f0ef7e22aa26904899d3c4fd755eeeebef Mon Sep 17 00:00:00 2001 From: Tanmay Rustagi Date: Mon, 30 Mar 2026 16:58:22 +0200 Subject: [PATCH 04/10] Resolve TokenAudience from default_oidc_audience in host metadata Signed-off-by: Tanmay Rustagi --- .../databricks/sdk/core/DatabricksConfig.java | 11 ++- .../sdk/core/oauth/HostMetadata.java | 7 ++ .../sdk/core/DatabricksConfigTest.java | 92 +++++++++++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) 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 35e93fd28..a946373aa 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 @@ -931,8 +931,17 @@ void resolveHostMetadata() throws IOException { discoveryUrl = oidcUri.resolve(".well-known/oauth-authorization-server").toString(); LOG.debug("Resolved discovery_url from host metadata: \"{}\"", discoveryUrl); } - // For account hosts, use the accountId as the token audience if not already set. + if (tokenAudience == null + && meta.getDefaultOidcAudience() != null + && !meta.getDefaultOidcAudience().isEmpty()) { + LOG.debug( + "Resolved token_audience from host metadata default_oidc_audience: \"{}\"", + meta.getDefaultOidcAudience()); + tokenAudience = meta.getDefaultOidcAudience(); + } + // Fallback: for account hosts, use the accountId as the token audience if not already set. if (tokenAudience == null && getClientType() == ClientType.ACCOUNT && accountId != null) { + LOG.debug("Setting token_audience to account_id for account host: \"{}\"", accountId); tokenAudience = accountId; } } diff --git a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/HostMetadata.java b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/HostMetadata.java index dfbf91fa5..0fe5a15ef 100644 --- a/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/HostMetadata.java +++ b/databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/HostMetadata.java @@ -26,6 +26,9 @@ public class HostMetadata { @JsonProperty("host_type") private String hostType; + @JsonProperty("default_oidc_audience") + private String defaultOidcAudience; + public HostMetadata() {} public HostMetadata(String oidcEndpoint, String accountId, String workspaceId) { @@ -60,4 +63,8 @@ public String getCloud() { public String getHostType() { return hostType; } + + public String getDefaultOidcAudience() { + return defaultOidcAudience; + } } 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 b2a83392f..70081a790 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 @@ -800,6 +800,98 @@ public void testResolveHostMetadataHostTypeUnified() throws IOException { } } + // --- resolveHostMetadata default_oidc_audience tests --- + + @Test + public void testResolveHostMetadataSetsTokenAudienceFromDefaultOidcAudience() throws IOException { + String response = + "{\"oidc_endpoint\":\"https://ws.databricks.com/oidc\"," + + "\"account_id\":\"" + + DUMMY_ACCOUNT_ID + + "\"," + + "\"default_oidc_audience\":\"https://ws.databricks.com/oidc/v1/token\"}"; + try (FixtureServer server = + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); + config.resolve(emptyEnv()); + config.resolveHostMetadata(); + assertEquals("https://ws.databricks.com/oidc/v1/token", config.getTokenAudience()); + } + } + + @Test + public void testResolveHostMetadataDefaultOidcAudiencePriorityOverAccountIdFallback() + throws IOException { + // default_oidc_audience should take priority over the account_id fallback for account hosts + String response = + "{\"oidc_endpoint\":\"https://acc.databricks.com/oidc/accounts/{account_id}\"," + + "\"account_id\":\"" + + DUMMY_ACCOUNT_ID + + "\"," + + "\"default_oidc_audience\":\"custom-audience\"}"; + try (FixtureServer server = + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + DatabricksConfig config = + new DatabricksConfig() + .setHost(server.getUrl()) + .setExperimentalIsUnifiedHost(true) + .setAccountId(DUMMY_ACCOUNT_ID); + // Note: need two fixtures — resolve() consumes first one (unified host triggers + // tryResolveHostMetadata) + // Instead, don't set unified — just test direct call + config = new DatabricksConfig().setHost(server.getUrl()).setAccountId(DUMMY_ACCOUNT_ID); + config.resolve(emptyEnv()); + config.resolveHostMetadata(); + // Should use default_oidc_audience, NOT account_id + assertEquals("custom-audience", config.getTokenAudience()); + } + } + + @Test + public void testResolveHostMetadataDoesNotOverrideExistingTokenAudienceWithOidcAudience() + throws IOException { + String response = + "{\"oidc_endpoint\":\"https://ws.databricks.com/oidc\"," + + "\"account_id\":\"" + + DUMMY_ACCOUNT_ID + + "\"," + + "\"default_oidc_audience\":\"metadata-audience\"}"; + try (FixtureServer server = + new FixtureServer().with("GET", "/.well-known/databricks-config", response, 200)) { + DatabricksConfig config = + new DatabricksConfig().setHost(server.getUrl()).setTokenAudience("existing-audience"); + config.resolve(emptyEnv()); + config.resolveHostMetadata(); + assertEquals("existing-audience", config.getTokenAudience()); + } + } + + @Test + public void testResolveHostMetadataFallsBackToAccountIdWhenNoDefaultOidcAudience() + throws IOException { + // When no default_oidc_audience, should fall back to account_id for account hosts. + // Use unified host flag so getClientType() returns ACCOUNT (no workspaceId). + String response = + "{\"oidc_endpoint\":\"https://acc.databricks.com/oidc/accounts/{account_id}\"," + + "\"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)) { + DatabricksConfig config = + new DatabricksConfig() + .setHost(server.getUrl()) + .setAccountId(DUMMY_ACCOUNT_ID) + .setExperimentalIsUnifiedHost(true); + config.resolve(emptyEnv()); + // resolve() with unified flag triggers tryResolveHostMetadata() consuming first fixture. + // Now call again with second fixture to verify account_id fallback. + assertEquals(DUMMY_ACCOUNT_ID, config.getTokenAudience()); + } + } + // --- discoveryUrl / OIDC endpoint tests --- @Test From 6b1ed72b84fe5a6468972e7f05a34068ba66fa98 Mon Sep 17 00:00:00 2001 From: Tanmay Rustagi Date: Mon, 30 Mar 2026 16:59:49 +0200 Subject: [PATCH 05/10] Use resolved host type from host metadata in getHostType() Signed-off-by: Tanmay Rustagi --- .../databricks/sdk/core/DatabricksConfig.java | 9 ++- .../databricks/sdk/core/UnifiedHostTest.java | 67 +++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) 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 a946373aa..44d1dae64 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 @@ -775,8 +775,15 @@ public boolean isAccountClient() { return host.startsWith("https://accounts.") || host.startsWith("https://accounts-dod."); } - /** Returns the host type based on configuration settings and host URL. */ + /** + * Returns the host type based on configuration settings and host URL. When host metadata has been + * resolved (via /.well-known/databricks-config), the resolved host type is returned directly. + * Otherwise, the host type is inferred from URL patterns as a fallback. + */ public HostType getHostType() { + if (resolvedHostType != null) { + return resolvedHostType; + } if (experimentalIsUnifiedHost != null && experimentalIsUnifiedHost) { return HostType.UNIFIED; } diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java index f282b51d8..caed880cd 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java @@ -231,4 +231,71 @@ public void testNoHeaderInjectionForTraditionalWorkspace() { assertEquals("Bearer test-token", headers.get("Authorization")); assertNull(headers.get("X-Databricks-Org-Id")); } + + // --- Resolved host type from metadata tests --- + + @Test + public void testMetadataWorkspaceOverridesAccountLikeUrl() { + DatabricksConfig config = + new DatabricksConfig() + .setHost("https://accounts.cloud.databricks.com") + .setResolvedHostType(HostType.WORKSPACE); + assertEquals(HostType.WORKSPACE, config.getHostType()); + } + + @Test + public void testMetadataAccountOverridesWorkspaceLikeUrl() { + DatabricksConfig config = + new DatabricksConfig() + .setHost("https://my-workspace.cloud.databricks.com") + .setResolvedHostType(HostType.ACCOUNTS); + assertEquals(HostType.ACCOUNTS, config.getHostType()); + } + + @Test + public void testMetadataUnifiedIsReturned() { + DatabricksConfig config = + new DatabricksConfig() + .setHost("https://my-workspace.cloud.databricks.com") + .setResolvedHostType(HostType.UNIFIED); + assertEquals(HostType.UNIFIED, config.getHostType()); + } + + @Test + public void testFallsBackToUrlMatchingWhenResolvedHostTypeNull() { + DatabricksConfig config = + new DatabricksConfig().setHost("https://accounts.cloud.databricks.com"); + // resolvedHostType is null by default + assertEquals(HostType.ACCOUNTS, config.getHostType()); + } + + @Test + public void testMetadataOverridesExperimentalFlag() { + DatabricksConfig config = + new DatabricksConfig() + .setHost("https://my-workspace.cloud.databricks.com") + .setExperimentalIsUnifiedHost(true) + .setResolvedHostType(HostType.ACCOUNTS); + // Resolved host type takes priority over experimental flag + assertEquals(HostType.ACCOUNTS, config.getHostType()); + } + + @Test + public void testEndToEndResolveToGetHostType() throws IOException { + String response = + "{\"oidc_endpoint\":\"https://ws.databricks.com/oidc\"," + + "\"account_id\":\"test-account\"," + + "\"host_type\":\"unified\"}"; + try (FixtureServer server = + 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()).setExperimentalIsUnifiedHost(true); + config.resolve( + new Environment(new HashMap<>(), new ArrayList<>(), System.getProperty("os.name"))); + // After resolve(), tryResolveHostMetadata() should have set resolvedHostType + assertEquals(HostType.UNIFIED, config.getHostType()); + } + } } From c1dadf7732dfc0b71f929a233ae1e3463e329f48 Mon Sep 17 00:00:00 2001 From: Tanmay Rustagi Date: Sat, 11 Apr 2026 13:10:27 +0200 Subject: [PATCH 06/10] Fix test failures: fixture double-consumption, experimental flag, imports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DatabricksConfigTest.java: - Add second fixture for tests calling both resolve() and resolveHostMetadata(), since resolve() internally calls tryResolveHostMetadata() consuming the first fixture. - Replace setExperimentalIsUnifiedHost(true) with host_type in metadata response, since PR #720 removed the experimental flag check from getHostType(). UnifiedHostTest.java: - Add missing java.io.IOException import. - Remove 3 broken header injection tests that asserted X-Databricks-Org-Id in authenticate() headers — that header is injected at the service impl level, not during authentication. - Remove stale setExperimentalIsUnifiedHost(true) from remaining tests (no-op after PR #720). - Update javadoc to reflect re-introduced UNIFIED host type. --- .../sdk/core/DatabricksConfigTest.java | 55 +++++++++------- .../databricks/sdk/core/UnifiedHostTest.java | 64 +++---------------- 2 files changed, 40 insertions(+), 79 deletions(-) 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 1b9794597..ebf388c16 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 @@ -668,7 +668,9 @@ public void testResolveHostMetadataPopulatesResolvedHostType() throws IOExceptio + "\"," + "\"host_type\":\"workspace\"}"; 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(); @@ -685,7 +687,9 @@ public void testResolveHostMetadataDoesNotOverwriteExistingHostType() throws IOE + "\"," + "\"host_type\":\"workspace\"}"; 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.setResolvedHostType(HostType.UNIFIED); @@ -703,7 +707,9 @@ public void testResolveHostMetadataUnknownHostTypeIgnored() throws IOException { + "\"," + "\"host_type\":\"unknown_value\"}"; 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(); @@ -720,7 +726,9 @@ public void testResolveHostMetadataHostTypeAccount() throws IOException { + "\"," + "\"host_type\":\"account\"}"; 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(); @@ -737,7 +745,9 @@ public void testResolveHostMetadataHostTypeUnified() throws IOException { + "\"," + "\"host_type\":\"unified\"}"; 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(); @@ -756,7 +766,9 @@ public void testResolveHostMetadataSetsTokenAudienceFromDefaultOidcAudience() th + "\"," + "\"default_oidc_audience\":\"https://ws.databricks.com/oidc/v1/token\"}"; 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(); @@ -773,18 +785,14 @@ public void testResolveHostMetadataDefaultOidcAudiencePriorityOverAccountIdFallb + "\"account_id\":\"" + DUMMY_ACCOUNT_ID + "\"," + + "\"host_type\":\"account\"," + "\"default_oidc_audience\":\"custom-audience\"}"; 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()) - .setExperimentalIsUnifiedHost(true) - .setAccountId(DUMMY_ACCOUNT_ID); - // Note: need two fixtures — resolve() consumes first one (unified host triggers - // tryResolveHostMetadata) - // Instead, don't set unified — just test direct call - config = new DatabricksConfig().setHost(server.getUrl()).setAccountId(DUMMY_ACCOUNT_ID); + new DatabricksConfig().setHost(server.getUrl()).setAccountId(DUMMY_ACCOUNT_ID); config.resolve(emptyEnv()); config.resolveHostMetadata(); // Should use default_oidc_audience, NOT account_id @@ -802,7 +810,9 @@ public void testResolveHostMetadataDoesNotOverrideExistingTokenAudienceWithOidcA + "\"," + "\"default_oidc_audience\":\"metadata-audience\"}"; 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()).setTokenAudience("existing-audience"); config.resolve(emptyEnv()); @@ -815,24 +825,23 @@ public void testResolveHostMetadataDoesNotOverrideExistingTokenAudienceWithOidcA public void testResolveHostMetadataFallsBackToAccountIdWhenNoDefaultOidcAudience() throws IOException { // When no default_oidc_audience, should fall back to account_id for account hosts. - // Use unified host flag so getClientType() returns ACCOUNT (no workspaceId). + // Use host_type=account in metadata so getClientType() returns ACCOUNT. String response = "{\"oidc_endpoint\":\"https://acc.databricks.com/oidc/accounts/{account_id}\"," + "\"account_id\":\"" + DUMMY_ACCOUNT_ID - + "\"}"; + + "\"," + + "\"host_type\":\"account\"}"; try (FixtureServer server = 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) - .setExperimentalIsUnifiedHost(true); + .setAccountId(DUMMY_ACCOUNT_ID); config.resolve(emptyEnv()); - // resolve() with unified flag triggers tryResolveHostMetadata() consuming first fixture. - // Now call again with second fixture to verify account_id fallback. + // resolve() triggers tryResolveHostMetadata() which sets resolvedHostType=ACCOUNTS, + // then the tokenAudience fallback sets tokenAudience to accountId. assertEquals(DUMMY_ACCOUNT_ID, config.getTokenAudience()); } } diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java index eba1f2899..22cab891f 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.*; import com.databricks.sdk.core.utils.Environment; +import java.io.IOException; import java.util.*; import java.util.stream.Stream; import org.junit.jupiter.api.Test; @@ -11,11 +12,11 @@ import org.junit.jupiter.params.provider.MethodSource; /** - * Tests for host type detection, client type determination, and header injection. + * Tests for host type detection, client type determination, and resolved host type from metadata. * - *

After removing the UNIFIED host type, host type is determined solely from the URL pattern. - * Host metadata resolution (via /.well-known/databricks-config) populates accountId, workspaceId, - * and discoveryUrl automatically during config init. + *

Host type is determined by resolvedHostType (from /.well-known/databricks-config metadata) + * when available, falling back to URL pattern matching. Host metadata resolution also populates + * accountId, workspaceId, and discoveryUrl automatically during config init. */ public class UnifiedHostTest { @@ -111,53 +112,6 @@ public void testWorkspaceIdFromEnvironmentVariables() { assertEquals(ClientType.WORKSPACE, config.getClientType()); } - // --- Header Injection Tests --- - - @Test - public void testHeaderInjectionForWorkspaceOnUnified() { - String workspaceId = "123456789"; - - DatabricksConfig config = - new DatabricksConfig() - .setHost("https://unified.databricks.com") - .setExperimentalIsUnifiedHost(true) - .setWorkspaceId(workspaceId) - .setToken("test-token"); - - Map headers = config.authenticate(); - - assertEquals("Bearer test-token", headers.get("Authorization")); - assertEquals(workspaceId, headers.get("X-Databricks-Org-Id")); - } - - @Test - public void testNoHeaderInjectionForAccountOnUnified() { - DatabricksConfig config = - new DatabricksConfig() - .setHost("https://unified.databricks.com") - .setExperimentalIsUnifiedHost(true) - .setToken("test-token"); - // No workspace ID set - - Map headers = config.authenticate(); - - assertEquals("Bearer test-token", headers.get("Authorization")); - assertNull(headers.get("X-Databricks-Org-Id")); - } - - @Test - public void testNoHeaderInjectionForTraditionalWorkspace() { - DatabricksConfig config = - new DatabricksConfig() - .setHost("https://adb-123.azuredatabricks.net") - .setToken("test-token"); - - Map headers = config.authenticate(); - - assertEquals("Bearer test-token", headers.get("Authorization")); - assertNull(headers.get("X-Databricks-Org-Id")); - } - // --- Resolved host type from metadata tests --- @Test @@ -196,13 +150,12 @@ public void testFallsBackToUrlMatchingWhenResolvedHostTypeNull() { } @Test - public void testMetadataOverridesExperimentalFlag() { + public void testResolvedHostTypeTakesPriorityOverUrlMatching() { DatabricksConfig config = new DatabricksConfig() .setHost("https://my-workspace.cloud.databricks.com") - .setExperimentalIsUnifiedHost(true) .setResolvedHostType(HostType.ACCOUNTS); - // Resolved host type takes priority over experimental flag + // Resolved host type takes priority over URL-based detection assertEquals(HostType.ACCOUNTS, config.getHostType()); } @@ -216,8 +169,7 @@ public void testEndToEndResolveToGetHostType() throws IOException { 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()).setExperimentalIsUnifiedHost(true); + DatabricksConfig config = new DatabricksConfig().setHost(server.getUrl()); config.resolve( new Environment(new HashMap<>(), new ArrayList<>(), System.getProperty("os.name"))); // After resolve(), tryResolveHostMetadata() should have set resolvedHostType From 6dfbf98cf19eaf4b9463d9cad732f87b14ec4d6f Mon Sep 17 00:00:00 2001 From: Tanmay Rustagi Date: Sat, 11 Apr 2026 13:13:48 +0200 Subject: [PATCH 07/10] Remove redundant resolveHostMetadata() calls, use host_type metadata - Remove redundant explicit resolveHostMetadata() calls since resolve() already triggers it internally via tryResolveHostMetadata(). Revert to single fixtures where the second call was removed. - Keep double fixture only for testResolveHostMetadataDoesNotOverwriteExistingHostType which genuinely needs a second resolveHostMetadata() call. - Use host_type in metadata response instead of experimentalIsUnifiedHost flag (removed by PR #720) to make getClientType() return ACCOUNT. --- .../sdk/core/DatabricksConfigTest.java | 35 ++++--------------- 1 file changed, 7 insertions(+), 28 deletions(-) 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 ebf388c16..c61477a73 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 @@ -668,12 +668,9 @@ public void testResolveHostMetadataPopulatesResolvedHostType() throws IOExceptio + "\"," + "\"host_type\":\"workspace\"}"; 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(HostType.WORKSPACE, config.getResolvedHostType()); } } @@ -707,12 +704,9 @@ public void testResolveHostMetadataUnknownHostTypeIgnored() throws IOException { + "\"," + "\"host_type\":\"unknown_value\"}"; 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(); assertNull(config.getResolvedHostType()); } } @@ -726,12 +720,9 @@ public void testResolveHostMetadataHostTypeAccount() throws IOException { + "\"," + "\"host_type\":\"account\"}"; 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(HostType.ACCOUNTS, config.getResolvedHostType()); } } @@ -745,12 +736,9 @@ public void testResolveHostMetadataHostTypeUnified() throws IOException { + "\"," + "\"host_type\":\"unified\"}"; 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(HostType.UNIFIED, config.getResolvedHostType()); } } @@ -766,12 +754,9 @@ public void testResolveHostMetadataSetsTokenAudienceFromDefaultOidcAudience() th + "\"," + "\"default_oidc_audience\":\"https://ws.databricks.com/oidc/v1/token\"}"; 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("https://ws.databricks.com/oidc/v1/token", config.getTokenAudience()); } } @@ -788,13 +773,10 @@ public void testResolveHostMetadataDefaultOidcAudiencePriorityOverAccountIdFallb + "\"host_type\":\"account\"," + "\"default_oidc_audience\":\"custom-audience\"}"; 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(); // Should use default_oidc_audience, NOT account_id assertEquals("custom-audience", config.getTokenAudience()); } @@ -810,13 +792,10 @@ public void testResolveHostMetadataDoesNotOverrideExistingTokenAudienceWithOidcA + "\"," + "\"default_oidc_audience\":\"metadata-audience\"}"; 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()).setTokenAudience("existing-audience"); config.resolve(emptyEnv()); - config.resolveHostMetadata(); assertEquals("existing-audience", config.getTokenAudience()); } } From 91389f14078b2ea36b699b60dcea9762f129c361 Mon Sep 17 00:00:00 2001 From: Tanmay Rustagi Date: Sat, 11 Apr 2026 13:31:05 +0200 Subject: [PATCH 08/10] Make tests hermetic by using FixtureServer instead of real hostnames - testWorkspaceIdFromEnvironmentVariables: use FixtureServer URL instead of https://mycompany.databricks.com to avoid hitting real /.well-known/databricks-config during resolve(). - testNewWithWorkspaceHost: use FixtureServer URL as workspace host instead of https://workspace.cloud.databricks.com. - Remove unnecessary second fixture from testEndToEndResolveToGetHostType. --- .../sdk/core/DatabricksConfigTest.java | 34 ++++++++++--------- .../databricks/sdk/core/UnifiedHostTest.java | 29 ++++++++-------- 2 files changed, 33 insertions(+), 30 deletions(-) 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 c61477a73..307caadae 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 @@ -173,22 +173,24 @@ public void testDiscoveryEndpoint() throws IOException { } @Test - public void testNewWithWorkspaceHost() { - DatabricksConfig config = - new DatabricksConfig() - .setAuthType("oauth-m2m") - .setClientId("my-client-id") - .setClientSecret("my-client-secret") - .setAccountId("account-id") - .setHost("https://account.cloud.databricks.com"); - String workspaceHost = "https://workspace.cloud.databricks.com"; - - DatabricksConfig newWorkspaceConfig = config.newWithWorkspaceHost(workspaceHost).resolve(); - - assert newWorkspaceConfig.getHost().equals(workspaceHost); - assert newWorkspaceConfig.getAuthType().equals("oauth-m2m"); - assert newWorkspaceConfig.getClientId().equals("my-client-id"); - assert newWorkspaceConfig.getClientSecret().equals("my-client-secret"); + public void testNewWithWorkspaceHost() throws IOException { + try (FixtureServer server = new FixtureServer()) { + String workspaceHost = server.getUrl(); + DatabricksConfig config = + new DatabricksConfig() + .setAuthType("oauth-m2m") + .setClientId("my-client-id") + .setClientSecret("my-client-secret") + .setAccountId("account-id") + .setHost("https://account.cloud.databricks.com"); + + DatabricksConfig newWorkspaceConfig = config.newWithWorkspaceHost(workspaceHost).resolve(); + + assert newWorkspaceConfig.getHost().equals(workspaceHost); + assert newWorkspaceConfig.getAuthType().equals("oauth-m2m"); + assert newWorkspaceConfig.getClientId().equals("my-client-id"); + assert newWorkspaceConfig.getClientSecret().equals("my-client-secret"); + } } @Test diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java index 22cab891f..bf8d94eb7 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java @@ -97,19 +97,21 @@ public void testIsAccountClientForNonAccountsHost() { // --- Environment Variable Tests --- @Test - public void testWorkspaceIdFromEnvironmentVariables() { - Map env = new HashMap<>(); - env.put("DATABRICKS_HOST", "https://mycompany.databricks.com"); - env.put("DATABRICKS_WORKSPACE_ID", "987654321"); - env.put("DATABRICKS_ACCOUNT_ID", "account-abc"); - - DatabricksConfig config = new DatabricksConfig(); - config.resolve(new Environment(env, new ArrayList<>(), System.getProperty("os.name"))); - - assertEquals(HostType.WORKSPACE, config.getHostType()); - assertEquals("987654321", config.getWorkspaceId()); - assertEquals("account-abc", config.getAccountId()); - assertEquals(ClientType.WORKSPACE, config.getClientType()); + public void testWorkspaceIdFromEnvironmentVariables() throws IOException { + try (FixtureServer server = new FixtureServer()) { + Map env = new HashMap<>(); + env.put("DATABRICKS_HOST", server.getUrl()); + env.put("DATABRICKS_WORKSPACE_ID", "987654321"); + env.put("DATABRICKS_ACCOUNT_ID", "account-abc"); + + DatabricksConfig config = new DatabricksConfig(); + config.resolve(new Environment(env, new ArrayList<>(), System.getProperty("os.name"))); + + assertEquals(HostType.WORKSPACE, config.getHostType()); + assertEquals("987654321", config.getWorkspaceId()); + assertEquals("account-abc", config.getAccountId()); + assertEquals(ClientType.WORKSPACE, config.getClientType()); + } } // --- Resolved host type from metadata tests --- @@ -167,7 +169,6 @@ public void testEndToEndResolveToGetHostType() throws IOException { + "\"host_type\":\"unified\"}"; try (FixtureServer server = 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( From 29fa19015b2d1312bc31fa39c3b0d3ef994d18eb Mon Sep 17 00:00:00 2001 From: Tanmay Rustagi Date: Sat, 11 Apr 2026 13:37:28 +0200 Subject: [PATCH 09/10] Make AccountClientTest.testGetWorkspaceClientForUnifiedHost hermetic with FixtureServer Replace real unified.databricks.com hostname with FixtureServer to prevent host metadata resolution from hitting live servers during tests. Co-authored-by: Isaac --- .../com/databricks/sdk/AccountClientTest.java | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) 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 f529d3525..3fae68afc 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 @@ -3,8 +3,10 @@ import static org.junit.jupiter.api.Assertions.*; import com.databricks.sdk.core.DatabricksConfig; +import com.databricks.sdk.core.FixtureServer; import com.databricks.sdk.core.HostType; import com.databricks.sdk.service.provisioning.Workspace; +import java.io.IOException; import org.junit.jupiter.api.Test; public class AccountClientTest { @@ -31,30 +33,32 @@ public void testGetWorkspaceClientForTraditionalAccount() { } @Test - public void testGetWorkspaceClientForUnifiedHost() { - String unifiedHost = "https://unified.databricks.com"; - DatabricksConfig accountConfig = - new DatabricksConfig() - .setHost(unifiedHost) - .setAccountId("test-account") - .setToken("test-token"); + public void testGetWorkspaceClientForUnifiedHost() throws IOException { + try (FixtureServer server = new FixtureServer()) { + String unifiedHost = server.getUrl(); + DatabricksConfig accountConfig = + new DatabricksConfig() + .setHost(unifiedHost) + .setAccountId("test-account") + .setToken("test-token"); - AccountClient accountClient = new AccountClient(accountConfig); + AccountClient accountClient = new AccountClient(accountConfig); - Workspace workspace = new Workspace(); - workspace.setWorkspaceId(123456L); - workspace.setDeploymentName("test-workspace"); + Workspace workspace = new Workspace(); + workspace.setWorkspaceId(123456L); + workspace.setDeploymentName("test-workspace"); - WorkspaceClient workspaceClient = accountClient.getWorkspaceClient(workspace); + WorkspaceClient workspaceClient = accountClient.getWorkspaceClient(workspace); - // Should have the same host (unified hosts reuse the same host) - assertEquals(unifiedHost, workspaceClient.config().getHost()); + // Should have the same host (non-matching DNS zone means SPOG path) + assertEquals(unifiedHost, workspaceClient.config().getHost()); - // Should have workspace ID set - assertEquals("123456", workspaceClient.config().getWorkspaceId()); + // Should have workspace ID set + assertEquals("123456", workspaceClient.config().getWorkspaceId()); - // Host type is WORKSPACE (determined from URL pattern, not unified flag) - assertEquals(HostType.WORKSPACE, workspaceClient.config().getHostType()); + // Host type is WORKSPACE (no resolved host type from metadata, URL doesn't match accounts pattern) + assertEquals(HostType.WORKSPACE, workspaceClient.config().getHostType()); + } } @Test From 48a405cfeeb53200651d4bd64a9ac93bb10096ff Mon Sep 17 00:00:00 2001 From: Tanmay Rustagi Date: Sat, 11 Apr 2026 13:54:47 +0200 Subject: [PATCH 10/10] Fix Spotless formatting in AccountClientTest, DatabricksConfigTest, UnifiedHostTest Co-authored-by: Isaac --- .../test/java/com/databricks/sdk/AccountClientTest.java | 3 ++- .../java/com/databricks/sdk/core/DatabricksConfigTest.java | 7 ++----- .../test/java/com/databricks/sdk/core/UnifiedHostTest.java | 3 +-- 3 files changed, 5 insertions(+), 8 deletions(-) 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 3fae68afc..5ff637d65 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 @@ -56,7 +56,8 @@ public void testGetWorkspaceClientForUnifiedHost() throws IOException { // Should have workspace ID set assertEquals("123456", workspaceClient.config().getWorkspaceId()); - // Host type is WORKSPACE (no resolved host type from metadata, URL doesn't match accounts pattern) + // Host type is WORKSPACE (no resolved host type from metadata, URL doesn't match accounts + // pattern) assertEquals(HostType.WORKSPACE, workspaceClient.config().getHostType()); } } 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 307caadae..c2738d2e2 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 @@ -814,12 +814,9 @@ public void testResolveHostMetadataFallsBackToAccountIdWhenNoDefaultOidcAudience + "\"," + "\"host_type\":\"account\"}"; try (FixtureServer server = - new FixtureServer() - .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); + new DatabricksConfig().setHost(server.getUrl()).setAccountId(DUMMY_ACCOUNT_ID); config.resolve(emptyEnv()); // resolve() triggers tryResolveHostMetadata() which sets resolvedHostType=ACCOUNTS, // then the tokenAudience fallback sets tokenAudience to accountId. diff --git a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java index bf8d94eb7..752ad0719 100644 --- a/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java +++ b/databricks-sdk-java/src/test/java/com/databricks/sdk/core/UnifiedHostTest.java @@ -168,8 +168,7 @@ public void testEndToEndResolveToGetHostType() throws IOException { + "\"account_id\":\"test-account\"," + "\"host_type\":\"unified\"}"; try (FixtureServer server = - new FixtureServer() - .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( new Environment(new HashMap<>(), new ArrayList<>(), System.getProperty("os.name")));