// Copyright 2019 The Nomulus Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import com.google.common.base.CaseFormat import java.util.Optional plugins { id 'java-library' id "org.flywaydb.flyway" version "11.0.1" id 'maven-publish' } // Path to code generated by ad hoc tasks in this project. A separate path is // used for easy inspection. def generatedDir = "${project.buildDir}/generated/sources/custom/java/main" def resourcesDir = "${project.buildDir}/resources/main" def screenshotsDir = "${project.buildDir}/screenshots" def screenshotsForGoldensDir = "${project.buildDir}/screenshots_for_goldens" def newGoldensDir = "${project.buildDir}/new_golden_images" def goldensDir = "${javaTestDir}/google/registry/webdriver/goldens/chrome-linux" // Tests that fail when running Gradle in a docker container, e. g. when // building the release artifacts in Google Cloud Build. def dockerIncompatibleTestPatterns = [ // The webdriver tests start headless Chrome in a Docker container, // resulting in Docker-in-Docker complications. Likewise, // GenerateSqlSchemaCommandTest and DumpGoldenSchemaCommandTest launch // postgresql in a docker container. "google/registry/webdriver/*", "google/registry/tools/GenerateSqlSchemaCommandTest.*", "google/registry/tools/DumpGoldenSchemaCommandTest.*", // PathParameterTest includes tests which validate that file permissions are // respected. However when running in Docker the user is root by default, so // every file is read/write-able. There is no way to exclude specific test // methods, so we exclude the whole test class. "google/registry/tools/params/PathParameterTest.*", "google/registry/persistence/PersistenceModuleTest.*", ] // Tests that conflict with members of the main test suite. They seem to be // affected by global states outside of Nomulus classes, e.g., threads and // objects retained by frameworks. // TODO(weiminyu): identify cause and fix offending tests. def fragileTestPatterns = [ // Breaks random other tests when running with standardTests. "google/registry/bsa/UploadBsaUnavailableDomainsActionTest.*", // Currently changes a global configuration parameter that for some reason // results in timestamp inversions for other tests. TODO(mmuller): fix. "google/registry/flows/host/HostInfoFlowTest.*", "google/registry/beam/common/RegistryPipelineWorkerInitializerTest.*", ] + dockerIncompatibleTestPatterns sourceSets { main { java { srcDirs += generatedDir } resources { exclude '**/*.xjb' } } nonprod { java { compileClasspath += main.output // Add the DB runtime classpath to nonprod so we can load the flyway // scripts. runtimeClasspath += main.output + rootProject.project(":db").sourceSets.main.runtimeClasspath } } test { java { compileClasspath += nonprod.output runtimeClasspath += nonprod.output } resources { exclude '**/*.xjb', '**/*.xsd' } } } processTestResources { exclude '**/webdriver/*' } configurations { jaxb soy devtool nonprodImplementation.extendsFrom implementation testImplementation.extendsFrom nonprodImplementation // Published jars that are used for server/schema compatibility tests. // See the integration project // for details. nomulus_test // Exclude non-canonical servlet-api jars. Our deployment uses // javax.servlet:servlet-api:2.5 // For reasons we do not understand, marking the following dependencies as // compileOnly instead of compile does not exclude them from runtimeClasspath. all { // servlet-api:3.1 pulled in but not used by soy compiler exclude group: 'javax.servlet', module: 'javax.servlet-api' } } dependencies { def deps = rootProject.dependencyMap testRuntimeOnly files(sourceSets.test.resources.srcDirs) implementation deps['com.github.ben-manes.caffeine:caffeine'] implementation deps['com.google.api:gax'] implementation deps['com.google.api.grpc:proto-google-common-protos'] implementation deps['com.google.api.grpc:proto-google-cloud-secretmanager-v1'] implementation deps['com.google.api-client:google-api-client'] implementation deps['com.google.api-client:google-api-client-servlet'] implementation deps['com.google.monitoring-client:metrics'] implementation deps['com.google.monitoring-client:stackdriver'] implementation deps['com.google.api-client:google-api-client-java6'] implementation deps['com.google.api.grpc:proto-google-cloud-tasks-v2'] implementation deps['com.google.apis:google-api-services-admin-directory'] implementation deps['com.google.apis:google-api-services-bigquery'] implementation deps['com.google.apis:google-api-services-dataflow'] implementation deps['com.google.apis:google-api-services-dns'] implementation deps['com.google.apis:google-api-services-drive'] implementation deps['com.google.apis:google-api-services-gmail'] implementation deps['com.google.apis:google-api-services-groupssettings'] implementation deps['com.google.apis:google-api-services-iam'] implementation deps['com.google.apis:google-api-services-monitoring'] implementation deps['com.google.apis:google-api-services-sheets'] implementation deps['com.google.apis:google-api-services-storage'] implementation deps['com.google.auth:google-auth-library-credentials'] implementation deps['com.google.auth:google-auth-library-oauth2-http'] implementation deps['com.google.cloud.bigdataoss:util'] implementation deps['com.google.cloud.sql:jdbc-socket-factory-core'] runtimeOnly deps['com.google.cloud.sql:postgres-socket-factory'] implementation deps['com.google.cloud:google-cloud-secretmanager'] implementation deps['com.google.code.gson:gson'] implementation deps['com.google.auto.service:auto-service-annotations'] implementation deps['com.google.auto.value:auto-value-annotations'] implementation deps['com.google.code.findbugs:jsr305'] implementation deps['com.google.dagger:dagger'] implementation deps['com.google.errorprone:error_prone_annotations'] implementation deps['com.google.flogger:flogger'] implementation deps['com.google.guava:guava'] implementation deps['com.google.protobuf:protobuf-java'] // Might need to add this back if we re-add nebula-lint // gradleLint.ignore('unused-dependency') { implementation deps['com.google.gwt:gwt-user'] // } implementation deps['com.google.cloud:google-cloud-compute'] implementation deps['com.google.cloud:google-cloud-core'] implementation deps['com.google.cloud:google-cloud-storage'] implementation deps['com.google.cloud:google-cloud-tasks'] implementation deps['com.google.http-client:google-http-client'] implementation deps['com.google.http-client:google-http-client-jackson2'] implementation deps['com.google.oauth-client:google-oauth-client'] implementation deps['com.google.oauth-client:google-oauth-client-java6'] implementation deps['com.google.oauth-client:google-oauth-client-jetty'] implementation deps['com.google.oauth-client:google-oauth-client-servlet'] implementation deps['com.google.re2j:re2j'] implementation deps['com.google.template:soy'] implementation deps['com.googlecode.json-simple:json-simple'] implementation deps['com.jcraft:jsch'] implementation deps['com.zaxxer:HikariCP'] implementation deps['com.squareup.okhttp3:okhttp'] implementation deps['dnsjava:dnsjava'] testRuntimeOnly deps['guru.nidi:graphviz-java-all-j2v8'] testImplementation deps['io.github.classgraph:classgraph'] testRuntimeOnly deps['io.github.java-diff-utils:java-diff-utils'] implementation deps['jakarta.inject:jakarta.inject-api'] implementation deps['jakarta.mail:jakarta.mail-api'] implementation deps['jakarta.persistence:jakarta.persistence-api'] implementation deps['jakarta.servlet:jakarta.servlet-api'] implementation deps['jakarta.xml.bind:jakarta.xml.bind-api'] implementation deps['joda-time:joda-time'] implementation deps['org.antlr:antlr4'] implementation deps['org.antlr:antlr4-runtime'] implementation deps['org.apache.avro:avro'] testImplementation deps['org.apache.beam:beam-runners-core-construction-java'] testImplementation deps['org.apache.beam:beam-runners-direct-java'] implementation deps['org.apache.beam:beam-runners-google-cloud-dataflow-java'] implementation deps['org.apache.beam:beam-sdks-java-core'] implementation deps['org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core'] implementation deps['org.apache.beam:beam-sdks-java-io-google-cloud-platform'] implementation deps['org.apache.commons:commons-csv'] implementation deps['org.apache.commons:commons-lang3'] testImplementation deps['org.apache.commons:commons-text'] testImplementation deps['org.apache.ftpserver:ftplet-api'] testImplementation deps['org.apache.ftpserver:ftpserver-core'] implementation deps['org.apache.httpcomponents:httpclient'] implementation deps['org.apache.httpcomponents:httpcore'] testImplementation deps['org.apache.sshd:sshd-core'] testImplementation deps['org.apache.sshd:sshd-scp'] testImplementation deps['org.apache.sshd:sshd-sftp'] testImplementation deps['org.apache.tomcat:tomcat-annotations-api'] implementation deps['org.bouncycastle:bcpg-jdk18on'] implementation deps['org.bouncycastle:bcpkix-jdk18on'] implementation deps['org.bouncycastle:bcprov-jdk18on'] implementation deps['com.fasterxml.jackson.dataformat:jackson-dataformat-yaml'] testImplementation deps['com.fasterxml.jackson.core:jackson-databind'] implementation deps['org.hibernate.orm:hibernate-ant'] implementation deps['org.hibernate.orm:hibernate-core'] implementation deps['org.hibernate.orm:hibernate-hikaricp'] implementation deps['org.jcommander:jcommander'] implementation deps['org.jline:jline'] implementation deps['org.joda:joda-money'] implementation deps['org.json:json'] implementation deps['org.jsoup:jsoup'] testImplementation deps['org.eclipse.jetty:jetty-server'] testImplementation deps['org.eclipse.jetty.ee10:jetty-ee10-servlet'] testImplementation deps['org.eclipse.jetty.ee10:jetty-ee10-webapp'] implementation deps['org.postgresql:postgresql'] testImplementation deps['org.seleniumhq.selenium:selenium-api'] testImplementation deps['org.seleniumhq.selenium:selenium-chrome-driver'] testImplementation deps['org.seleniumhq.selenium:selenium-java'] testImplementation deps['org.seleniumhq.selenium:selenium-remote-driver'] runtimeOnly deps['org.slf4j:slf4j-jdk14'] testImplementation deps['org.testcontainers:jdbc'] testImplementation deps['org.testcontainers:junit-jupiter'] implementation deps['org.testcontainers:postgresql'] testImplementation deps['org.testcontainers:selenium'] testImplementation deps['org.testcontainers:testcontainers'] implementation deps['us.fatehi:schemacrawler'] implementation deps['us.fatehi:schemacrawler-api'] implementation deps['us.fatehi:schemacrawler-diagram'] implementation deps['us.fatehi:schemacrawler-tools'] implementation deps['us.fatehi:schemacrawler-postgresql'] implementation deps['xerces:xmlParserAPIs'] implementation deps['org.ogce:xpp3'] // Known issue: nebula-lint misses inherited dependency. implementation project(':common') testImplementation project(path: ':common', configuration: 'testing') implementation project(':util') // Import NomulusPostreSql from ':db' for implementation but exclude dependencies. implementation project(path: ':db', configuration: 'implementationApi') testRuntimeOnly project(':db') annotationProcessor deps['com.google.auto.service:auto-service'] annotationProcessor deps['com.google.auto.value:auto-value'] testAnnotationProcessor deps['com.google.auto.value:auto-value'] annotationProcessor deps['com.google.dagger:dagger-compiler'] testAnnotationProcessor deps['com.google.dagger:dagger-compiler'] annotationProcessor project(':processor') testAnnotationProcessor project(':processor') testImplementation deps['com.google.cloud:google-cloud-nio'] testImplementation deps['com.google.guava:guava-testlib'] testImplementation deps['com.google.monitoring-client:contrib'] testImplementation deps['com.google.protobuf:protobuf-java-util'] testImplementation deps['com.google.truth:truth'] testImplementation deps['org.checkerframework:checker-qual'] testImplementation deps['org.hamcrest:hamcrest'] testImplementation deps['org.hamcrest:hamcrest-core'] testImplementation deps['org.hamcrest:hamcrest-library'] testImplementation deps['org.junit.jupiter:junit-jupiter-api'] testImplementation deps['org.junit.jupiter:junit-jupiter-engine'] testImplementation deps['org.junit.jupiter:junit-jupiter-migrationsupport'] testImplementation deps['org.junit.jupiter:junit-jupiter-params'] testImplementation deps['org.junit-pioneer:junit-pioneer'] testImplementation deps['org.junit.platform:junit-platform-runner'] testImplementation deps['org.junit.platform:junit-platform-suite-api'] testImplementation deps['org.mockito:mockito-core'] testImplementation deps['org.mockito:mockito-junit-jupiter'] // Indirect dependency found by undeclared-dependency check. Such // dependencies should go after all other implementation and testImplementation // dependencies to avoid overriding them accidentally. implementation deps['com.google.oauth-client:google-oauth-client-java6'] // Dependencies needed for jaxb compilation. jaxb deps['jakarta.xml.bind:jakarta.xml.bind-api'] jaxb deps['org.glassfish.jaxb:jaxb-runtime'] jaxb deps['org.glassfish.jaxb:jaxb-xjc'] // Dependency needed for soy to java compilation. soy deps['com.google.template:soy'] // Tool dependencies. used for doc generation. implementation files("${System.properties['java.home']}/../lib/tools.jar") // Flyway classes needed to generate the golden file. implementation deps['org.flywaydb:flyway-core'] implementation deps['org.flywaydb:flyway-database-postgresql'] } task jaxbToJava { def xsdFilesDir = "${javaDir}/google/registry/xml/xsd" def bindingsFile = "${javaDir}/google/registry/xjc/bindings.xjb" def pkgInfoTemplate = "${javaDir}/google/registry/xjc/package-info.java.in" def pkgInfoMap = "${javaDir}/google/registry/xjc/package-info.map" def outputDir = "${generatedDir}/google/registry/xjc" inputs.dir xsdFilesDir inputs.files bindingsFile, pkgInfoTemplate, pkgInfoMap outputs.dir outputDir doLast { file(generatedDir).mkdirs() // Temp dir to hold schema and bindings files. Files must be in the same // directory because the bindings (.xjb) file does not declare relative // paths to schema (.xsd) files. def xjcTempSourceDir = file("${temporaryDir}/xjc") xjcTempSourceDir.mkdirs() ant.copy( todir: "${xjcTempSourceDir}", overwrite: true) { fileSet( dir: xsdFilesDir, includes: '**.xsd') } ant.copy( todir: "${xjcTempSourceDir}", overwrite: true, file: bindingsFile) ant.taskdef( name: 'xjc', classname: 'com.sun.tools.xjc.XJCTask', classpath: configurations.jaxb.asPath) ant.xjc( destdir: "${generatedDir}", binding: "${xjcTempSourceDir}/bindings.xjb", removeOldOutput: 'yes', extension: 'true') { project.fileTree( dir: new File("$xjcTempSourceDir"), include: ['**/*.xsd']) .addToAntBuilder(ant, 'schema', FileCollection.AntType.FileSet) // -npa: do not generate package-info.java files. They will be generated // below. arg(line: '-npa -quiet -extension') } new File(pkgInfoMap).eachLine { line -> def (packageName, namespace) = line.split() ant.copy( tofile: "${outputDir}/${packageName}/package-info.java", overwrite: true, file: "${pkgInfoTemplate}") { filterSet() { filter(token: 'PACKAGE', value: packageName) filter(token: 'NAMESPACE', value: namespace) } } } execInBash( "find . -name *.java -exec sed -i -e '/" + /\*

