-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Improve Spark Tests Framework #18551
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
c3a415f
ce3acee
e38f01c
b88079e
c72200f
644bdff
a3119b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
|
|
||
| *.log | ||
| .gitignore | ||
|
|
||
| metastore_db/* | ||
| spark-warehouse/* | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| *.log | ||
| .gitignore | ||
|
moderakh marked this conversation as resolved.
Outdated
|
||
|
|
||
| metastore_db/* | ||
| spark-warehouse/* | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # Dev Azure Cosmos DB OLTP Spark connector client library for Java | ||
|
|
||
| ### How to run unit | ||
|
|
||
| To run the tests of Spark connector without running the SDK tests you need to install azure-cosmos first | ||
| ```bash | ||
| mvn -e -DskipTests -Dgpg.skip -Dmaven.javadoc.skip=true -Dspotbugs.skip=true -Dcheckstyle.skip=true -Drevapi.skip=true -pl ,azure-cosmos -am clean install | ||
| ``` | ||
|
|
||
| To run unit tests: | ||
| ``` | ||
| mvn -e -Dgpg.skip -Dmaven.javadoc.skip=true -Dspotbugs.skip=true -Dcheckstyle.skip=true -Drevapi.skip=true -pl ,azure-cosmos-spark_3-0_2-12 test package -Punit | ||
| ``` | ||
|
|
||
| To run integration tests (requires Cosmos DB endpoint) | ||
|
|
||
| Create the file ~/cosmos-v4.properties with the following content (modify to match your cosmos endpoint): | ||
|
|
||
| ``` | ||
| ACCOUNT_HOST=https://192.168.1.51:8081 | ||
|
moderakh marked this conversation as resolved.
Outdated
|
||
| ACCOUNT_KEY=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw== | ||
| ``` | ||
|
|
||
| run the following command to run end to end integration tests: | ||
|
|
||
| ```bash | ||
| mvn -e -Dgpg.skip -Dmaven.javadoc.skip=true -Dspotbugs.skip=true -Dcheckstyle.skip=true -Drevapi.skip=true -pl ,azure-cosmos-spark_3-0_2-12 test package -PsparkE2E | ||
| ``` | ||
|
|
||
| How to run style check: | ||
| ```bash | ||
| mvn -e -Dgpg.skip -DskipTests -Dmaven.javadoc.skip=true -Dspotbugs.skip=false -Dcheckstyle.skip=false -Drevapi.skip=true -pl ,azure-cosmos-spark_3-0_2-12 -am clean package | ||
| ``` | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,160 +3,94 @@ | |
| package com.azure.cosmos.spark | ||
|
|
||
| import com.azure.cosmos.implementation.TestConfigurations | ||
| import com.azure.cosmos.{CosmosAsyncClient, CosmosClientBuilder, CosmosException} | ||
| import org.apache.commons.lang3.RandomStringUtils | ||
| import org.apache.spark.sql.SparkSession | ||
| import org.assertj.core.api.Assertions.assertThat | ||
| // scalastyle:off underscore.import | ||
| import scala.collection.JavaConverters._ | ||
| // scalastyle:on underscore.import | ||
|
|
||
| // TODO moderakh do proper clean up for spark session, client, etc | ||
| // TODO: moderakh should we tag tests at the test class level or test method level? | ||
| // TODO: moderakh do we need to recreate spark for each test or should we use a common instance? | ||
| // TODO: moderakh rely on the shared database/container for the tests to avoid creating many | ||
| // TODO: moderakh develop the proper pattern for proper resource cleanup after test | ||
| // we need to clean up databases after creation. | ||
|
|
||
| class CosmosCatalogSpec extends IntegrationSpec { | ||
| class CosmosCatalogSpec extends IntegrationSpec with CosmosClient { | ||
| //scalastyle:off multiple.string.literals | ||
| //scalastyle:off magic.number | ||
|
|
||
| it should "create a database with shared throughput" taggedAs (RequiresCosmosEndpoint) in { | ||
| var spark : SparkSession = _ | ||
|
|
||
| override def beforeAll(): Unit = { | ||
| super.beforeAll() | ||
| val cosmosEndpoint = TestConfigurations.HOST | ||
| val cosmosMasterKey = TestConfigurations.MASTER_KEY | ||
|
|
||
| val client = new CosmosClientBuilder() | ||
| .endpoint(cosmosEndpoint) | ||
| .key(cosmosMasterKey) | ||
| .buildAsyncClient() | ||
|
|
||
| val spark = SparkSession.builder() | ||
| spark = SparkSession.builder() | ||
| .appName("spark connector sample") | ||
| .master("local") | ||
| .enableHiveSupport() | ||
| .getOrCreate() | ||
|
|
||
| spark.conf.set(s"spark.sql.catalog.testCatalog", "com.azure.cosmos.spark.CosmosCatalog") | ||
| spark.conf.set(s"spark.sql.catalog.testCatalog.spark.cosmos.accountEndpoint", cosmosEndpoint) | ||
| spark.conf.set(s"spark.sql.catalog.testCatalog.spark.cosmos.accountKey", cosmosMasterKey) | ||
| } | ||
|
|
||
| val databaseName = RandomStringUtils.randomAlphabetic(5) | ||
|
|
||
| spark.sql(s"CREATE DATABASE testCatalog.${databaseName} WITH DBPROPERTIES ('manualThroughput' = '1000');") | ||
|
|
||
| client.getDatabase(databaseName).read().block() | ||
| val throughput = client.getDatabase(databaseName).readThroughput().block() | ||
| assertThat(throughput.getProperties.getManualThroughput).isEqualTo(1000) | ||
|
|
||
| client.close() | ||
| spark.close() | ||
| override def afterAll(): Unit = { | ||
| try spark.close() | ||
| finally super.afterAll() | ||
| } | ||
|
|
||
| it should "drops a database" taggedAs (RequiresCosmosEndpoint) in { | ||
| val cosmosEndpoint = TestConfigurations.HOST | ||
| val cosmosMasterKey = TestConfigurations.MASTER_KEY | ||
| "Cosmos Catalog" can "create a database with shared throughput" taggedAs (RequiresCosmosEndpoint) in { | ||
| val databaseName = getAutoCleanableDatabaseName() | ||
|
|
||
| val client = new CosmosClientBuilder() | ||
| .endpoint(cosmosEndpoint) | ||
| .key(cosmosMasterKey) | ||
| .buildAsyncClient() | ||
| spark.sql(s"CREATE DATABASE testCatalog.${databaseName} WITH DBPROPERTIES ('manualThroughput' = '1000');") | ||
|
|
||
| val spark = SparkSession.builder() | ||
| .appName("spark connector sample") | ||
| .master("local") | ||
| .getOrCreate() | ||
| cosmosClient.getDatabase(databaseName).read().block() | ||
| val throughput = cosmosClient.getDatabase(databaseName).readThroughput().block() | ||
|
|
||
| spark.conf.set(s"spark.sql.catalog.testCatalog", "com.azure.cosmos.spark.CosmosCatalog") | ||
| spark.conf.set(s"spark.sql.catalog.testCatalog.spark.cosmos.accountEndpoint", cosmosEndpoint) | ||
| spark.conf.set(s"spark.sql.catalog.testCatalog.spark.cosmos.accountKey", cosmosMasterKey) | ||
| throughput.getProperties.getManualThroughput shouldEqual 1000 | ||
| } | ||
|
|
||
| val databaseName = RandomStringUtils.randomAlphabetic(6) | ||
| assertThat(databaseExists(client, databaseName)).isEqualTo(false) | ||
| it can "drops a database" taggedAs (RequiresCosmosEndpoint) in { | ||
| val databaseName = getAutoCleanableDatabaseName() | ||
| spark.catalog.databaseExists(databaseName) shouldEqual false | ||
|
|
||
| createDatabase(spark, databaseName) | ||
| assertThat(databaseExists(client, databaseName)).isEqualTo(true) | ||
| databaseExists(databaseName) shouldEqual true | ||
|
|
||
| dropDatabase(spark, databaseName) | ||
| assertThat(spark.catalog.databaseExists(databaseName)).isEqualTo(false) | ||
|
|
||
| client.close() | ||
| spark.close() | ||
| spark.catalog.databaseExists(databaseName) shouldEqual false | ||
| } | ||
|
|
||
| it can "create a table with defaults" taggedAs (RequiresCosmosEndpoint) in { | ||
| val cosmosEndpoint = TestConfigurations.HOST | ||
| val cosmosMasterKey = TestConfigurations.MASTER_KEY | ||
|
|
||
| val client = new CosmosClientBuilder() | ||
| .endpoint(cosmosEndpoint) | ||
| .key(cosmosMasterKey) | ||
| .buildAsyncClient() | ||
|
|
||
| val spark = SparkSession.builder() | ||
| .appName("spark connector sample") | ||
| .master("local") | ||
| .enableHiveSupport() | ||
| .getOrCreate() | ||
|
|
||
| spark.conf.set(s"spark.sql.catalog.cosmoscatalog", "com.azure.cosmos.spark.CosmosCatalog") | ||
| spark.conf.set(s"spark.sql.catalog.cosmoscatalog.spark.cosmos.accountEndpoint", cosmosEndpoint) | ||
| spark.conf.set(s"spark.sql.catalog.cosmoscatalog.spark.cosmos.accountKey", cosmosMasterKey) | ||
|
|
||
| val databaseName = RandomStringUtils.randomAlphabetic(5).toLowerCase | ||
| val databaseName = getAutoCleanableDatabaseName() | ||
| val containerName = RandomStringUtils.randomAlphabetic(6).toLowerCase + System.currentTimeMillis() | ||
| cleanupDatabaseLater(databaseName) | ||
|
|
||
| spark.sql(s"CREATE DATABASE cosmoscatalog.${databaseName};") | ||
| spark.sql(s"CREATE TABLE cosmoscatalog.${databaseName}.${containerName} (word STRING, number INT) using cosmos.items;") | ||
| spark.sql(s"CREATE DATABASE testCatalog.${databaseName};") | ||
| spark.sql(s"CREATE TABLE testCatalog.${databaseName}.${containerName} (word STRING, number INT) using cosmos.items;") | ||
|
|
||
| val containerProperties = client.getDatabase(databaseName).getContainer(containerName).read().block().getProperties | ||
| val containerProperties = cosmosClient.getDatabase(databaseName).getContainer(containerName).read().block().getProperties | ||
|
|
||
| // verify default partition key path is used | ||
| containerProperties.getPartitionKeyDefinition.getPaths.asScala.toArray should equal(Array("/id")) | ||
|
|
||
| // validate throughput | ||
|
|
||
| val throughput = client.getDatabase(databaseName).getContainer(containerName).readThroughput().block().getProperties | ||
| val throughput = cosmosClient.getDatabase(databaseName).getContainer(containerName).readThroughput().block().getProperties | ||
| throughput.getManualThroughput shouldEqual 400 | ||
|
|
||
| client.close() | ||
| spark.close() | ||
| } | ||
|
|
||
| it should "create a table with customized properties" taggedAs (RequiresCosmosEndpoint) in { | ||
| val cosmosEndpoint = TestConfigurations.HOST | ||
| val cosmosMasterKey = TestConfigurations.MASTER_KEY | ||
|
|
||
| val client = new CosmosClientBuilder() | ||
| .endpoint(cosmosEndpoint) | ||
| .key(cosmosMasterKey) | ||
| .buildAsyncClient() | ||
|
|
||
| val spark = SparkSession.builder() | ||
| .appName("spark connector sample") | ||
| .master("local") | ||
| .enableHiveSupport() | ||
| .getOrCreate() | ||
|
|
||
| spark.conf.set(s"spark.sql.catalog.cosmoscatalog", "com.azure.cosmos.spark.CosmosCatalog") | ||
| spark.conf.set(s"spark.sql.catalog.cosmoscatalog.spark.cosmos.accountEndpoint", cosmosEndpoint) | ||
| spark.conf.set(s"spark.sql.catalog.cosmoscatalog.spark.cosmos.accountKey", cosmosMasterKey) | ||
|
|
||
| val databaseName = RandomStringUtils.randomAlphabetic(5).toLowerCase | ||
| it can "create a table with customized properties" taggedAs (RequiresCosmosEndpoint) in { | ||
| val databaseName = getAutoCleanableDatabaseName() | ||
| val containerName = RandomStringUtils.randomAlphabetic(6).toLowerCase + System.currentTimeMillis() | ||
|
|
||
| spark.sql(s"CREATE DATABASE cosmoscatalog.${databaseName};") | ||
| spark.sql(s"CREATE TABLE cosmoscatalog.${databaseName}.${containerName} (word STRING, number INT) using cosmos.items " + | ||
| spark.sql(s"CREATE DATABASE testCatalog.${databaseName};") | ||
| spark.sql(s"CREATE TABLE testCatalog.${databaseName}.${containerName} (word STRING, number INT) using cosmos.items " + | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unrelated - but I really love that you have wired up the metadata changes already - I am sure Spark developers will love this feature - don't know how many customers I have seen that had taken a dependency to some crappy very old Python SDK just to be able to create/modify containers etc. |
||
| s"TBLPROPERTIES(partitionKeyPath = '/mypk', manualThroughput = '1100')") | ||
|
|
||
| val containerProperties = client.getDatabase(databaseName).getContainer(containerName).read().block().getProperties | ||
| val containerProperties = cosmosClient.getDatabase(databaseName).getContainer(containerName).read().block().getProperties | ||
| containerProperties.getPartitionKeyDefinition.getPaths.asScala.toArray should equal(Array("/mypk")) | ||
|
|
||
| // validate throughput | ||
| val throughput = client.getDatabase(databaseName).getContainer(containerName).readThroughput().block().getProperties | ||
| val throughput = cosmosClient.getDatabase(databaseName).getContainer(containerName).readThroughput().block().getProperties | ||
| throughput.getManualThroughput shouldEqual 1100 | ||
|
|
||
| client.close() | ||
| spark.close() | ||
| } | ||
|
|
||
| private def createDatabase(spark: SparkSession, databaseName: String) = { | ||
|
|
@@ -167,14 +101,6 @@ class CosmosCatalogSpec extends IntegrationSpec { | |
| spark.sql(s"DROP DATABASE testCatalog.${databaseName};") | ||
| } | ||
|
|
||
| private def databaseExists(client: CosmosAsyncClient, databaseName: String) = { | ||
| try { | ||
| client.getDatabase(databaseName).read().block() | ||
| true | ||
| } catch { | ||
| case e: CosmosException if e.getStatusCode == 404 => false | ||
| } | ||
| } | ||
| //scalastyle:on magic.number | ||
| //scalastyle:on multiple.string.literals | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.