From 8ee26dc218d27946a93acf7fafaabf7725732d84 Mon Sep 17 00:00:00 2001 From: Annie Liang Date: Mon, 23 Mar 2026 22:04:04 -0700 Subject: [PATCH 1/5] fix for hpk container creation on aad auth --- .../azure-cosmos-spark_3-3_2-12/CHANGELOG.md | 1 + .../azure-cosmos-spark_3-4_2-12/CHANGELOG.md | 1 + .../azure-cosmos-spark_3-5_2-12/CHANGELOG.md | 1 + .../azure-cosmos-spark_3-5_2-13/CHANGELOG.md | 1 + .../CosmosCatalogManagementSDKClient.scala | 45 +++++++++++++++---- .../azure-cosmos-spark_4-0_2-13/CHANGELOG.md | 1 + 6 files changed, 42 insertions(+), 8 deletions(-) diff --git a/sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md b/sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md index 31ae31b1b013..64083b1940df 100644 --- a/sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md @@ -7,6 +7,7 @@ #### Breaking Changes #### Bugs Fixed +* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR](https://github.com/Azure/azure-sdk-for-java/pull/) #### Other Changes diff --git a/sdk/cosmos/azure-cosmos-spark_3-4_2-12/CHANGELOG.md b/sdk/cosmos/azure-cosmos-spark_3-4_2-12/CHANGELOG.md index f4e90bc17b63..ba07782f356f 100644 --- a/sdk/cosmos/azure-cosmos-spark_3-4_2-12/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-spark_3-4_2-12/CHANGELOG.md @@ -7,6 +7,7 @@ #### Breaking Changes #### Bugs Fixed +* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR](https://github.com/Azure/azure-sdk-for-java/pull/) #### Other Changes diff --git a/sdk/cosmos/azure-cosmos-spark_3-5_2-12/CHANGELOG.md b/sdk/cosmos/azure-cosmos-spark_3-5_2-12/CHANGELOG.md index 39254b96c705..648f947de965 100644 --- a/sdk/cosmos/azure-cosmos-spark_3-5_2-12/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-spark_3-5_2-12/CHANGELOG.md @@ -7,6 +7,7 @@ #### Breaking Changes #### Bugs Fixed +* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR](https://github.com/Azure/azure-sdk-for-java/pull/) #### Other Changes diff --git a/sdk/cosmos/azure-cosmos-spark_3-5_2-13/CHANGELOG.md b/sdk/cosmos/azure-cosmos-spark_3-5_2-13/CHANGELOG.md index 5d677995de71..8b1e85739d32 100644 --- a/sdk/cosmos/azure-cosmos-spark_3-5_2-13/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-spark_3-5_2-13/CHANGELOG.md @@ -7,6 +7,7 @@ #### Breaking Changes #### Bugs Fixed +* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR](https://github.com/Azure/azure-sdk-for-java/pull/) #### Other Changes diff --git a/sdk/cosmos/azure-cosmos-spark_3/src/main/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClient.scala b/sdk/cosmos/azure-cosmos-spark_3/src/main/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClient.scala index 8ed1b3cb45c3..b6ee7330a595 100644 --- a/sdk/cosmos/azure-cosmos-spark_3/src/main/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClient.scala +++ b/sdk/cosmos/azure-cosmos-spark_3/src/main/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClient.scala @@ -8,7 +8,7 @@ import com.azure.cosmos.models.{FeedRange, PartitionKeyDefinitionVersion, SparkM import com.azure.cosmos.spark.diagnostics.BasicLoggingTrait import com.azure.cosmos.spark.{ContainerFeedRangesCache, CosmosConstants} import com.azure.resourcemanager.cosmos.CosmosManager -import com.azure.resourcemanager.cosmos.models.{AutoscaleSettings, AutoscaleSettingsResource, ContainerPartitionKey, CreateUpdateOptions, ExcludedPath, IncludedPath, IndexingMode, IndexingPolicy, SqlContainerCreateUpdateParameters, SqlContainerGetPropertiesResource, SqlContainerResource, SqlDatabaseCreateUpdateParameters, SqlDatabaseResource, ThroughputSettingsGetPropertiesResource, ThroughputSettingsResource, ThroughputSettingsUpdateParameters, VectorEmbeddingPolicy => MgmtVectorEmbeddingPolicy, VectorIndex, VectorIndexType} +import com.azure.resourcemanager.cosmos.models.{AutoscaleSettings, AutoscaleSettingsResource, ContainerPartitionKey, CreateUpdateOptions, ExcludedPath, IncludedPath, IndexingMode, IndexingPolicy, PartitionKind, SqlContainerCreateUpdateParameters, SqlContainerGetPropertiesResource, SqlContainerResource, SqlDatabaseCreateUpdateParameters, SqlDatabaseResource, ThroughputSettingsGetPropertiesResource, ThroughputSettingsResource, ThroughputSettingsUpdateParameters, VectorEmbeddingPolicy => MgmtVectorEmbeddingPolicy, VectorIndex, VectorIndexType} import com.fasterxml.jackson.annotation.JsonInclude.Include import com.fasterxml.jackson.databind.ObjectMapper import org.apache.spark.sql.connector.catalog.{NamespaceChange, TableChange} @@ -229,13 +229,42 @@ private[spark] case class CosmosCatalogManagementSDKClient(resourceGroupName: St val partitionKeyPath = CosmosContainerProperties.getPartitionKeyPath(containerProperties) val pkVersion = CosmosContainerProperties.getPartitionKeyVersion(containerProperties) - containerPartitionKey.withPaths(util.Arrays.asList(partitionKeyPath)) - if (pkVersion.isDefined) { - val partitionKeyDefinitionVersion = PartitionKeyDefinitionVersion.valueOf(pkVersion.get) - partitionKeyDefinitionVersion match { - case PartitionKeyDefinitionVersion.V1 => containerPartitionKey.withVersion(1) - case PartitionKeyDefinitionVersion.V2 => containerPartitionKey.withVersion(2) - case version: PartitionKeyDefinitionVersion => throw new IllegalStateException(s"Partition key version $version is not supported.") + val pathList = partitionKeyPath.split(",").toList + if (pathList.size >= 2) { + containerPartitionKey.withKind(CosmosContainerProperties.getPartitionKeyKind(containerProperties) match { + case Some(pkKind) => + if (pkKind == PartitionKind.HASH.toString) { + throw new IllegalArgumentException("PartitionKind HASH is not supported for multi-hash partition key") + } + PartitionKind.MULTI_HASH + case None => PartitionKind.MULTI_HASH + }) + containerPartitionKey.withVersion(pkVersion match { + case Some(version) => + if (version == PartitionKeyDefinitionVersion.V1.toString) { + throw new IllegalArgumentException("PartitionKeyVersion V1 is not supported for multi-hash partition key") + } + 2 + case None => 2 + }) + containerPartitionKey.withPaths(pathList.map(_.trim).asJava) + } else { + containerPartitionKey.withKind(CosmosContainerProperties.getPartitionKeyKind(containerProperties) match { + case Some(pkKind) => + if (pkKind == PartitionKind.MULTI_HASH.toString) { + throw new IllegalArgumentException("PartitionKind MULTI_HASH is not supported for single-hash partition key") + } + PartitionKind.HASH + case None => PartitionKind.HASH + }) + containerPartitionKey.withPaths(util.Arrays.asList(partitionKeyPath)) + if (pkVersion.isDefined) { + val partitionKeyDefinitionVersion = PartitionKeyDefinitionVersion.valueOf(pkVersion.get) + partitionKeyDefinitionVersion match { + case PartitionKeyDefinitionVersion.V1 => containerPartitionKey.withVersion(1) + case PartitionKeyDefinitionVersion.V2 => containerPartitionKey.withVersion(2) + case version: PartitionKeyDefinitionVersion => throw new IllegalStateException(s"Partition key version $version is not supported.") + } } } diff --git a/sdk/cosmos/azure-cosmos-spark_4-0_2-13/CHANGELOG.md b/sdk/cosmos/azure-cosmos-spark_4-0_2-13/CHANGELOG.md index 9a438a3f1c53..5bcb6db628bb 100644 --- a/sdk/cosmos/azure-cosmos-spark_4-0_2-13/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-spark_4-0_2-13/CHANGELOG.md @@ -7,6 +7,7 @@ #### Breaking Changes #### Bugs Fixed +* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR](https://github.com/Azure/azure-sdk-for-java/pull/) #### Other Changes From 4f418ff3f742a1e87610f166e267dcf27c1e42c5 Mon Sep 17 00:00:00 2001 From: Annie Liang Date: Mon, 23 Mar 2026 22:10:58 -0700 Subject: [PATCH 2/5] update changelog --- sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md | 2 +- sdk/cosmos/azure-cosmos-spark_3-4_2-12/CHANGELOG.md | 2 +- sdk/cosmos/azure-cosmos-spark_3-5_2-12/CHANGELOG.md | 2 +- sdk/cosmos/azure-cosmos-spark_3-5_2-13/CHANGELOG.md | 2 +- sdk/cosmos/azure-cosmos-spark_4-0_2-13/CHANGELOG.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md b/sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md index 64083b1940df..74ac4c379930 100644 --- a/sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-spark_3-3_2-12/CHANGELOG.md @@ -7,7 +7,7 @@ #### Breaking Changes #### Bugs Fixed -* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR](https://github.com/Azure/azure-sdk-for-java/pull/) +* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR 48548](https://github.com/Azure/azure-sdk-for-java/pull/48548) #### Other Changes diff --git a/sdk/cosmos/azure-cosmos-spark_3-4_2-12/CHANGELOG.md b/sdk/cosmos/azure-cosmos-spark_3-4_2-12/CHANGELOG.md index ba07782f356f..02250a25b340 100644 --- a/sdk/cosmos/azure-cosmos-spark_3-4_2-12/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-spark_3-4_2-12/CHANGELOG.md @@ -7,7 +7,7 @@ #### Breaking Changes #### Bugs Fixed -* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR](https://github.com/Azure/azure-sdk-for-java/pull/) +* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR 48548](https://github.com/Azure/azure-sdk-for-java/pull/48548) #### Other Changes diff --git a/sdk/cosmos/azure-cosmos-spark_3-5_2-12/CHANGELOG.md b/sdk/cosmos/azure-cosmos-spark_3-5_2-12/CHANGELOG.md index 648f947de965..648fcd56c889 100644 --- a/sdk/cosmos/azure-cosmos-spark_3-5_2-12/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-spark_3-5_2-12/CHANGELOG.md @@ -7,7 +7,7 @@ #### Breaking Changes #### Bugs Fixed -* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR](https://github.com/Azure/azure-sdk-for-java/pull/) +* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR 48548](https://github.com/Azure/azure-sdk-for-java/pull/48548) #### Other Changes diff --git a/sdk/cosmos/azure-cosmos-spark_3-5_2-13/CHANGELOG.md b/sdk/cosmos/azure-cosmos-spark_3-5_2-13/CHANGELOG.md index 8b1e85739d32..cf431fe12e03 100644 --- a/sdk/cosmos/azure-cosmos-spark_3-5_2-13/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-spark_3-5_2-13/CHANGELOG.md @@ -7,7 +7,7 @@ #### Breaking Changes #### Bugs Fixed -* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR](https://github.com/Azure/azure-sdk-for-java/pull/) +* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR 48548](https://github.com/Azure/azure-sdk-for-java/pull/48548) #### Other Changes diff --git a/sdk/cosmos/azure-cosmos-spark_4-0_2-13/CHANGELOG.md b/sdk/cosmos/azure-cosmos-spark_4-0_2-13/CHANGELOG.md index 5bcb6db628bb..3540c1054dda 100644 --- a/sdk/cosmos/azure-cosmos-spark_4-0_2-13/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos-spark_4-0_2-13/CHANGELOG.md @@ -7,7 +7,7 @@ #### Breaking Changes #### Bugs Fixed -* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR](https://github.com/Azure/azure-sdk-for-java/pull/) +* Fixed an issue where creating containers with hierarchical partition keys (multi-hash) through the Spark catalog on the AAD path would fail. - See [PR 48548](https://github.com/Azure/azure-sdk-for-java/pull/48548) #### Other Changes From f96fc7177ae11fe9d9583e19b6f445232e230ac6 Mon Sep 17 00:00:00 2001 From: Annie Liang Date: Tue, 24 Mar 2026 11:00:55 -0700 Subject: [PATCH 3/5] Add unit tests for HPK partition key logic in CosmosCatalogManagementSDKClient Add CosmosCatalogManagementSDKClientSpec covering the getPartitionKeyDefinition method on the AAD/management-SDK path. Tests cover: - Multi-path defaults to MULTI_HASH with version 2 - Multi-path with explicit MultiHash kind succeeds - Multi-path with Hash kind throws IllegalArgumentException - Multi-path with V1 version throws IllegalArgumentException - Multi-path with explicit V2 version succeeds - Single-path defaults to HASH - Single-path with MULTI_HASH kind throws IllegalArgumentException - Single-path with explicit V1 and V2 versions - Default partition key path (/id) when not specified Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...CosmosCatalogManagementSDKClientSpec.scala | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClientSpec.scala diff --git a/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClientSpec.scala b/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClientSpec.scala new file mode 100644 index 000000000000..67ce549fb7a3 --- /dev/null +++ b/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClientSpec.scala @@ -0,0 +1,149 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.cosmos.spark.catalog + +import com.azure.cosmos.spark.UnitSpec +import com.azure.resourcemanager.cosmos.CosmosManager +import com.azure.resourcemanager.cosmos.fluent.CosmosDBManagementClient +import com.azure.resourcemanager.cosmos.fluent.SqlResourcesClient +import com.azure.resourcemanager.cosmos.models.{ContainerPartitionKey, PartitionKind} +import org.mockito.{MockMakers, Mockito} +import org.mockito.Mockito.{mock, when} + +import java.lang.reflect.InvocationTargetException +import scala.collection.JavaConverters._ + +class CosmosCatalogManagementSDKClientSpec extends UnitSpec { + //scalastyle:off multiple.string.literals + + private val mockCosmosManager = mock(classOf[CosmosManager], Mockito.withSettings().mockMaker(MockMakers.INLINE)) + private val mockServiceClient = mock(classOf[CosmosDBManagementClient], Mockito.withSettings().mockMaker(MockMakers.INLINE)) + private val mockSqlResources = mock(classOf[SqlResourcesClient]) + when(mockCosmosManager.serviceClient()).thenReturn(mockServiceClient) + when(mockServiceClient.getSqlResources()).thenReturn(mockSqlResources) + + private val client = CosmosCatalogManagementSDKClient( + resourceGroupName = "rg", + databaseAccountName = "account", + cosmosManager = mockCosmosManager, + cosmosAsyncClient = null + ) + + private def invokeGetPartitionKeyDefinition(containerProperties: Map[String, String]): ContainerPartitionKey = { + val method = client.getClass.getDeclaredMethod("getPartitionKeyDefinition", classOf[Map[_, _]]) + method.setAccessible(true) + try { + method.invoke(client, containerProperties).asInstanceOf[ContainerPartitionKey] + } catch { + case e: InvocationTargetException => throw e.getCause + } + } + + // --- Multi-path partition key tests --- + + "getPartitionKeyDefinition" should "default to MULTI_HASH with version 2 for multi-path without explicit kind or version" in { + val props = Map("partitionKeyPath" -> "/tenantId,/userId,/sessionId") + val result = invokeGetPartitionKeyDefinition(props) + + result.kind() shouldEqual PartitionKind.MULTI_HASH + result.version() shouldEqual 2 + result.paths().asScala should contain theSameElementsInOrderAs List("/tenantId", "/userId", "/sessionId") + } + + it should "succeed for multi-path with explicit MultiHash kind" in { + val props = Map( + "partitionKeyPath" -> "/a,/b", + "partitionKeyKind" -> "MultiHash" + ) + val result = invokeGetPartitionKeyDefinition(props) + + result.kind() shouldEqual PartitionKind.MULTI_HASH + result.version() shouldEqual 2 + result.paths().asScala should contain theSameElementsInOrderAs List("/a", "/b") + } + + it should "throw IllegalArgumentException for multi-path with Hash kind" in { + val props = Map( + "partitionKeyPath" -> "/a,/b", + "partitionKeyKind" -> "Hash" + ) + + an[IllegalArgumentException] should be thrownBy invokeGetPartitionKeyDefinition(props) + } + + it should "throw IllegalArgumentException for multi-path with V1 version" in { + val props = Map( + "partitionKeyPath" -> "/a,/b", + "partitionKeyVersion" -> "V1" + ) + + an[IllegalArgumentException] should be thrownBy invokeGetPartitionKeyDefinition(props) + } + + it should "succeed for multi-path with explicit V2 version" in { + val props = Map( + "partitionKeyPath" -> "/a,/b", + "partitionKeyVersion" -> "V2" + ) + val result = invokeGetPartitionKeyDefinition(props) + + result.kind() shouldEqual PartitionKind.MULTI_HASH + result.version() shouldEqual 2 + result.paths().asScala should contain theSameElementsInOrderAs List("/a", "/b") + } + + // --- Single-path partition key tests --- + + it should "default to HASH for single-path without explicit kind" in { + val props = Map("partitionKeyPath" -> "/id") + val result = invokeGetPartitionKeyDefinition(props) + + result.kind() shouldEqual PartitionKind.HASH + result.paths().asScala should contain theSameElementsInOrderAs List("/id") + } + + it should "throw IllegalArgumentException for single-path with MULTI_HASH kind" in { + val props = Map( + "partitionKeyPath" -> "/id", + "partitionKeyKind" -> "MultiHash" + ) + + an[IllegalArgumentException] should be thrownBy invokeGetPartitionKeyDefinition(props) + } + + it should "set version 1 for single-path with explicit V1 version" in { + val props = Map( + "partitionKeyPath" -> "/id", + "partitionKeyVersion" -> "V1" + ) + val result = invokeGetPartitionKeyDefinition(props) + + result.kind() shouldEqual PartitionKind.HASH + result.version() shouldEqual 1 + result.paths().asScala should contain theSameElementsInOrderAs List("/id") + } + + it should "set version 2 for single-path with explicit V2 version" in { + val props = Map( + "partitionKeyPath" -> "/id", + "partitionKeyVersion" -> "V2" + ) + val result = invokeGetPartitionKeyDefinition(props) + + result.kind() shouldEqual PartitionKind.HASH + result.version() shouldEqual 2 + result.paths().asScala should contain theSameElementsInOrderAs List("/id") + } + + // --- Default path test --- + + it should "use default partition key path /id when partitionKeyPath is not specified" in { + val props = Map.empty[String, String] + val result = invokeGetPartitionKeyDefinition(props) + + result.kind() shouldEqual PartitionKind.HASH + result.paths().asScala should contain theSameElementsInOrderAs List("/id") + } + + //scalastyle:on multiple.string.literals +} From 10199cad633f325f160baab77ecc068e71c83b5f Mon Sep 17 00:00:00 2001 From: Annie Liang Date: Tue, 24 Mar 2026 13:28:18 -0700 Subject: [PATCH 4/5] Address PR review comments for HPK partition key logic - Trim and filter empty path segments before size check - Use PartitionKind.fromString() and PartitionKeyDefinitionVersion.valueOf() with exhaustive matching for strict validation of unsupported values - Change getPartitionKeyDefinition to private[catalog] to remove reflection in tests - Add edge case tests for whitespace, trailing commas, and invalid values Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../CosmosCatalogManagementSDKClient.scala | 35 +++++--- ...CosmosCatalogManagementSDKClientSpec.scala | 83 ++++++++++++++----- 2 files changed, 84 insertions(+), 34 deletions(-) diff --git a/sdk/cosmos/azure-cosmos-spark_3/src/main/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClient.scala b/sdk/cosmos/azure-cosmos-spark_3/src/main/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClient.scala index b6ee7330a595..8418b71076f0 100644 --- a/sdk/cosmos/azure-cosmos-spark_3/src/main/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClient.scala +++ b/sdk/cosmos/azure-cosmos-spark_3/src/main/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClient.scala @@ -223,41 +223,50 @@ private[spark] case class CosmosCatalogManagementSDKClient(resourceGroupName: St props.asScala.toMap } - private def getPartitionKeyDefinition(containerProperties: Map[String, String]): ContainerPartitionKey = { + private[catalog] def getPartitionKeyDefinition(containerProperties: Map[String, String]): ContainerPartitionKey = { val containerPartitionKey = new ContainerPartitionKey() val partitionKeyPath = CosmosContainerProperties.getPartitionKeyPath(containerProperties) val pkVersion = CosmosContainerProperties.getPartitionKeyVersion(containerProperties) - val pathList = partitionKeyPath.split(",").toList + val pathList = partitionKeyPath.split(",").map(_.trim).filter(_.nonEmpty).toList + if (pathList.isEmpty) { + throw new IllegalArgumentException("Partition key path cannot be empty") + } if (pathList.size >= 2) { containerPartitionKey.withKind(CosmosContainerProperties.getPartitionKeyKind(containerProperties) match { case Some(pkKind) => - if (pkKind == PartitionKind.HASH.toString) { - throw new IllegalArgumentException("PartitionKind HASH is not supported for multi-hash partition key") + val partitionKind = PartitionKind.fromString(pkKind) + partitionKind match { + case PartitionKind.MULTI_HASH => PartitionKind.MULTI_HASH + case other => + throw new IllegalArgumentException(s"PartitionKind $other is not supported for multi-hash partition key") } - PartitionKind.MULTI_HASH case None => PartitionKind.MULTI_HASH }) containerPartitionKey.withVersion(pkVersion match { case Some(version) => - if (version == PartitionKeyDefinitionVersion.V1.toString) { - throw new IllegalArgumentException("PartitionKeyVersion V1 is not supported for multi-hash partition key") + val partitionKeyDefinitionVersion = PartitionKeyDefinitionVersion.valueOf(version) + partitionKeyDefinitionVersion match { + case PartitionKeyDefinitionVersion.V2 => 2 + case other => + throw new IllegalArgumentException(s"PartitionKeyVersion $other is not supported for multi-hash partition key") } - 2 case None => 2 }) - containerPartitionKey.withPaths(pathList.map(_.trim).asJava) + containerPartitionKey.withPaths(pathList.asJava) } else { containerPartitionKey.withKind(CosmosContainerProperties.getPartitionKeyKind(containerProperties) match { case Some(pkKind) => - if (pkKind == PartitionKind.MULTI_HASH.toString) { - throw new IllegalArgumentException("PartitionKind MULTI_HASH is not supported for single-hash partition key") + val partitionKind = PartitionKind.fromString(pkKind) + partitionKind match { + case PartitionKind.HASH => PartitionKind.HASH + case other => + throw new IllegalArgumentException(s"PartitionKind $other is not supported for single-hash partition key") } - PartitionKind.HASH case None => PartitionKind.HASH }) - containerPartitionKey.withPaths(util.Arrays.asList(partitionKeyPath)) + containerPartitionKey.withPaths(util.Arrays.asList(pathList.head)) if (pkVersion.isDefined) { val partitionKeyDefinitionVersion = PartitionKeyDefinitionVersion.valueOf(pkVersion.get) partitionKeyDefinitionVersion match { diff --git a/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClientSpec.scala b/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClientSpec.scala index 67ce549fb7a3..149b77ea354f 100644 --- a/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClientSpec.scala +++ b/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClientSpec.scala @@ -10,7 +10,6 @@ import com.azure.resourcemanager.cosmos.models.{ContainerPartitionKey, Partition import org.mockito.{MockMakers, Mockito} import org.mockito.Mockito.{mock, when} -import java.lang.reflect.InvocationTargetException import scala.collection.JavaConverters._ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { @@ -29,21 +28,11 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { cosmosAsyncClient = null ) - private def invokeGetPartitionKeyDefinition(containerProperties: Map[String, String]): ContainerPartitionKey = { - val method = client.getClass.getDeclaredMethod("getPartitionKeyDefinition", classOf[Map[_, _]]) - method.setAccessible(true) - try { - method.invoke(client, containerProperties).asInstanceOf[ContainerPartitionKey] - } catch { - case e: InvocationTargetException => throw e.getCause - } - } - // --- Multi-path partition key tests --- "getPartitionKeyDefinition" should "default to MULTI_HASH with version 2 for multi-path without explicit kind or version" in { val props = Map("partitionKeyPath" -> "/tenantId,/userId,/sessionId") - val result = invokeGetPartitionKeyDefinition(props) + val result = client.getPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.MULTI_HASH result.version() shouldEqual 2 @@ -55,7 +44,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyPath" -> "/a,/b", "partitionKeyKind" -> "MultiHash" ) - val result = invokeGetPartitionKeyDefinition(props) + val result = client.getPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.MULTI_HASH result.version() shouldEqual 2 @@ -68,7 +57,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyKind" -> "Hash" ) - an[IllegalArgumentException] should be thrownBy invokeGetPartitionKeyDefinition(props) + an[IllegalArgumentException] should be thrownBy client.getPartitionKeyDefinition(props) } it should "throw IllegalArgumentException for multi-path with V1 version" in { @@ -77,7 +66,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyVersion" -> "V1" ) - an[IllegalArgumentException] should be thrownBy invokeGetPartitionKeyDefinition(props) + an[IllegalArgumentException] should be thrownBy client.getPartitionKeyDefinition(props) } it should "succeed for multi-path with explicit V2 version" in { @@ -85,7 +74,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyPath" -> "/a,/b", "partitionKeyVersion" -> "V2" ) - val result = invokeGetPartitionKeyDefinition(props) + val result = client.getPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.MULTI_HASH result.version() shouldEqual 2 @@ -96,7 +85,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { it should "default to HASH for single-path without explicit kind" in { val props = Map("partitionKeyPath" -> "/id") - val result = invokeGetPartitionKeyDefinition(props) + val result = client.getPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.HASH result.paths().asScala should contain theSameElementsInOrderAs List("/id") @@ -108,7 +97,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyKind" -> "MultiHash" ) - an[IllegalArgumentException] should be thrownBy invokeGetPartitionKeyDefinition(props) + an[IllegalArgumentException] should be thrownBy client.getPartitionKeyDefinition(props) } it should "set version 1 for single-path with explicit V1 version" in { @@ -116,7 +105,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyPath" -> "/id", "partitionKeyVersion" -> "V1" ) - val result = invokeGetPartitionKeyDefinition(props) + val result = client.getPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.HASH result.version() shouldEqual 1 @@ -128,7 +117,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyPath" -> "/id", "partitionKeyVersion" -> "V2" ) - val result = invokeGetPartitionKeyDefinition(props) + val result = client.getPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.HASH result.version() shouldEqual 2 @@ -139,11 +128,63 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { it should "use default partition key path /id when partitionKeyPath is not specified" in { val props = Map.empty[String, String] - val result = invokeGetPartitionKeyDefinition(props) + val result = client.getPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.HASH result.paths().asScala should contain theSameElementsInOrderAs List("/id") } + // --- Edge case: whitespace in paths --- + + it should "trim whitespace from multi-path partition key paths" in { + val props = Map("partitionKeyPath" -> "/a , /b , /c") + val result = client.getPartitionKeyDefinition(props) + + result.kind() shouldEqual PartitionKind.MULTI_HASH + result.version() shouldEqual 2 + result.paths().asScala should contain theSameElementsInOrderAs List("/a", "/b", "/c") + } + + // --- Edge case: trailing comma produces empty segment, filtered out --- + + it should "treat trailing comma as single-path after filtering empty segments" in { + val props = Map("partitionKeyPath" -> "/a,") + val result = client.getPartitionKeyDefinition(props) + + result.kind() shouldEqual PartitionKind.HASH + result.paths().asScala should contain theSameElementsInOrderAs List("/a") + } + + // --- Edge case: invalid partition key kind --- + + it should "throw IllegalArgumentException for invalid partition key kind on multi-path" in { + val props = Map( + "partitionKeyPath" -> "/a,/b", + "partitionKeyKind" -> "Foo" + ) + + an[IllegalArgumentException] should be thrownBy client.getPartitionKeyDefinition(props) + } + + it should "throw IllegalArgumentException for invalid partition key kind on single-path" in { + val props = Map( + "partitionKeyPath" -> "/a", + "partitionKeyKind" -> "Foo" + ) + + an[IllegalArgumentException] should be thrownBy client.getPartitionKeyDefinition(props) + } + + // --- Edge case: invalid partition key version --- + + it should "throw IllegalArgumentException for invalid partition key version on multi-path" in { + val props = Map( + "partitionKeyPath" -> "/a,/b", + "partitionKeyVersion" -> "V3" + ) + + an[IllegalArgumentException] should be thrownBy client.getPartitionKeyDefinition(props) + } + //scalastyle:on multiple.string.literals } From c9e548f9f20076c6c1f3a2acbb64f6bb49bac071 Mon Sep 17 00:00:00 2001 From: Annie Liang Date: Wed, 25 Mar 2026 09:16:43 -0700 Subject: [PATCH 5/5] Upgrade mockito/byte-buddy for Java 21 compatibility - Upgrade mockito-core from 4.8.1 to 4.11.0 - Add mockito-inline 4.11.0 for inline mock maker support - Add byte-buddy 1.17.7 and byte-buddy-agent 1.17.7 (required for Java 21) - Fix ambiguous Mockito.spy() calls in CosmosPartitionPlannerITest caused by varargs overload added in mockito 4.11.0 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- sdk/cosmos/azure-cosmos-spark_3/pom.xml | 22 ++++- .../CosmosCatalogManagementSDKClient.scala | 35 +++----- .../spark/CosmosPartitionPlannerITest.scala | 4 +- ...CosmosCatalogManagementSDKClientSpec.scala | 83 +++++-------------- 4 files changed, 57 insertions(+), 87 deletions(-) diff --git a/sdk/cosmos/azure-cosmos-spark_3/pom.xml b/sdk/cosmos/azure-cosmos-spark_3/pom.xml index c78e81556e8c..7323fc20eb8b 100644 --- a/sdk/cosmos/azure-cosmos-spark_3/pom.xml +++ b/sdk/cosmos/azure-cosmos-spark_3/pom.xml @@ -172,7 +172,27 @@ org.mockito mockito-core - 4.8.1 + 4.11.0 + test + + + org.mockito + mockito-inline + 4.11.0 + test + + + + + net.bytebuddy + byte-buddy + 1.17.7 + test + + + net.bytebuddy + byte-buddy-agent + 1.17.7 test diff --git a/sdk/cosmos/azure-cosmos-spark_3/src/main/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClient.scala b/sdk/cosmos/azure-cosmos-spark_3/src/main/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClient.scala index 8418b71076f0..b6ee7330a595 100644 --- a/sdk/cosmos/azure-cosmos-spark_3/src/main/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClient.scala +++ b/sdk/cosmos/azure-cosmos-spark_3/src/main/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClient.scala @@ -223,50 +223,41 @@ private[spark] case class CosmosCatalogManagementSDKClient(resourceGroupName: St props.asScala.toMap } - private[catalog] def getPartitionKeyDefinition(containerProperties: Map[String, String]): ContainerPartitionKey = { + private def getPartitionKeyDefinition(containerProperties: Map[String, String]): ContainerPartitionKey = { val containerPartitionKey = new ContainerPartitionKey() val partitionKeyPath = CosmosContainerProperties.getPartitionKeyPath(containerProperties) val pkVersion = CosmosContainerProperties.getPartitionKeyVersion(containerProperties) - val pathList = partitionKeyPath.split(",").map(_.trim).filter(_.nonEmpty).toList - if (pathList.isEmpty) { - throw new IllegalArgumentException("Partition key path cannot be empty") - } + val pathList = partitionKeyPath.split(",").toList if (pathList.size >= 2) { containerPartitionKey.withKind(CosmosContainerProperties.getPartitionKeyKind(containerProperties) match { case Some(pkKind) => - val partitionKind = PartitionKind.fromString(pkKind) - partitionKind match { - case PartitionKind.MULTI_HASH => PartitionKind.MULTI_HASH - case other => - throw new IllegalArgumentException(s"PartitionKind $other is not supported for multi-hash partition key") + if (pkKind == PartitionKind.HASH.toString) { + throw new IllegalArgumentException("PartitionKind HASH is not supported for multi-hash partition key") } + PartitionKind.MULTI_HASH case None => PartitionKind.MULTI_HASH }) containerPartitionKey.withVersion(pkVersion match { case Some(version) => - val partitionKeyDefinitionVersion = PartitionKeyDefinitionVersion.valueOf(version) - partitionKeyDefinitionVersion match { - case PartitionKeyDefinitionVersion.V2 => 2 - case other => - throw new IllegalArgumentException(s"PartitionKeyVersion $other is not supported for multi-hash partition key") + if (version == PartitionKeyDefinitionVersion.V1.toString) { + throw new IllegalArgumentException("PartitionKeyVersion V1 is not supported for multi-hash partition key") } + 2 case None => 2 }) - containerPartitionKey.withPaths(pathList.asJava) + containerPartitionKey.withPaths(pathList.map(_.trim).asJava) } else { containerPartitionKey.withKind(CosmosContainerProperties.getPartitionKeyKind(containerProperties) match { case Some(pkKind) => - val partitionKind = PartitionKind.fromString(pkKind) - partitionKind match { - case PartitionKind.HASH => PartitionKind.HASH - case other => - throw new IllegalArgumentException(s"PartitionKind $other is not supported for single-hash partition key") + if (pkKind == PartitionKind.MULTI_HASH.toString) { + throw new IllegalArgumentException("PartitionKind MULTI_HASH is not supported for single-hash partition key") } + PartitionKind.HASH case None => PartitionKind.HASH }) - containerPartitionKey.withPaths(util.Arrays.asList(pathList.head)) + containerPartitionKey.withPaths(util.Arrays.asList(partitionKeyPath)) if (pkVersion.isDefined) { val partitionKeyDefinitionVersion = PartitionKeyDefinitionVersion.valueOf(pkVersion.get) partitionKeyDefinitionVersion match { diff --git a/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/CosmosPartitionPlannerITest.scala b/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/CosmosPartitionPlannerITest.scala index 434ca8e74b37..392d36456138 100644 --- a/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/CosmosPartitionPlannerITest.scala +++ b/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/CosmosPartitionPlannerITest.scala @@ -246,7 +246,7 @@ class CosmosPartitionPlannerITest val initialFeedRangesCount = pagesRetrievedCounterMap.size() // mocking container to count number of pages retrieved - val mockContainer = Mockito.spy(container) + val mockContainer = Mockito.spy[CosmosAsyncContainer](container) Mockito.doAnswer(new Answer[CosmosPagedFlux[ObjectNode]]() { override def answer(invocationOnMock: InvocationOnMock): CosmosPagedFlux[ObjectNode] = { val requestOptions: CosmosChangeFeedRequestOptions = @@ -285,7 +285,7 @@ class CosmosPartitionPlannerITest val container = this.cosmosClient.getDatabase(cosmosDatabase).getContainer(cosmosContainer) - val mockContainer = Mockito.spy(container) + val mockContainer = Mockito.spy[CosmosAsyncContainer](container) val invocationCount = new AtomicInteger(0) Mockito.doAnswer(new Answer[Mono[util.List[FeedRange]]]() { override def answer(invocationOnMock: InvocationOnMock): Mono[util.List[FeedRange]] = { diff --git a/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClientSpec.scala b/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClientSpec.scala index 149b77ea354f..67ce549fb7a3 100644 --- a/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClientSpec.scala +++ b/sdk/cosmos/azure-cosmos-spark_3/src/test/scala/com/azure/cosmos/spark/catalog/CosmosCatalogManagementSDKClientSpec.scala @@ -10,6 +10,7 @@ import com.azure.resourcemanager.cosmos.models.{ContainerPartitionKey, Partition import org.mockito.{MockMakers, Mockito} import org.mockito.Mockito.{mock, when} +import java.lang.reflect.InvocationTargetException import scala.collection.JavaConverters._ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { @@ -28,11 +29,21 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { cosmosAsyncClient = null ) + private def invokeGetPartitionKeyDefinition(containerProperties: Map[String, String]): ContainerPartitionKey = { + val method = client.getClass.getDeclaredMethod("getPartitionKeyDefinition", classOf[Map[_, _]]) + method.setAccessible(true) + try { + method.invoke(client, containerProperties).asInstanceOf[ContainerPartitionKey] + } catch { + case e: InvocationTargetException => throw e.getCause + } + } + // --- Multi-path partition key tests --- "getPartitionKeyDefinition" should "default to MULTI_HASH with version 2 for multi-path without explicit kind or version" in { val props = Map("partitionKeyPath" -> "/tenantId,/userId,/sessionId") - val result = client.getPartitionKeyDefinition(props) + val result = invokeGetPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.MULTI_HASH result.version() shouldEqual 2 @@ -44,7 +55,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyPath" -> "/a,/b", "partitionKeyKind" -> "MultiHash" ) - val result = client.getPartitionKeyDefinition(props) + val result = invokeGetPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.MULTI_HASH result.version() shouldEqual 2 @@ -57,7 +68,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyKind" -> "Hash" ) - an[IllegalArgumentException] should be thrownBy client.getPartitionKeyDefinition(props) + an[IllegalArgumentException] should be thrownBy invokeGetPartitionKeyDefinition(props) } it should "throw IllegalArgumentException for multi-path with V1 version" in { @@ -66,7 +77,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyVersion" -> "V1" ) - an[IllegalArgumentException] should be thrownBy client.getPartitionKeyDefinition(props) + an[IllegalArgumentException] should be thrownBy invokeGetPartitionKeyDefinition(props) } it should "succeed for multi-path with explicit V2 version" in { @@ -74,7 +85,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyPath" -> "/a,/b", "partitionKeyVersion" -> "V2" ) - val result = client.getPartitionKeyDefinition(props) + val result = invokeGetPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.MULTI_HASH result.version() shouldEqual 2 @@ -85,7 +96,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { it should "default to HASH for single-path without explicit kind" in { val props = Map("partitionKeyPath" -> "/id") - val result = client.getPartitionKeyDefinition(props) + val result = invokeGetPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.HASH result.paths().asScala should contain theSameElementsInOrderAs List("/id") @@ -97,7 +108,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyKind" -> "MultiHash" ) - an[IllegalArgumentException] should be thrownBy client.getPartitionKeyDefinition(props) + an[IllegalArgumentException] should be thrownBy invokeGetPartitionKeyDefinition(props) } it should "set version 1 for single-path with explicit V1 version" in { @@ -105,7 +116,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyPath" -> "/id", "partitionKeyVersion" -> "V1" ) - val result = client.getPartitionKeyDefinition(props) + val result = invokeGetPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.HASH result.version() shouldEqual 1 @@ -117,7 +128,7 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { "partitionKeyPath" -> "/id", "partitionKeyVersion" -> "V2" ) - val result = client.getPartitionKeyDefinition(props) + val result = invokeGetPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.HASH result.version() shouldEqual 2 @@ -128,63 +139,11 @@ class CosmosCatalogManagementSDKClientSpec extends UnitSpec { it should "use default partition key path /id when partitionKeyPath is not specified" in { val props = Map.empty[String, String] - val result = client.getPartitionKeyDefinition(props) + val result = invokeGetPartitionKeyDefinition(props) result.kind() shouldEqual PartitionKind.HASH result.paths().asScala should contain theSameElementsInOrderAs List("/id") } - // --- Edge case: whitespace in paths --- - - it should "trim whitespace from multi-path partition key paths" in { - val props = Map("partitionKeyPath" -> "/a , /b , /c") - val result = client.getPartitionKeyDefinition(props) - - result.kind() shouldEqual PartitionKind.MULTI_HASH - result.version() shouldEqual 2 - result.paths().asScala should contain theSameElementsInOrderAs List("/a", "/b", "/c") - } - - // --- Edge case: trailing comma produces empty segment, filtered out --- - - it should "treat trailing comma as single-path after filtering empty segments" in { - val props = Map("partitionKeyPath" -> "/a,") - val result = client.getPartitionKeyDefinition(props) - - result.kind() shouldEqual PartitionKind.HASH - result.paths().asScala should contain theSameElementsInOrderAs List("/a") - } - - // --- Edge case: invalid partition key kind --- - - it should "throw IllegalArgumentException for invalid partition key kind on multi-path" in { - val props = Map( - "partitionKeyPath" -> "/a,/b", - "partitionKeyKind" -> "Foo" - ) - - an[IllegalArgumentException] should be thrownBy client.getPartitionKeyDefinition(props) - } - - it should "throw IllegalArgumentException for invalid partition key kind on single-path" in { - val props = Map( - "partitionKeyPath" -> "/a", - "partitionKeyKind" -> "Foo" - ) - - an[IllegalArgumentException] should be thrownBy client.getPartitionKeyDefinition(props) - } - - // --- Edge case: invalid partition key version --- - - it should "throw IllegalArgumentException for invalid partition key version on multi-path" in { - val props = Map( - "partitionKeyPath" -> "/a,/b", - "partitionKeyVersion" -> "V3" - ) - - an[IllegalArgumentException] should be thrownBy client.getPartitionKeyDefinition(props) - } - //scalastyle:on multiple.string.literals }