$/ + "/d' {} +", generatedDir) } } task soyToJava { // Relative paths of soy directories. def spec11SoyDir = "google/registry/reporting/spec11/soy" def toolsSoyDir = "google/registry/tools/soy" def soyRelativeDirs = [spec11SoyDir, toolsSoyDir] soyRelativeDirs.each { inputs.dir "${resourcesSourceDir}/${it}" outputs.dir "${generatedDir}/${it}" } ext.soyToJava = { javaPackage, outputDirectory, soyFiles -> javaexec { main = "com.google.template.soy.SoyParseInfoGenerator" classpath configurations.soy args "--javaPackage", "${javaPackage}", "--outputDirectory", "${outputDirectory}", "--javaClassNameSource", "filename", "--srcs", "${soyFiles.join(',')}" } // Replace the "@link" tags after the "@deprecated" tags in the generated // files. The soy compiler doesn't generate imports for these, causing // us to get warnings when we generate javadocs. // TODO(b/200296387): To be fair, the deprecations are accurate: we're // using the old "SoyInfo" classes instead of the new "Templates" files. // When we convert to the new classes, this hack can go away. def outputs = fileTree(outputDirectory) { include '**/*.java' } outputs.each { file -> exec { commandLine 'sed', '-i""', '-e', 's/@link/LINK/g', file.getCanonicalPath() } } } doLast { soyToJava('google.registry.tools.soy', "${generatedDir}/${toolsSoyDir}", fileTree( dir: "${resourcesSourceDir}/${toolsSoyDir}", include: ['**/*.soy'])) soyToJava('google.registry.reporting.spec11.soy', "${generatedDir}/${spec11SoyDir}", fileTree( dir: "${resourcesSourceDir}/${spec11SoyDir}", include: ['**/*.soy'])) } } compileJava.dependsOn jaxbToJava compileJava.dependsOn soyToJava // Make testing artifacts available to be depended up on by other projects. // TODO: factor out google.registry.testing to be a separate project. task testJar(type: Jar) { archiveClassifier = 'test' from sourceSets.test.output } artifacts { testRuntimeOnly testJar } task findGoldenImages(type: JavaExec) { classpath = sourceSets.test.runtimeClasspath main = 'google.registry.webdriver.GoldenImageFinder' def arguments = [] arguments << "--screenshots_for_goldens_dir=${screenshotsForGoldensDir}" arguments << "--new_goldens_dir=${newGoldensDir}" arguments << "--existing_goldens_dir=${goldensDir}" if (rootProject.findProperty("overrideExistingGoldens") == "true") { arguments << "--override_existing_goldens=true" } args arguments } Optional> getToolArgsList() { // If "-PtoolArgs=..." is present in the command line, use it to set the args, // otherwise use the default flag, which is "--args" to set the args. def toolArgs = rootProject.findProperty("toolArgs") if (toolArgs != null) { def delimiter = '|' toolArgs += delimiter def argsList = [] def currArg = '' for (def i = 0; i < toolArgs.length(); i++) { def currChar = toolArgs[i] if (currChar != delimiter) { currArg += currChar } else if (i != 0 && toolArgs[i - 1] == '\\') { currArg = currArg.substring(0, currArg.length() - 1) + currChar } else { argsList.add(currArg) currArg = '' } } return Optional.of(argsList) } return Optional.empty() } // To run the nomulus tools with these command line tokens: // "--foo", "bar baz", "--qux=quz" // gradle core:registryTool --args="--foo 'bar baz' --qux=quz" // or: // gradle core:registryTool -PtoolArgs="--foo|bar baz|--qux=quz" // Note that the delimiting pipe can be backslash escaped if it is part of a // parameter. ext.createToolTask = { taskName, mainClass, sourceSet = sourceSets.main -> project.tasks.create(taskName, JavaExec) { classpath = sourceSet.runtimeClasspath main = mainClass doFirst { getToolArgsList().ifPresent { args it } } } } createToolTask('registryTool', 'google.registry.tools.RegistryTool') createToolTask( 'devTool', 'google.registry.tools.DevTool', sourceSets.nonprod) project.tasks.create('generateSqlSchema', JavaExec) { classpath = sourceSets.nonprod.runtimeClasspath main = 'google.registry.tools.DevTool' args = [ '-e', 'alpha', 'generate_sql_schema', '--start_postgresql', '-o', "${rootProject.projectRootDir}/db/src/main/resources/sql/schema/" + "db-schema.sql.generated" ] } task generateGoldenImages(type: FilteringTest) { tests = ["**/webdriver/*"] // Sets the maximum number of test executors that may exist at the same time. maxParallelForks 5 systemProperty 'test.screenshot.dir', screenshotsForGoldensDir systemProperty 'test.screenshot.runAllAttempts', 'true' systemProperty 'test.screenshot.maxAttempts', '5' doFirst { new File(screenshotsForGoldensDir).deleteDir() } } generateGoldenImages.finalizedBy(findGoldenImages) createUberJar('nomulus', 'nomulus', 'google.registry.tools.RegistryTool') // Build the Uber jar shared by all flex-template based BEAM pipelines. // This packages more code and dependency than necessary. However, without // restructuring the source tree it is difficult to generate leaner jars. createUberJar( 'beamPipelineCommon', 'beam_pipeline_common', '') // Create beam staging task if the environment is alpha. Production, sandbox and // qa use formally released pipelines through CloudBuild, whereas crash and // alpha use the pipelines staged on alpha deployment project. // // User should install gcloud and login to GCP before invoking this tasks. if (environment == 'alpha') { def pipelines = [ spec11 : [ mainClass: 'google.registry.beam.spec11.Spec11Pipeline', metaData : 'google/registry/beam/spec11_pipeline_metadata.json' ], invoicing : [ mainClass: 'google.registry.beam.billing.InvoicingPipeline', metaData : 'google/registry/beam/invoicing_pipeline_metadata.json' ], expandBilling : [ mainClass: 'google.registry.beam.billing.ExpandBillingRecurrencesPipeline', metaData : 'google/registry/beam/expand_billing_recurrences_pipeline_metadata.json' ], rde : [ mainClass: 'google.registry.beam.rde.RdePipeline', metaData : 'google/registry/beam/rde_pipeline_metadata.json' ], resaveAllEppResources: [ mainClass: 'google.registry.beam.resave.ResaveAllEppResourcesPipeline', metaData: 'google/registry/beam/resave_all_epp_resources_pipeline_metadata.json' ], wipeOutContactHistoryPii: [ mainClass: 'google.registry.beam.wipeout.WipeOutContactHistoryPiiPipeline', metaData: 'google/registry/beam/wipe_out_contact_history_pii_pipeline_metadata.json' ], ] project.tasks.create("stageBeamPipelines") { doLast { pipelines.each { if (rootProject.pipeline == ''|| rootProject.pipeline == it.key) { def mainClass = it.value['mainClass'] def metaData = it.value['metaData'] def pipelineName = CaseFormat.UPPER_CAMEL.to( CaseFormat.LOWER_UNDERSCORE, mainClass.substring(mainClass.lastIndexOf('.') + 1)) def imageName = "gcr.io/${gcpProject}/beam/${pipelineName}" def metaDataBaseName = metaData.substring(metaData.lastIndexOf('/') + 1) def uberJarName = tasks.beamPipelineCommon.outputs.files.asPath def command = "\ gcloud dataflow flex-template build \ gs://${gcpProject}-deploy/live/beam/${metaDataBaseName} \ --image-gcr-path ${imageName}:live \ --sdk-language JAVA \ --flex-template-base-image gcr.io/dataflow-templates-base/java21-template-launcher-base:latest \ --metadata-file ${projectDir}/src/main/resources/${metaData} \ --jar ${uberJarName} \ --env FLEX_TEMPLATE_JAVA_MAIN_CLASS=${mainClass} \ --project ${gcpProject}".toString() rootProject.ext.execInBash(command, '/tmp') } } } }.dependsOn(tasks.beamPipelineCommon) } // A jar with classes and resources from main sourceSet, excluding internal // data. See comments on configurations.nomulus_test above for details. // TODO(weiminyu): release process should build this using the public repo to eliminate the need // for excludes. task nomulusFossJar (type: Jar) { archiveBaseName = 'nomulus' archiveClassifier = 'public' from (project.sourceSets.main.output) { exclude 'google/registry/config/files/**' exclude 'google/registry/proxy/config/**' } from (project.sourceSets.main.output) { include 'google/registry/config/files/default-config.yaml' include 'google/registry/config/files/nomulus-config-unittest.yaml' } } // An UberJar of registry test classes, resources and all dependencies. // See comments on configurations.nomulus_test above for details. createUberJar( 'testUberJar', 'nomulus-tests', '', [project.configurations.testRuntimeClasspath], [project.sourceSets.test.output], [ // Exclude SQL schema, which is a test dependency. 'sql/flyway/**', // ShadowJar includes java source files when used on // sourceSets.test.output. '**/*.java' ]) tasks.testUberJar { archiveClassifier = 'alldeps' } artifacts { nomulus_test nomulusFossJar nomulus_test testUberJar } publishing { repositories { maven { url project.publish_repo } } publications { nomulusTestsPublication(MavenPublication) { groupId 'google.registry' artifactId 'nomulus_test' version project.nomulus_version artifact nomulusFossJar artifact testUberJar } } } task buildToolImage(dependsOn: nomulus, type: Exec) { commandLine 'docker', 'build', '-t', 'nomulus-tool', '.' } // Build the devtool jar. createUberJar( 'devtool', 'devtool', 'google.registry.tools.DevTool', [ project.configurations.nonprodRuntimeClasspath ], [ project.sourceSets.nonprod.output, sourceSets.main.output ], [ '**/*.java' ]) artifacts { devtool devtool } task runTestServer(type: JavaExec) { main = 'google.registry.server.RegistryTestServerMain' classpath = sourceSets.test.runtimeClasspath dependsOn(rootProject.project('console-webapp').tasks.named('buildConsoleWebapp')) } /** * We have to break out the test suites because some of the tests conflict * with one another, but unfortunately this breaks the "--tests" flag. The * --tests flag only applies to the task named on the command line (usually * just "test"), not for all tasks of type "Test". * * As a better solution, FilteringTest sets testNameIncludePatterns (the * internal property that --tests sets) from the value of the "testFilter" * property, allowing us to filter across all the tests in core without * explicitly specifying a test task or causing errors because there are no * matching tests in the main task. * * To use it, define "testFilter" to be a comma-separated collection of class * names (wildcards are allowed): * * ./gradlew test -P testFilter=*.FooBar,google.registry.tools.ShellCommandTest */ abstract class FilteringTest extends Test { FilteringTest() { useJUnitPlatform(); } private void applyTestFilter() { if (project.testFilter) { testNameIncludePatterns = project.testFilter.split(',') // By default, gradle test tasks will produce a failure if no tests // match the include/exclude/filter rules. Since test filtering allows us // to select a set of tests from a particular task, we don't want this // behavior. filter.failOnNoMatchingTests = false } } /** * Set to false if you also want to include TestCase and TestSuite classes. * *

Must be defined before "test", if at all. */ @Input boolean excludeTestCases = true void setTests(List tests) { // Common exclude pattern. See README in parent directory for explanation. if (excludeTestCases) { exclude "**/*TestCase.*", "**/*TestSuite.*" } include tests applyTestFilter() } /** * Include all of the tests (except Test{Case,TestSuite}). This actually * doesn't explicitly "include" anything, in which cast the Test class tries * to include everything that is not explicitly excluded. */ void includeAllTests() { exclude "**/*TestCase.*", "**/*TestSuite.*" applyTestFilter() } } task fragileTest(type: FilteringTest) { // Common exclude pattern. See README in parent directory for explanation. tests = fragileTestPatterns // Screenshot tests depend on the console being built dependsOn(rootProject.project('console-webapp').tasks.named('buildConsoleWebapp')) if (rootProject.findProperty("skipDockerIncompatibleTests") == "true") { exclude dockerIncompatibleTestPatterns } // Run every test class in a freshly started process. forkEvery 1 doFirst { new File(screenshotsDir).deleteDir() } } // Dedicated test suite for schema-dependent tests. task sqlIntegrationTest(type: FilteringTest) { // TestSuite still requires a JUnit 4 runner, which knows how to handle JUnit 5 tests. // Here we need to override parent's choice of JUnit 5. If changing this, remember to // change :integration:sqlIntegrationTest too. useJUnit() excludeTestCases = false tests = ['google/registry/schema/integration/SqlIntegrationTestSuite.*'] } // Verifies that RegistryTool can be instantiated: // - All dependencies are packaged in nomulus.jar // - JPA setup succeeds. task registryToolIntegrationTest(dependsOn: nomulus, type: FilteringTest) { tests = ['google/registry/tools/RegistryToolTest.*'] testClassesDirs = sourceSets.test.output.classesDirs classpath = nomulus.outputs.files.plus(configurations.testRuntimeClasspath) .plus(files(testClassesDirs)) } task standardTest(type: FilteringTest) { includeAllTests() exclude fragileTestPatterns // See SqlIntegrationTestSuite.java exclude '**/*BeforeSuiteTest.*', '**/*AfterSuiteTest.*' if (rootProject.findProperty("skipDockerIncompatibleTests") == "true") { exclude dockerIncompatibleTestPatterns } // Run every test class in its own process. // Uncomment to unblock build while troubleshooting inexplicable test errors. // This setting makes the build take 35 minutes, without it it takes about 10. // forkEvery 1 // Sets the maximum number of test executors that may exist at the same time. // Also, Gradle executes tests in 1 thread and some of our test infrastructures // depend on that, e.g. DualDatabaseTestInvocationContextProvider injects // different implementation of TransactionManager into TransactionManagerFactory. maxParallelForks 64 systemProperty 'test.projectRoot', rootProject.projectRootDir systemProperty 'test.resourcesDir', resourcesDir } test { // Don't run any tests from this task, all testing gets done in the // FilteringTest tasks. exclude "**" // TODO(weiminyu): Remove dependency on sqlIntegrationTest }.dependsOn(fragileTest, standardTest, registryToolIntegrationTest, sqlIntegrationTest) // When we override tests, we also break the cleanTest command. cleanTest.dependsOn(cleanFragileTest, cleanStandardTest, cleanRegistryToolIntegrationTest, cleanSqlIntegrationTest) project.build.dependsOn devtool project.build.dependsOn buildToolImage project.build.dependsOn ':stage'