This project is a Gradle multi-project build. Use Java 17 for the main build and keep Gradle's user home stable when running commands locally:
GRADLE_USER_HOME=/data/.gradle ./gradlew checkDocker is required for integration tests that start Testcontainers services. Some example tasks start multiple large containers, so prefer running focused tasks while developing.
Keep the module split intentional:
coreowns service options, container construction, endpoint metadata, startup ordering, and log routing.junit5owns annotation parsing, config loading for startup-time options, lifecycle integration, and parameter resolution.extensionsowns heavier setup that depends on Hadoop, Kafka clients, Avro, object-store clients, or other integration libraries.- Spring Boot modules should adapt the core API to Spring configuration. They should not duplicate container logic.
- Example modules should demonstrate supported user workflows and catch real integration regressions.
Do not add Hadoop, Spark, Kafka client, or storage SDK dependencies to core or junit5 unless the module boundary is intentionally changed and documented.
The root build imports the Testcontainers BOM once for all subprojects:
org.testcontainers:testcontainers-bom:2.0.4
Subprojects should declare Testcontainers modules without repeating the BOM. External users should import the BOM in their own build if they also depend on Testcontainers directly.
When adding dependencies, keep them in the narrowest module that needs them. For example, Hadoop credential provider helpers belong in extensions, not core.
Heavy client dependencies in extensions, such as Hadoop, Kafka, Avro, Schema Registry, and serialization libraries, should stay as implementation unless their types intentionally become part of the public API. This avoids pushing those libraries onto a user's compile classpath. Do not switch them to api just because an internal extension implementation imports them.
Startup-time service configuration belongs to @BigDataTest and its TOML files. Examples include:
- enabled services
- service images
- fixed ports
- Kerberos service switches
- container log routing
Test-data and setup automation belongs to @BigDataExtensions. Examples include:
- creating buckets
- creating JCEKS files
- producing Kafka Avro records
- publishing generated Kerberos material for tests
Launcher-driven config should use the existing system-property hooks:
bigdata.test.config
bigdata.test.config.replace
bigdata.extensions.config
bigdata.extensions.config.replace
Use replacement mode for matrix tasks that need to turn services on and off. Service booleans are additive when configs are appended.
Prefer config-driven extension behavior when the user should only declare what they want. A good extension should:
- validate required services before doing work
- run at the narrowest lifecycle event that makes sense
- publish useful output through
BigDataExtensionResult - accept generated names and dynamic values through the programmatic builder
- keep service-specific client code inside
extensions
For built-in extension types, update:
- config model and loader
- builder API
- result output keys
- user guide
- an example or focused test
For external extension modules, implement BigDataExtensionProvider and register it with ServiceLoader.
Kerberos is intentionally opt-in per service. kerberos = true starts the shared KDC, then service-specific switches decide which services use Kerberos.
Schema Registry should stay out of the Kerberos service switch model unless its own authentication is explicitly implemented. It can still run with Kafka Kerberos by using Kafka's internal plaintext listener.
Host-side Kafka Kerberos clients need a stable advertised host port. Existing Kerberos matrix tasks use fixed Kafka port 19092 for this reason.
The project supports two Hive Metastore implementations:
hiveMetastore = true: open-source Hive HMS image plus external PostgreSQL by default, or MySQL withdatabaseType = "mysql".clouderaHms = true: Cloudera HMS image with embedded PostgreSQL.
Keep their endpoint contract the same through BigDataService.HIVE_METASTORE. A test must enable only one HMS implementation.
The Spark example defaults to the Hive 3 open-source HMS image because Spark 3.x uses an older Hive metastore client. Keep Hive 4 compatibility notes in doc/hive-docker-hms-issues.adoc.
Update docs with every user-visible feature, breaking change, task, config key, image key, endpoint property, or behavior change.
Use this split:
README.md: quick start, key commands, and links.doc/user-guide.adoc: detailed usage, configuration, examples, and troubleshooting.CONTRIBUTING.md: development workflow and project conventions.- focused
doc/*.adocnotes: current known issues or design-specific references.
Run focused compile checks for ordinary API edits:
GRADLE_USER_HOME=/data/.gradle ./gradlew :core:compileKotlin :junit5:compileKotlin :extensions:compileKotlinRun the Spark example when touching Spark, HMS, Kafka, object-store, extension, or Kerberos behavior:
GRADLE_USER_HOME=/data/.gradle ./gradlew :example:spark:testRun the full Spark matrix when touching runtime config composition, HMS selection, or Kerberos behavior:
GRADLE_USER_HOME=/data/.gradle ./gradlew :example:spark:sparkBigDataMatrixTestThe Spark matrix has two kinds of axes. Container/service axes belong in TOML and can be selected with bigdata.test.config. Dependency axes belong in Gradle tasks because they require different resolved test JVM classpaths. Add a new dependency line by creating a resolvable runtime classpath in example/spark/build.gradle.kts, then pair it with the existing TOML service variants.
The Gradle configuration-cache warning from net.researchgate.release is currently expected and unrelated to test behavior.
The release workflow publishes library modules to Maven Central through Sonatype by default.
GitHub Packages publishing is opt-in because GitHub's Maven registry can return 409 Conflict for Gradle checksum sidecar uploads during retry. Enable it in a manual workflow run with publish_github_packages=true, or locally with -PpublishGitHubPackages=true or PUBLISH_GITHUB_PACKAGES=true.
GitHub Packages uses the repository Maven endpoint:
https://maven.pkg.github.com/OpenProjectX/bigdata-test
When enabled, the workflow needs packages: write permission and passes GITHUB_PACKAGES_USERNAME plus GITHUB_PACKAGES_TOKEN to Gradle. Local dry runs can validate task selection without uploading:
GRADLE_USER_HOME=/data/.gradle ./gradlew publishAllPublicationsToGitHubPackagesRepository --dry-run
GRADLE_USER_HOME=/data/.gradle ./gradlew release --dry-run -PpublishGitHubPackages=trueSuccessful release workflow runs write a GitHub Actions job summary with the released version, Maven coordinates, GitHub Packages links, Maven Central links, and the GitHub Packages repository snippet for consumers.
Push-triggered release workflow runs can be skipped with common commit-message markers:
[skip ci]
[ci skip]
[no ci]
[skip actions]
[actions skip]
skip-checks:true
Manual workflow_dispatch releases ignore these markers and still run.
Use file logs when investigating container startup or service-side behavior:
@BigDataTest(
kafka = true,
containerLogMode = ContainerLogMode.FILE,
containerLogDirectory = "build/container-logs",
)
class DebugTestFor port conflicts, check local listeners before switching tests to fixed ports. Dynamic ports are the default and should remain the default for general JUnit usage.