Skip to content

Commit e9503a1

Browse files
committed
feat: enhance Spark example and improve HDFS container startup
- Updated Spark example with detailed connectivity checks for HDFS and Hive Metastore. - Added `hdfsStartupCommand` for improved HDFS container initialization. - Configured Gradle tests to include necessary JVM arguments. - Adjusted container log mode to file for Spark tests.
1 parent ac633d0 commit e9503a1

4 files changed

Lines changed: 45 additions & 6 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ GRADLE_USER_HOME=/data/.gradle ./gradlew :example:spring:bootRun --args='--sprin
132132

133133
The JUnit examples in `example/junit` are annotated with `@Disabled`; remove that annotation from an example class to start the configured stack.
134134

135-
The Spark example in `example/spark` shows a JUnit test that creates a `SparkSession` from `BigDataTestKit` endpoints and configures HDFS, Hive Metastore, Kafka, S3A, and fake GCS settings. It is also disabled by default because it starts the full container stack:
135+
The Spark example in `example/spark` creates a `SparkSession` from `BigDataTestKit` endpoints, starts HDFS, Hive Metastore, Kafka, Schema Registry, LocalStack S3, and fake GCS, verifies HDFS and Hive Metastore connectivity, and configures Spark Kafka/S3/GCS settings:
136136

137137
```bash
138138
GRADLE_USER_HOME=/data/.gradle ./gradlew :example:spark:test

core/src/main/kotlin/org/openprojectx/bigdata/test/core/container/BigDataContainerFactory.kt

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ internal class BigDataContainerFactory(
112112
.withNetwork(network)
113113
.withNetworkAliases("hdfs", "hdfs.example.com")
114114
.withExposedPorts(hdfs.nameNodePort, hdfs.webPort)
115-
.waitingFor(Wait.forListeningPort().withStartupTimeout(Duration.ofMinutes(3)))
115+
.withCommand("sh", "-lc", hdfsStartupCommand(hdfs.nameNodePort, hdfs.webPort))
116+
.waitingFor(Wait.forHttp("/").forPort(hdfs.webPort).withStartupTimeout(Duration.ofMinutes(3)))
116117
if (hdfs.kerberos.enabled) {
117118
mountKerberos(container)
118119
container
@@ -400,6 +401,31 @@ internal class BigDataContainerFactory(
400401
private fun sanitizeLogName(name: String): String =
401402
name.replace(Regex("[^A-Za-z0-9._-]"), "_")
402403

404+
private fun hdfsStartupCommand(nameNodePort: Int, webPort: Int): String =
405+
"""
406+
set -eu
407+
cat > "${'$'}HADOOP_CONF_DIR/core-site.xml" <<EOF
408+
<configuration>
409+
<property><name>fs.defaultFS</name><value>hdfs://hdfs:$nameNodePort</value></property>
410+
</configuration>
411+
EOF
412+
cat > "${'$'}HADOOP_CONF_DIR/hdfs-site.xml" <<EOF
413+
<configuration>
414+
<property><name>dfs.replication</name><value>1</value></property>
415+
<property><name>dfs.permissions.enabled</name><value>false</value></property>
416+
<property><name>dfs.namenode.name.dir</name><value>file:///tmp/hadoop-name</value></property>
417+
<property><name>dfs.datanode.data.dir</name><value>file:///tmp/hadoop-data</value></property>
418+
<property><name>dfs.namenode.rpc-bind-host</name><value>0.0.0.0</value></property>
419+
<property><name>dfs.namenode.http-address</name><value>0.0.0.0:$webPort</value></property>
420+
<property><name>dfs.namenode.http-bind-host</name><value>0.0.0.0</value></property>
421+
</configuration>
422+
EOF
423+
hdfs namenode -format -force -nonInteractive
424+
hdfs namenode &
425+
hdfs datanode &
426+
wait
427+
""".trimIndent()
428+
403429
private fun encodeConfigKey(key: String): String =
404430
key.lowercase(Locale.ROOT)
405431
.replace("-", "__")

example/spark/build.gradle.kts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,10 @@ dependencies {
1414
testRuntimeOnly(libs.junitJupiterEngine)
1515
testRuntimeOnly(libs.junitPlatformLauncher)
1616
}
17+
18+
19+
tasks.withType<Test>().configureEach {
20+
jvmArgs(
21+
"--add-exports=java.base/sun.nio.ch=ALL-UNNAMED",
22+
)
23+
}

example/spark/src/test/kotlin/org/openprojectx/bigdata/test/example/spark/SparkBigDataTestExample.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
package org.openprojectx.bigdata.test.example.spark
22

3+
import org.apache.hadoop.fs.FileSystem
4+
import org.apache.hadoop.fs.Path
35
import org.apache.spark.sql.SparkSession
4-
import org.junit.jupiter.api.Disabled
6+
import java.net.URI
7+
import java.nio.file.Files
58
import org.junit.jupiter.api.Test
69
import org.openprojectx.bigdata.test.core.BigDataService
710
import org.openprojectx.bigdata.test.core.BigDataTestKit
811
import org.openprojectx.bigdata.test.core.ContainerLogMode
912
import org.openprojectx.bigdata.test.junit5.BigDataTest
1013

11-
@Disabled("Example only. Remove @Disabled to start Spark against the configured Testcontainers stack.")
1214
@BigDataTest(
1315
hdfs = true,
1416
hiveMetastore = true,
1517
kafka = true,
1618
schemaRegistry = true,
1719
localStackS3 = true,
1820
fakeGcs = true,
19-
containerLogMode = ContainerLogMode.STDOUT
21+
containerLogMode = ContainerLogMode.FILE
2022
)
2123
class SparkBigDataTestExample {
2224
@Test
@@ -28,11 +30,12 @@ class SparkBigDataTestExample {
2830
val s3 = kit.endpoint(BigDataService.LOCALSTACK_S3)
2931
val gcs = kit.endpoint(BigDataService.FAKE_GCS)
3032

33+
val warehouseDir = Files.createTempDirectory("bigdata-test-spark-warehouse-").toUri().toString()
3134
val spark = SparkSession.builder()
3235
.appName("bigdata-test-spark-example")
3336
.master("local[2]")
3437
.config("spark.ui.enabled", "false")
35-
.config("spark.sql.warehouse.dir", "${hdfs.property("fs.defaultFS")}/user/hive/warehouse")
38+
.config("spark.sql.warehouse.dir", warehouseDir)
3639
.config("hive.metastore.uris", hiveMetastore.property("hive.metastore.uris"))
3740
.config("spark.hadoop.fs.defaultFS", hdfs.property("fs.defaultFS"))
3841
.config("spark.hadoop.fs.s3a.endpoint", s3.property("aws.endpoint-url.s3"))
@@ -45,6 +48,9 @@ class SparkBigDataTestExample {
4548
.getOrCreate()
4649

4750
spark.use { session ->
51+
FileSystem.get(URI.create(hdfs.property("fs.defaultFS")), session.sparkContext().hadoopConfiguration())
52+
.use { fs -> check(fs.exists(Path("/"))) }
53+
4854
session.sql("CREATE DATABASE IF NOT EXISTS bigdata_test_example")
4955
session.sql("CREATE TABLE IF NOT EXISTS bigdata_test_example.spark_smoke (id INT, name STRING) USING parquet")
5056
session.sql("INSERT INTO bigdata_test_example.spark_smoke VALUES (1, 'spark')")

0 commit comments

Comments
 (0)