plugins { id 'java-library' id 'pegasus' id 'io.ebean' version "${ebeanVersion}" // Use the latest version from global build.gradle id 'java-test-fixtures' } apply from: '../gradle/coverage/java-coverage.gradle' // Memory profile configuration - supports environment variable GRADLE_MEMORY_PROFILE or system property // Values: "low" (8GB systems), "default" (16GB+ systems), "high" (32GB+ systems) // Auto-detects system memory if not explicitly set def detectMemoryProfile() { // Check if explicitly set via environment variable or system property def explicitProfile = System.getenv("GRADLE_MEMORY_PROFILE") ?: System.getProperty("gradle.memory.profile") if (explicitProfile) { return explicitProfile } // Auto-detect based on actual system memory (total RAM) using OperatingSystemMXBean try { def osBean = java.lang.management.ManagementFactory.getOperatingSystemMXBean() def sunOsBean = Class.forName("com.sun.management.OperatingSystemMXBean") if (!sunOsBean.isInstance(osBean)) { throw new Exception("OperatingSystemMXBean does not support getTotalPhysicalMemorySize()") } def method = sunOsBean.getMethod("getTotalPhysicalMemorySize") def totalMemoryBytes = method.invoke(osBean) as Long def totalMemoryGB = totalMemoryBytes / (1024.0 * 1024.0 * 1024.0) def detectedProfile if (totalMemoryGB < 12) { detectedProfile = "low" // < 12GB: use low profile (8GB systems) } else if (totalMemoryGB < 24) { detectedProfile = "default" // 12-24GB: use default profile (16GB+ systems) } else { detectedProfile = "high" // >= 24GB: use high profile (32GB+ systems) } println "Auto-detected memory profile: ${detectedProfile} (System RAM: ${String.format("%.1f", totalMemoryGB)}GB)" return detectedProfile } catch (Exception e) { // Fallback to default if detection fails println "Warning: Could not detect system memory (${e.message}), using 'default' profile" return "default" } } def memoryProfile = detectMemoryProfile() // Define memory configurations per profile // since it's read before build.gradle runs def memoryConfigs = [ "low": [ testHeap: "1g", testMinHeap: "256m", testMetaspace: "384m", // Docker container memory settings (for ES/OS/Cassandra/Neo4j) - applied via system properties elasticsearchHeap: "256m", opensearchHeap: "512m", cassandraHeap: "128m", neo4jHeap: "256m" ], "default": [ testHeap: "2g", testMinHeap: "512m", testMetaspace: "512m", elasticsearchHeap: "512m", opensearchHeap: "1024m", cassandraHeap: "128m", neo4jHeap: "512m" ], "high": [ testHeap: "3g", testMinHeap: "1g", testMetaspace: "768m", elasticsearchHeap: "768m", opensearchHeap: "1536m", cassandraHeap: "256m", neo4jHeap: "768m" ] ] def memoryConfig = memoryConfigs[memoryProfile] ?: memoryConfigs["low"] println "Using memory profile: ${memoryProfile}" println " Test processes: ${memoryConfig.testHeap} heap (min ${memoryConfig.testMinHeap}), ${memoryConfig.testMetaspace} metaspace" println " Docker containers:" println " - Elasticsearch: ${memoryConfig.elasticsearchHeap}" println " - OpenSearch: ${memoryConfig.opensearchHeap}" println " - Cassandra: ${memoryConfig.cassandraHeap}" println " - Neo4j: ${memoryConfig.neo4jHeap}" println " Note: Gradle daemon memory is set in gradle.properties (see file for details)" println " Override: Set GRADLE_MEMORY_PROFILE environment variable or -Dgradle.memory.profile system property" // Set system properties for container memory configuration (containers read these at runtime) System.setProperty("testcontainers.elasticsearch.heap", memoryConfig.elasticsearchHeap) System.setProperty("testcontainers.opensearch.heap", memoryConfig.opensearchHeap) System.setProperty("testcontainers.cassandra.heap", memoryConfig.cassandraHeap) System.setProperty("testcontainers.neo4j.heap", memoryConfig.neo4jHeap) configurations { enhance } dependencies { implementation project(':entity-registry') implementation project(':metadata-service:auth-config') api project(':metadata-io:metadata-io-api') api project(':metadata-utils') api project(':metadata-events:mxe-avro') api project(':metadata-events:mxe-registration') api project(':metadata-events:mxe-utils-avro') api project(':metadata-models') api project(':metadata-service:restli-client-api') api project(':metadata-service:configuration') api project(':metadata-service:services') api project(':metadata-operation-context') implementation spec.product.pegasus.restliServer implementation spec.product.pegasus.data implementation spec.product.pegasus.generator implementation externalDependency.guava implementation externalDependency.reflections implementation externalDependency.neo4jJavaDriver implementation externalDependency.graphqlJava implementation externalDependency.slf4jApi runtimeOnly externalDependency.logbackClassic compileOnly externalDependency.lombok compileOnly externalDependency.hazelcast api externalDependency.datastaxOssNativeProtocol api(externalDependency.datastaxOssCore) { exclude group: 'com.fasterxml.jackson.core' } api externalDependency.datastaxOssQueryBuilder api externalDependency.elasticSearchRest // Optional search client shim dependencies api externalDependency.elasticsearch8Client implementation externalDependency.awsRds implementation externalDependency.javatuples api externalDependency.javaxValidation runtimeOnly externalDependency.jna api externalDependency.kafkaClients api externalDependency.ebean annotationProcessor externalDependency.ebeanQueryBean implementation externalDependency.ebeanDdl implementation externalDependency.ebeanAgent implementation externalDependency.opentelemetryAnnotations implementation externalDependency.opentelemetrySdkTrace implementation externalDependency.opentelemetrySdkMetrics implementation externalDependency.resilience4j // Newer Spring libraries require JDK17 classes, allow for JDK11 compileOnly externalDependency.springBootAutoconfigureJdk11 implementation(externalDependency.mixpanel) { exclude group: 'org.json', module: 'json' } annotationProcessor externalDependency.lombok testImplementation project(':test-models') testImplementation project(path: ':test-models', configuration: 'testDataTemplate') testFixturesApi project(':datahub-graphql-core') testImplementation project(path: ':metadata-integration:java:datahub-client', configuration: 'shadow') testImplementation project(':metadata-service:auth-impl') testFixturesApi project(':metadata-service:configuration') testImplementation project(':li-utils') testImplementation externalDependency.testng testImplementation externalDependency.h2 testImplementation externalDependency.mysqlConnector testImplementation externalDependency.mockito testImplementation externalDependency.mockitoInline testImplementation externalDependency.iStackCommons testImplementation externalDependency.resilience4j testImplementation externalDependency.testContainers testImplementation externalDependency.testContainersJunit testImplementation externalDependency.testContainersElasticsearch testImplementation externalDependency.testContainersOpenSearch testImplementation externalDependency.testContainersCassandra testImplementation externalDependency.testContainersNeo4j testImplementation externalDependency.lombok testFixturesApi externalDependency.springBootTest testImplementation spec.product.pegasus.restliServer testImplementation externalDependency.ebeanTest testImplementation externalDependency.opentelemetrySdk // logback >=1.3 required due to `testcontainers` only testImplementation 'ch.qos.logback:logback-classic:1.4.7' testImplementation 'net.datafaker:datafaker:1.9.0' testImplementation externalDependency.awaitility testImplementation(testFixtures(project(":entity-registry"))) testAnnotationProcessor externalDependency.lombok testImplementation project(':mock-entity-registry') constraints { implementation(externalDependency.log4jCore) { because("previous versions are vulnerable to CVE-2021-45105") } implementation(externalDependency.log4jApi) { because("previous versions are vulnerable to CVE-2021-45105") } implementation(externalDependency.commonsText) { because("previous versions are vulnerable to CVE-2022-42889") } implementation(externalDependency.snakeYaml) { because("previous versions are vulnerable to CVE-2022-25857") } implementation(externalDependency.woodstoxCore) { because("previous versions are vulnerable to CVE-2022-40151-2") } implementation(externalDependency.jettison) { because("previous versions are vulnerable") } implementation(externalDependency.snappy) { because("previous versions are vulnerable to CVE-2023-34453 through CVE-2023-34455") } implementation(externalDependency.grpcProtobuf) { because("CVE-2023-1428, CVE-2023-32731") } implementation(externalDependency.grpcNettyShaded) { because("Security vulnerability in grpc-netty-shaded 1.68.3") } } } test { doFirst { // override, testng controlling parallelization // increasing >1 will merely run all tests extra times maxParallelForks = 1 } useTestNG() { suites 'src/test/resources/testng.xml' } testLogging { events "failed", "skipped" exceptionFormat "full" showStandardStreams = false } environment 'STRICT_URN_VALIDATION_ENABLED', 'true' } task testEs7CassandraNeo4j(type: Test) { doFirst { maxParallelForks = 1 } useTestNG() { suites 'src/test/resources/testng-es7-cassandra-neo4j.xml' } testLogging { events "failed", "skipped", "passed" exceptionFormat "full" showStandardStreams = true } environment 'STRICT_URN_VALIDATION_ENABLED', 'true' group = 'verification' description = 'Runs only the testng-es7-cassandra-neo4j.xml test suite' } task testOpenSearch(type: Test) { doFirst { maxParallelForks = 1 } useTestNG() { suites 'src/test/resources/testng-opensearch.xml' } testLogging { events "failed", "skipped", "passed" exceptionFormat "full" showStandardStreams = true } environment 'STRICT_URN_VALIDATION_ENABLED', 'true' group = 'verification' description = 'Runs only the testng-opensearch.xml test suite' } task testOther(type: Test) { doFirst { maxParallelForks = 1 } useTestNG() { suites 'src/test/resources/testng-other.xml' } testLogging { events "failed", "skipped", "passed", "started" exceptionFormat "full" showStandardStreams = true } environment 'STRICT_URN_VALIDATION_ENABLED', 'true' group = 'verification' description = 'Runs only other test suite to debug the failing tests' } ebean { debugLevel = 1 // 0 - 9 } tasks.withType(Test) { enableAssertions = false // Set heap size for test JVM processes based on memory profile // This is separate from gradle.properties which only sets memory for the Gradle daemon maxHeapSize = memoryConfig.testHeap minHeapSize = memoryConfig.testMinHeap // Add JVM args for memory efficiency and to prevent OOM kills // -XX:MaxMetaspaceSize: Limit metaspace to prevent unbounded growth // -XX:+UseG1GC: Use G1 garbage collector for better memory efficiency // -XX:MaxGCPauseMillis: Target pause time for GC (higher for low-memory systems) def gcPauseMillis = memoryProfile == "low" ? "1000" : "500" jvmArgs = [ "-XX:MaxMetaspaceSize=${memoryConfig.testMetaspace}", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=${gcPauseMillis}" ] } clean { //TODO: Is this really needed? dont see generated folder in projectDir. It is in build, but that doest need explicit clean delete "$projectDir/generated" }