mirror of
https://github.com/google/nomulus
synced 2026-07-10 18:13:02 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 19bc1c9c9c | |||
| c361c9e601 | |||
| aa0dcea537 | |||
| e920e4d201 | |||
| cd13f6c5d3 | |||
| 210de9340e | |||
| 5d58be6f0a | |||
| d8066ca752 | |||
| ca3ae9b0e4 | |||
| 295251ee78 | |||
| 7ca0e9387c | |||
| 4f988d42c7 | |||
| 9b47a6cfee | |||
| 9db4d1a082 | |||
| ec22d4d1a0 | |||
| 0fcf26def0 | |||
| 3d88ba4e1b | |||
| 580a3b6981 | |||
| 6990d6058f | |||
| dfeed63c40 | |||
| 9eac9621cb | |||
| b7efc5dd25 | |||
| 1911c11623 | |||
| b8df0bac24 | |||
| 0561c7754e | |||
| 904f16c8b5 | |||
| 3a7d71e411 | |||
| 1ded33ecea | |||
| bf4659f11c | |||
| bac1998d6a | |||
| 4a34369ba9 | |||
| db7d49801d | |||
| 0c52d209e5 | |||
| 73b98d298b | |||
| 7880aab386 |
@@ -31,10 +31,6 @@ def coreResourcesDir = "${rootDir}/core/build/resources/main"
|
||||
war {
|
||||
webInf {
|
||||
from "../../core/src/main/java/google/registry/env/common/${project.name}/WEB-INF"
|
||||
|
||||
from("${coreResourcesDir}/META-INF/persistence.xml") {
|
||||
into "classes/META-INF"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,12 +61,12 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.10.0
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.json:json:20160212
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.0
|
||||
org.junit.platform:junit-platform-commons:1.6.0
|
||||
org.junit.platform:junit-platform-engine:1.6.0
|
||||
org.junit.vintage:junit-vintage-engine:5.6.0
|
||||
org.junit:junit-bom:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.mockito:mockito-core:2.25.0
|
||||
org.objenesis:objenesis:2.6
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -61,12 +61,12 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.10.0
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.json:json:20160212
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.0
|
||||
org.junit.platform:junit-platform-commons:1.6.0
|
||||
org.junit.platform:junit-platform-engine:1.6.0
|
||||
org.junit.vintage:junit-vintage-engine:5.6.0
|
||||
org.junit:junit-bom:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.mockito:mockito-core:2.25.0
|
||||
org.objenesis:objenesis:2.6
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -61,12 +61,12 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.10.0
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.json:json:20160212
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.0
|
||||
org.junit.platform:junit-platform-commons:1.6.0
|
||||
org.junit.platform:junit-platform-engine:1.6.0
|
||||
org.junit.vintage:junit-vintage-engine:5.6.0
|
||||
org.junit:junit-bom:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.mockito:mockito-core:2.25.0
|
||||
org.objenesis:objenesis:2.6
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -61,12 +61,12 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.10.0
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.json:json:20160212
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.0
|
||||
org.junit.platform:junit-platform-commons:1.6.0
|
||||
org.junit.platform:junit-platform-engine:1.6.0
|
||||
org.junit.vintage:junit-vintage-engine:5.6.0
|
||||
org.junit:junit-bom:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.mockito:mockito-core:2.25.0
|
||||
org.objenesis:objenesis:2.6
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -20,10 +20,10 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.10.0
|
||||
org.eclipse.jgit:org.eclipse.jgit:4.4.1.201607150455-r
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.0
|
||||
org.junit.platform:junit-platform-commons:1.6.0
|
||||
org.junit.platform:junit-platform-engine:1.6.0
|
||||
org.junit.vintage:junit-vintage-engine:5.6.0
|
||||
org.junit:junit-bom:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -20,10 +20,10 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.10.0
|
||||
org.eclipse.jgit:org.eclipse.jgit:4.4.1.201607150455-r
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.0
|
||||
org.junit.platform:junit-platform-commons:1.6.0
|
||||
org.junit.platform:junit-platform-engine:1.6.0
|
||||
org.junit.vintage:junit-vintage-engine:5.6.0
|
||||
org.junit:junit-bom:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -21,10 +21,10 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.10.0
|
||||
org.eclipse.jgit:org.eclipse.jgit:4.4.1.201607150455-r
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.0
|
||||
org.junit.platform:junit-platform-commons:1.6.0
|
||||
org.junit.platform:junit-platform-engine:1.6.0
|
||||
org.junit.vintage:junit-vintage-engine:5.6.0
|
||||
org.junit:junit-bom:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -21,10 +21,10 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.10.0
|
||||
org.eclipse.jgit:org.eclipse.jgit:4.4.1.201607150455-r
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.0
|
||||
org.junit.platform:junit-platform-commons:1.6.0
|
||||
org.junit.platform:junit-platform-engine:1.6.0
|
||||
org.junit.vintage:junit-vintage-engine:5.6.0
|
||||
org.junit:junit-bom:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -99,6 +99,15 @@ PRESUBMITS = {
|
||||
"System.(out|err).println is only allowed in tools/ packages. Please "
|
||||
"use a logger instead.",
|
||||
|
||||
# ObjectifyService.register is restricted to main/ or AppEngineRule.
|
||||
PresubmitCheck(
|
||||
r".*\bObjectifyService\.register", "java", {
|
||||
"/build/", "/generated/", "node_modules/", "src/main/",
|
||||
"AppEngineRule.java"
|
||||
}):
|
||||
"ObjectifyService.register is not allowed in tests. Please use "
|
||||
"AppengineRule.register instead.",
|
||||
|
||||
# PostgreSQLContainer instantiation must specify docker tag
|
||||
PresubmitCheck(
|
||||
r"[\s\S]*new\s+PostgreSQLContainer(<[\s\S]*>)?\(\s*\)[\s\S]*",
|
||||
|
||||
@@ -177,6 +177,8 @@ dependencies {
|
||||
|
||||
compile deps['com.beust:jcommander']
|
||||
compile deps['com.google.api-client:google-api-client']
|
||||
compile deps['com.google.api-client:google-api-client-appengine']
|
||||
compile deps['com.google.api-client:google-api-client-servlet']
|
||||
compile deps['com.google.monitoring-client:metrics']
|
||||
compile deps['com.google.monitoring-client:stackdriver']
|
||||
compile deps['com.google.api-client:google-api-client-java6']
|
||||
@@ -216,6 +218,8 @@ dependencies {
|
||||
compile deps['com.google.oauth-client:google-oauth-client']
|
||||
compile deps['com.google.oauth-client:google-oauth-client-java6']
|
||||
compile deps['com.google.oauth-client:google-oauth-client-jetty']
|
||||
compile deps['com.google.oauth-client:google-oauth-client-appengine']
|
||||
compile deps['com.google.oauth-client:google-oauth-client-servlet']
|
||||
compile deps['com.google.re2j:re2j']
|
||||
compile deps['com.google.template:soy']
|
||||
compile deps['com.googlecode.json-simple:json-simple']
|
||||
@@ -262,6 +266,7 @@ dependencies {
|
||||
testCompile deps['org.seleniumhq.selenium:selenium-chrome-driver']
|
||||
testCompile deps['org.seleniumhq.selenium:selenium-java']
|
||||
testCompile deps['org.seleniumhq.selenium:selenium-remote-driver']
|
||||
runtimeOnly deps['org.slf4j:slf4j-jdk14']
|
||||
testCompile deps['org.testcontainers:jdbc']
|
||||
compile deps['org.testcontainers:postgresql']
|
||||
testCompile deps['org.testcontainers:selenium']
|
||||
@@ -290,6 +295,8 @@ dependencies {
|
||||
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')
|
||||
|
||||
testCompile deps['com.google.appengine:appengine-testing']
|
||||
testCompile deps['com.google.guava:guava-testlib']
|
||||
@@ -304,6 +311,8 @@ dependencies {
|
||||
testCompile deps['org.junit.jupiter:junit-jupiter-api']
|
||||
testCompile deps['org.junit.jupiter:junit-jupiter-engine']
|
||||
testCompile deps['org.junit.jupiter:junit-jupiter-migrationsupport']
|
||||
testCompile deps['org.junit.platform:junit-platform-runner']
|
||||
testCompile deps['org.junit.platform:junit-platform-suite-api']
|
||||
testCompile deps['org.junit.vintage:junit-vintage-engine']
|
||||
testCompile deps['org.mockito:mockito-core']
|
||||
runtime deps['org.postgresql:postgresql']
|
||||
@@ -641,6 +650,10 @@ artifacts {
|
||||
*/
|
||||
class FilteringTest extends Test {
|
||||
|
||||
FilteringTest() {
|
||||
useJUnitPlatform();
|
||||
}
|
||||
|
||||
private void applyTestFilter() {
|
||||
if (project.testFilter) {
|
||||
testNameIncludePatterns = project.testFilter.split(',')
|
||||
@@ -728,6 +741,10 @@ task registryToolIntegrationTest {
|
||||
|
||||
// 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.*']
|
||||
}
|
||||
@@ -847,6 +864,8 @@ task standardTest(type: FilteringTest) {
|
||||
includeAllTests()
|
||||
exclude fragileTestPatterns
|
||||
exclude outcastTestPatterns
|
||||
// See SqlIntegrationTestSuite.java
|
||||
exclude '**/*BeforeSuiteTest.*', '**/*AfterSuiteTest.*'
|
||||
|
||||
if (rootProject.findProperty("skipDockerIncompatibleTests") == "true") {
|
||||
exclude dockerIncompatibleTestPatterns
|
||||
@@ -879,11 +898,14 @@ createUberJar('nomulus', 'nomulus', 'google.registry.tools.RegistryTool')
|
||||
|
||||
// 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'
|
||||
|
||||
@@ -12,24 +12,24 @@ com.google.dagger:dagger-producers:2.21
|
||||
com.google.dagger:dagger-spi:2.21
|
||||
com.google.dagger:dagger:2.21
|
||||
com.google.errorprone:error_prone_annotation:2.3.3
|
||||
com.google.errorprone:error_prone_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_annotations:2.3.4
|
||||
com.google.errorprone:error_prone_check_api:2.3.3
|
||||
com.google.errorprone:error_prone_core:2.3.3
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.3
|
||||
com.google.errorprone:javac-shaded:9-dev-r4023-3
|
||||
com.google.googlejavaformat:google-java-format:1.5
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.0.1-jre
|
||||
com.google.guava:guava:28.2-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.j2objc:j2objc-annotations:1.1
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.google.protobuf:protobuf-java:3.4.0
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
com.squareup:javapoet:1.11.1
|
||||
com.squareup:javapoet:1.12.1
|
||||
javax.annotation:jsr250-api:1.0
|
||||
javax.inject:javax.inject:1
|
||||
javax.persistence:javax.persistence-api:2.2
|
||||
org.checkerframework:checker-compat-qual:2.5.3
|
||||
org.checkerframework:checker-qual:2.5.3
|
||||
org.checkerframework:checker-qual:2.10.0
|
||||
org.checkerframework:dataflow:2.5.3
|
||||
org.checkerframework:javacutil:2.5.3
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.pcollections:pcollections:2.1.2
|
||||
|
||||
@@ -235,6 +235,7 @@ org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
org.scijava:native-lib-loader:2.0.2
|
||||
org.slf4j:slf4j-api:1.7.28
|
||||
org.slf4j:slf4j-jdk14:1.7.28
|
||||
org.testcontainers:database-commons:1.12.1
|
||||
org.testcontainers:jdbc:1.12.1
|
||||
org.testcontainers:postgresql:1.12.1
|
||||
|
||||
@@ -232,6 +232,7 @@ org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
org.scijava:native-lib-loader:2.0.2
|
||||
org.slf4j:slf4j-api:1.7.28
|
||||
org.slf4j:slf4j-jdk14:1.7.28
|
||||
org.testcontainers:database-commons:1.12.1
|
||||
org.testcontainers:jdbc:1.12.1
|
||||
org.testcontainers:postgresql:1.12.1
|
||||
|
||||
@@ -232,6 +232,7 @@ org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
org.scijava:native-lib-loader:2.0.2
|
||||
org.slf4j:slf4j-api:1.7.28
|
||||
org.slf4j:slf4j-jdk14:1.7.28
|
||||
org.testcontainers:database-commons:1.12.1
|
||||
org.testcontainers:jdbc:1.12.1
|
||||
org.testcontainers:postgresql:1.12.1
|
||||
|
||||
@@ -12,24 +12,24 @@ com.google.dagger:dagger-producers:2.21
|
||||
com.google.dagger:dagger-spi:2.21
|
||||
com.google.dagger:dagger:2.21
|
||||
com.google.errorprone:error_prone_annotation:2.3.3
|
||||
com.google.errorprone:error_prone_annotations:2.3.3
|
||||
com.google.errorprone:error_prone_annotations:2.3.4
|
||||
com.google.errorprone:error_prone_check_api:2.3.3
|
||||
com.google.errorprone:error_prone_core:2.3.3
|
||||
com.google.errorprone:error_prone_type_annotations:2.3.3
|
||||
com.google.errorprone:javac-shaded:9-dev-r4023-3
|
||||
com.google.googlejavaformat:google-java-format:1.5
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.0.1-jre
|
||||
com.google.guava:guava:28.2-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.j2objc:j2objc-annotations:1.1
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.google.protobuf:protobuf-java:3.4.0
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
com.squareup:javapoet:1.11.1
|
||||
com.squareup:javapoet:1.12.1
|
||||
javax.annotation:jsr250-api:1.0
|
||||
javax.inject:javax.inject:1
|
||||
javax.persistence:javax.persistence-api:2.2
|
||||
org.checkerframework:checker-compat-qual:2.5.3
|
||||
org.checkerframework:checker-qual:2.5.3
|
||||
org.checkerframework:checker-qual:2.10.0
|
||||
org.checkerframework:dataflow:2.5.3
|
||||
org.checkerframework:javacutil:2.5.3
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.pcollections:pcollections:2.1.2
|
||||
|
||||
@@ -243,13 +243,16 @@ org.jboss:jandex:2.0.5.Final
|
||||
org.jetbrains:annotations:17.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:5.6.0
|
||||
org.junit.platform:junit-platform-commons:1.6.0
|
||||
org.junit.platform:junit-platform-engine:1.6.0
|
||||
org.junit.vintage:junit-vintage-engine:5.6.0
|
||||
org.junit:junit-bom:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.platform:junit-platform-launcher:1.6.1
|
||||
org.junit.platform:junit-platform-runner:1.6.1
|
||||
org.junit.platform:junit-platform-suite-api:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mockito:mockito-core:2.25.0
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
|
||||
@@ -241,13 +241,16 @@ org.jboss:jandex:2.0.5.Final
|
||||
org.jetbrains:annotations:17.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:5.6.0
|
||||
org.junit.platform:junit-platform-commons:1.6.0
|
||||
org.junit.platform:junit-platform-engine:1.6.0
|
||||
org.junit.vintage:junit-vintage-engine:5.6.0
|
||||
org.junit:junit-bom:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.platform:junit-platform-launcher:1.6.1
|
||||
org.junit.platform:junit-platform-runner:1.6.1
|
||||
org.junit.platform:junit-platform-suite-api:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mockito:mockito-core:2.25.0
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
|
||||
@@ -246,13 +246,16 @@ org.jboss:jandex:2.0.5.Final
|
||||
org.jetbrains:annotations:17.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:5.6.0
|
||||
org.junit.platform:junit-platform-commons:1.6.0
|
||||
org.junit.platform:junit-platform-engine:1.6.0
|
||||
org.junit.vintage:junit-vintage-engine:5.6.0
|
||||
org.junit:junit-bom:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.platform:junit-platform-launcher:1.6.1
|
||||
org.junit.platform:junit-platform-runner:1.6.1
|
||||
org.junit.platform:junit-platform-suite-api:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mockito:mockito-core:2.25.0
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
|
||||
@@ -246,13 +246,16 @@ org.jboss:jandex:2.0.5.Final
|
||||
org.jetbrains:annotations:17.0.0
|
||||
org.joda:joda-money:1.0.1
|
||||
org.json:json:20160810
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:5.6.0
|
||||
org.junit.platform:junit-platform-commons:1.6.0
|
||||
org.junit.platform:junit-platform-engine:1.6.0
|
||||
org.junit.vintage:junit-vintage-engine:5.6.0
|
||||
org.junit:junit-bom:5.6.0
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.platform:junit-platform-launcher:1.6.1
|
||||
org.junit.platform:junit-platform-runner:1.6.1
|
||||
org.junit.platform:junit-platform-suite-api:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.jvnet.staxex:stax-ex:1.8
|
||||
org.mockito:mockito-core:2.25.0
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
@@ -280,6 +283,7 @@ org.seleniumhq.selenium:selenium-remote-driver:3.141.59
|
||||
org.seleniumhq.selenium:selenium-safari-driver:3.141.59
|
||||
org.seleniumhq.selenium:selenium-support:3.141.59
|
||||
org.slf4j:slf4j-api:1.7.28
|
||||
org.slf4j:slf4j-jdk14:1.7.28
|
||||
org.testcontainers:database-commons:1.12.1
|
||||
org.testcontainers:jdbc:1.12.1
|
||||
org.testcontainers:postgresql:1.12.1
|
||||
|
||||
@@ -31,6 +31,7 @@ import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.util.AppEngineServiceUtils;
|
||||
import google.registry.util.Retrier;
|
||||
import javax.inject.Inject;
|
||||
@@ -158,6 +159,26 @@ public final class AsyncTaskEnqueuer {
|
||||
.param(PARAM_REQUESTED_TIME, now.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues a task to asynchronously re-lock a registry-locked domain after it was unlocked.
|
||||
*
|
||||
* <p>Note: the relockDuration must be present on the lock object.
|
||||
*/
|
||||
public void enqueueDomainRelock(RegistryLock lock) {
|
||||
checkArgument(
|
||||
lock.getRelockDuration().isPresent(),
|
||||
"Lock with ID %s not configured for relock",
|
||||
lock.getRevisionId());
|
||||
addTaskToQueueWithRetry(
|
||||
asyncActionsPushQueue,
|
||||
TaskOptions.Builder.withUrl(RelockDomainAction.PATH)
|
||||
.method(Method.POST)
|
||||
.param(
|
||||
RelockDomainAction.OLD_UNLOCK_REVISION_ID_PARAM,
|
||||
String.valueOf(lock.getRevisionId()))
|
||||
.countdownMillis(lock.getRelockDuration().get().getMillis()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a task to a queue with retrying, to avoid aborting the entire flow over a transient issue
|
||||
* enqueuing a task.
|
||||
|
||||
@@ -50,6 +50,7 @@ import javax.inject.Inject;
|
||||
public class RelockDomainAction implements Runnable {
|
||||
|
||||
public static final String PATH = "/_dr/task/relockDomain";
|
||||
public static final String OLD_UNLOCK_REVISION_ID_PARAM = "oldUnlockRevisionId";
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
@@ -59,7 +60,7 @@ public class RelockDomainAction implements Runnable {
|
||||
|
||||
@Inject
|
||||
public RelockDomainAction(
|
||||
@Parameter("oldUnlockRevisionId") long oldUnlockRevisionId,
|
||||
@Parameter(OLD_UNLOCK_REVISION_ID_PARAM) long oldUnlockRevisionId,
|
||||
DomainLockUtils domainLockUtils,
|
||||
Response response) {
|
||||
this.oldUnlockRevisionId = oldUnlockRevisionId;
|
||||
|
||||
@@ -1512,21 +1512,11 @@ public final class RegistryConfig {
|
||||
return CONFIG_SETTINGS.get().hibernate.hikariConnectionTimeout;
|
||||
}
|
||||
|
||||
/** Returns the minimum idle connections for HikariCP. */
|
||||
public static String getHibernateHikariMinimumIdle() {
|
||||
return CONFIG_SETTINGS.get().hibernate.hikariMinimumIdle;
|
||||
}
|
||||
|
||||
/** Returns the maximum pool size for HikariCP. */
|
||||
public static String getHibernateHikariMaximumPoolSize() {
|
||||
return CONFIG_SETTINGS.get().hibernate.hikariMaximumPoolSize;
|
||||
}
|
||||
|
||||
/** Returns the idle timeout for HikariCP. */
|
||||
public static String getHibernateHikariIdleTimeout() {
|
||||
return CONFIG_SETTINGS.get().hibernate.hikariIdleTimeout;
|
||||
}
|
||||
|
||||
/** Returns the roid suffix to be used for the roids of all contacts and hosts. */
|
||||
public static String getContactAndHostRoidSuffix() {
|
||||
return CONFIG_SETTINGS.get().registryPolicy.contactAndHostRoidSuffix;
|
||||
|
||||
@@ -112,9 +112,7 @@ public class RegistryConfigSettings {
|
||||
public String connectionIsolation;
|
||||
public String logSqlQueries;
|
||||
public String hikariConnectionTimeout;
|
||||
public String hikariMinimumIdle;
|
||||
public String hikariMaximumPoolSize;
|
||||
public String hikariIdleTimeout;
|
||||
}
|
||||
|
||||
/** Configuration for Cloud SQL. */
|
||||
|
||||
@@ -207,9 +207,17 @@ hibernate:
|
||||
|
||||
# Connection pool configurations.
|
||||
hikariConnectionTimeout: 20000
|
||||
hikariMinimumIdle: 0
|
||||
|
||||
# We occasionally received "Connection is not available, request timed out"
|
||||
# exception when setting minimumIdle to 0 and it turned out it is a bug (See
|
||||
# https://github.com/brettwooldridge/HikariCP/issues/1212) in HikariCP and
|
||||
# the workaround is to use a fixed size connection pool.
|
||||
#
|
||||
# HikariCP also recommends not setting minimumIdle for maximum performance
|
||||
# and responsiveness to spike demands (See
|
||||
# https://github.com/brettwooldridge/HikariCP).
|
||||
# TODO(b/154720215): Experiment with a smaller pool size.
|
||||
hikariMaximumPoolSize: 20
|
||||
hikariIdleTimeout: 300000
|
||||
|
||||
cloudSql:
|
||||
# jdbc url for the Cloud SQL database.
|
||||
|
||||
@@ -70,9 +70,11 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable {
|
||||
|
||||
/** The ID of the registrar that is currently sponsoring this resource. */
|
||||
@Index
|
||||
@Column(nullable = false)
|
||||
String currentSponsorClientId;
|
||||
|
||||
/** The ID of the registrar that created this resource. */
|
||||
@Column(nullable = false)
|
||||
String creationClientId;
|
||||
|
||||
/**
|
||||
@@ -88,7 +90,9 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable {
|
||||
// Map the method to XML, not the field, because if we map the field (with an adaptor class) it
|
||||
// will never be omitted from the xml even if the timestamp inside creationTime is null and we
|
||||
// return null from the adaptor. (Instead it gets written as an empty tag.)
|
||||
@Index CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null);
|
||||
@Column(nullable = false)
|
||||
@Index
|
||||
CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null);
|
||||
|
||||
/**
|
||||
* The time when this resource was or will be deleted.
|
||||
@@ -131,7 +135,7 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable {
|
||||
@Transient
|
||||
ImmutableSortedMap<DateTime, Key<CommitLogManifest>> revisions = ImmutableSortedMap.of();
|
||||
|
||||
public final String getRepoId() {
|
||||
public String getRepoId() {
|
||||
return repoId;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,13 +16,14 @@ package google.registry.model.contact;
|
||||
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
import google.registry.model.eppcommon.Address;
|
||||
import javax.persistence.Embeddable;
|
||||
|
||||
/**
|
||||
* EPP Contact Address
|
||||
*
|
||||
* <p>This class is embedded inside the {@link PostalInfo} of an EPP contact to hold its
|
||||
* address. The fields are all defined in parent class {@link Address}, but the subclass is still
|
||||
* necessary to pick up the contact namespace.
|
||||
* <p>This class is embedded inside the {@link PostalInfo} of an EPP contact to hold its address.
|
||||
* The fields are all defined in parent class {@link Address}, but the subclass is still necessary
|
||||
* to pick up the contact namespace.
|
||||
*
|
||||
* <p>This does not implement {@code Overlayable} because it is intended to be bulk replaced on
|
||||
* update.
|
||||
@@ -30,6 +31,7 @@ import google.registry.model.eppcommon.Address;
|
||||
* @see PostalInfo
|
||||
*/
|
||||
@Embed
|
||||
@Embeddable
|
||||
public class ContactAddress extends Address {
|
||||
|
||||
/** Builder for {@link ContactAddress}. */
|
||||
|
||||
@@ -20,6 +20,7 @@ import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/** A version of authInfo specifically for contacts. */
|
||||
@Embed
|
||||
@javax.persistence.Embeddable
|
||||
@XmlType(namespace = "urn:ietf:params:xml:ns:contact-1.0")
|
||||
public class ContactAuthInfo extends AuthInfo {
|
||||
public static ContactAuthInfo create(PasswordAuth pw) {
|
||||
|
||||
@@ -16,17 +16,19 @@ package google.registry.model.contact;
|
||||
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
import google.registry.model.eppcommon.PhoneNumber;
|
||||
import javax.persistence.Embeddable;
|
||||
|
||||
/**
|
||||
* EPP Contact Phone Number
|
||||
*
|
||||
* <p>This class is embedded inside a {@link ContactResource} hold the phone number of an EPP
|
||||
* contact. The fields are all defined in the parent class {@link PhoneNumber}, but the subclass is
|
||||
* contact. The fields are all defined in the parent class {@link PhoneNumber}, but the subclass is
|
||||
* still necessary to pick up the contact namespace.
|
||||
*
|
||||
* @see ContactResource
|
||||
*/
|
||||
@Embed
|
||||
@Embeddable
|
||||
public class ContactPhoneNumber extends PhoneNumber {
|
||||
|
||||
/** Builder for {@link ContactPhoneNumber}. */
|
||||
|
||||
@@ -33,6 +33,11 @@ import google.registry.model.transfer.TransferData;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import javax.persistence.AttributeOverride;
|
||||
import javax.persistence.AttributeOverrides;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Transient;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -43,9 +48,19 @@ import org.joda.time.DateTime;
|
||||
*/
|
||||
@ReportedOn
|
||||
@Entity
|
||||
@javax.persistence.Entity(name = "Contact")
|
||||
@javax.persistence.Table(
|
||||
name = "Contact",
|
||||
indexes = {
|
||||
@javax.persistence.Index(columnList = "creationTime"),
|
||||
@javax.persistence.Index(columnList = "currentSponsorClientId"),
|
||||
@javax.persistence.Index(columnList = "deletionTime"),
|
||||
@javax.persistence.Index(columnList = "contactId", unique = true),
|
||||
@javax.persistence.Index(columnList = "searchName")
|
||||
})
|
||||
@ExternalMessagingName("contact")
|
||||
public class ContactResource extends EppResource implements
|
||||
ForeignKeyedEppResource, ResourceWithTransferData {
|
||||
public class ContactResource extends EppResource
|
||||
implements ForeignKeyedEppResource, ResourceWithTransferData {
|
||||
|
||||
/**
|
||||
* Unique identifier for this contact.
|
||||
@@ -61,13 +76,55 @@ public class ContactResource extends EppResource implements
|
||||
* US-ASCII character set. Personal info; cleared by {@link Builder#wipeOut}.
|
||||
*/
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "name", column = @Column(name = "addr_local_name")),
|
||||
@AttributeOverride(name = "org", column = @Column(name = "addr_local_org")),
|
||||
@AttributeOverride(name = "type", column = @Column(name = "addr_local_type")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine1",
|
||||
column = @Column(name = "addr_local_street_line1")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine2",
|
||||
column = @Column(name = "addr_local_street_line2")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine3",
|
||||
column = @Column(name = "addr_local_street_line3")),
|
||||
@AttributeOverride(name = "address.city", column = @Column(name = "addr_local_city")),
|
||||
@AttributeOverride(name = "address.state", column = @Column(name = "addr_local_state")),
|
||||
@AttributeOverride(name = "address.zip", column = @Column(name = "addr_local_zip")),
|
||||
@AttributeOverride(
|
||||
name = "address.countryCode",
|
||||
column = @Column(name = "addr_local_country_code"))
|
||||
})
|
||||
PostalInfo localizedPostalInfo;
|
||||
|
||||
/**
|
||||
* Internationalized postal info for the contact. Personal info; cleared by
|
||||
* {@link Builder#wipeOut}.
|
||||
* Internationalized postal info for the contact. Personal info; cleared by {@link
|
||||
* Builder#wipeOut}.
|
||||
*/
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "name", column = @Column(name = "addr_i18n_name")),
|
||||
@AttributeOverride(name = "org", column = @Column(name = "addr_i18n_org")),
|
||||
@AttributeOverride(name = "type", column = @Column(name = "addr_i18n_type")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine1",
|
||||
column = @Column(name = "addr_i18n_street_line1")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine2",
|
||||
column = @Column(name = "addr_i18n_street_line2")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine3",
|
||||
column = @Column(name = "addr_i18n_street_line3")),
|
||||
@AttributeOverride(name = "address.city", column = @Column(name = "addr_i18n_city")),
|
||||
@AttributeOverride(name = "address.state", column = @Column(name = "addr_i18n_state")),
|
||||
@AttributeOverride(name = "address.zip", column = @Column(name = "addr_i18n_zip")),
|
||||
@AttributeOverride(
|
||||
name = "address.countryCode",
|
||||
column = @Column(name = "addr_i18n_country_code"))
|
||||
})
|
||||
PostalInfo internationalizedPostalInfo;
|
||||
|
||||
/**
|
||||
@@ -80,10 +137,20 @@ public class ContactResource extends EppResource implements
|
||||
|
||||
/** Contact’s voice number. Personal info; cleared by {@link Builder#wipeOut}. */
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "phoneNumber", column = @Column(name = "voice_phone_number")),
|
||||
@AttributeOverride(name = "extension", column = @Column(name = "voice_phone_extension")),
|
||||
})
|
||||
ContactPhoneNumber voice;
|
||||
|
||||
/** Contact’s fax number. Personal info; cleared by {@link Builder#wipeOut}. */
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "phoneNumber", column = @Column(name = "fax_phone_number")),
|
||||
@AttributeOverride(name = "extension", column = @Column(name = "fax_phone_extension")),
|
||||
})
|
||||
ContactPhoneNumber fax;
|
||||
|
||||
/** Contact’s email address. Personal info; cleared by {@link Builder#wipeOut}. */
|
||||
@@ -91,10 +158,16 @@ public class ContactResource extends EppResource implements
|
||||
String email;
|
||||
|
||||
/** Authorization info (aka transfer secret) of the contact. */
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "pw.value", column = @Column(name = "auth_info_value")),
|
||||
@AttributeOverride(name = "pw.repoId", column = @Column(name = "auth_info_repo_id")),
|
||||
})
|
||||
ContactAuthInfo authInfo;
|
||||
|
||||
/** Data about any pending or past transfers on this contact. */
|
||||
TransferData transferData;
|
||||
// TODO(b/153363295): Figure out how to persist transfer data
|
||||
@Transient TransferData transferData;
|
||||
|
||||
/**
|
||||
* The time that this resource was last transferred.
|
||||
@@ -107,6 +180,16 @@ public class ContactResource extends EppResource implements
|
||||
// the wipeOut() function, so that data is not kept around for deleted contacts.
|
||||
|
||||
/** Disclosure policy. */
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "name", column = @Column(name = "disclose_types_name")),
|
||||
@AttributeOverride(name = "org", column = @Column(name = "disclose_types_org")),
|
||||
@AttributeOverride(name = "addr", column = @Column(name = "disclose_types_addr")),
|
||||
@AttributeOverride(name = "flag", column = @Column(name = "disclose_mode_flag")),
|
||||
@AttributeOverride(name = "voice.marked", column = @Column(name = "disclose_show_voice")),
|
||||
@AttributeOverride(name = "fax.marked", column = @Column(name = "disclose_show_fax")),
|
||||
@AttributeOverride(name = "email.marked", column = @Column(name = "disclose_show_email"))
|
||||
})
|
||||
Disclose disclose;
|
||||
|
||||
public String getContactId() {
|
||||
|
||||
@@ -22,11 +22,14 @@ import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.eppcommon.PresenceMarker;
|
||||
import java.util.List;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/** The "discloseType" from {@link "http://tools.ietf.org/html/rfc5733"}. */
|
||||
@Embed
|
||||
@Embeddable
|
||||
@XmlType(propOrder = {"name", "org", "addr", "voice", "fax", "email"})
|
||||
public class Disclose extends ImmutableObject {
|
||||
|
||||
@@ -36,11 +39,11 @@ public class Disclose extends ImmutableObject {
|
||||
|
||||
List<PostalInfoChoice> addr;
|
||||
|
||||
PresenceMarker voice;
|
||||
@Embedded PresenceMarker voice;
|
||||
|
||||
PresenceMarker fax;
|
||||
@Embedded PresenceMarker fax;
|
||||
|
||||
PresenceMarker email;
|
||||
@Embedded PresenceMarker email;
|
||||
|
||||
@XmlAttribute
|
||||
Boolean flag;
|
||||
|
||||
@@ -21,6 +21,9 @@ import google.registry.model.Buildable;
|
||||
import google.registry.model.Buildable.Overlayable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import java.util.Optional;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlEnumValue;
|
||||
@@ -29,10 +32,11 @@ import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
/**
|
||||
* Implementation of both "postalInfoType" and "chgPostalInfoType" from
|
||||
* {@link "http://tools.ietf.org/html/rfc5733"}.
|
||||
* Implementation of both "postalInfoType" and "chgPostalInfoType" from {@link
|
||||
* "http://tools.ietf.org/html/rfc5733"}.
|
||||
*/
|
||||
@Embed
|
||||
@Embeddable
|
||||
@XmlType(propOrder = {"name", "org", "address", "type"})
|
||||
public class PostalInfo extends ImmutableObject implements Overlayable<PostalInfo> {
|
||||
|
||||
@@ -53,6 +57,7 @@ public class PostalInfo extends ImmutableObject implements Overlayable<PostalInf
|
||||
@XmlElement(name = "addr")
|
||||
ContactAddress address;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@XmlAttribute
|
||||
Type type;
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ import google.registry.model.registry.Registry;
|
||||
import google.registry.model.transfer.TransferData;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.schema.replay.DatastoreAndSqlEntity;
|
||||
import google.registry.util.CollectionUtils;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
@@ -78,6 +79,7 @@ import javax.persistence.AttributeOverrides;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.Transient;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Interval;
|
||||
@@ -105,7 +107,7 @@ import org.joda.time.Interval;
|
||||
})
|
||||
@ExternalMessagingName("domain")
|
||||
public class DomainBase extends EppResource
|
||||
implements ForeignKeyedEppResource, ResourceWithTransferData {
|
||||
implements ForeignKeyedEppResource, ResourceWithTransferData, DatastoreAndSqlEntity {
|
||||
|
||||
/** The max number of years that a domain can be registered for, as set by ICANN policy. */
|
||||
public static final int MAX_REGISTRATION_YEARS = 10;
|
||||
@@ -141,7 +143,10 @@ public class DomainBase extends EppResource
|
||||
*/
|
||||
@Index @ElementCollection @Transient Set<Key<HostResource>> nsHosts;
|
||||
|
||||
@Ignore @Transient Set<VKey<HostResource>> nsHostVKeys;
|
||||
@Ignore
|
||||
@ElementCollection
|
||||
@JoinTable(name = "DomainHost")
|
||||
Set<VKey<HostResource>> nsHostVKeys;
|
||||
|
||||
/**
|
||||
* The union of the contacts visible via {@link #getContacts} and {@link #getRegistrant}.
|
||||
|
||||
@@ -18,6 +18,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
import javax.xml.bind.annotation.XmlValue;
|
||||
@@ -31,17 +33,21 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
* "e164Type" type from {@link "http://tools.ietf.org/html/draft-lozano-tmch-smd"}.
|
||||
*
|
||||
* <blockquote>
|
||||
*
|
||||
* <p>"Contact telephone number structure is derived from structures defined in [ITU.E164.2005].
|
||||
* Telephone numbers described in this mapping are character strings that MUST begin with a plus
|
||||
* sign ("+", ASCII value 0x002B), followed by a country code defined in [ITU.E164.2005], followed
|
||||
* by a dot (".", ASCII value 0x002E), followed by a sequence of digits representing the telephone
|
||||
* number. An optional "x" attribute is provided to note telephone extension information."
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* @see google.registry.model.contact.ContactPhoneNumber
|
||||
* @see google.registry.model.mark.MarkPhoneNumber
|
||||
*/
|
||||
@XmlTransient
|
||||
@Embeddable
|
||||
@MappedSuperclass
|
||||
public class PhoneNumber extends ImmutableObject {
|
||||
|
||||
@XmlValue
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.model.eppcommon;
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
|
||||
/**
|
||||
@@ -26,6 +27,7 @@ import javax.xml.bind.annotation.XmlTransient;
|
||||
* {@code <foo></foo>}, and will unmarshal always to {@code <foo/>}.
|
||||
*/
|
||||
@Embed
|
||||
@Embeddable
|
||||
public class PresenceMarker extends ImmutableObject implements Serializable {
|
||||
@XmlTransient
|
||||
boolean marked = true;
|
||||
|
||||
@@ -34,23 +34,27 @@ import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.transfer.TransferData;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.persistence.WithStringVKey;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.ElementCollection;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* A persistable Host resource including mutable and non-mutable fields.
|
||||
*
|
||||
* <p>A host's {@link TransferData} is stored on the superordinate domain. Non-subordinate hosts
|
||||
* <p>A host's {@link TransferData} is stored on the superordinate domain. Non-subordinate hosts
|
||||
* don't carry a full set of TransferData; all they have is lastTransferTime.
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc5732">RFC 5732</a>
|
||||
*/
|
||||
@ReportedOn
|
||||
@Entity
|
||||
@javax.persistence.Entity
|
||||
@ExternalMessagingName("host")
|
||||
@WithStringVKey
|
||||
public class HostResource extends EppResource implements ForeignKeyedEppResource {
|
||||
|
||||
/**
|
||||
@@ -64,8 +68,7 @@ public class HostResource extends EppResource implements ForeignKeyedEppResource
|
||||
String fullyQualifiedHostName;
|
||||
|
||||
/** IP Addresses for this host. Can be null if this is an external host. */
|
||||
@Index
|
||||
Set<InetAddress> inetAddresses;
|
||||
@Index @ElementCollection Set<InetAddress> inetAddresses;
|
||||
|
||||
/** The superordinate domain of this host, or null if this is an external host. */
|
||||
@Index
|
||||
|
||||
@@ -151,11 +151,14 @@ public class ObjectifyService {
|
||||
String kind = Key.getKind(clazz);
|
||||
boolean registered = factory().getMetadata(kind) != null;
|
||||
if (clazz.isAnnotationPresent(Entity.class)) {
|
||||
// Objectify silently ignores re-registrations for a given kind string, even if the classes
|
||||
// being registered are distinct. Throw an exception if that would happen here.
|
||||
checkState(!registered,
|
||||
// Objectify silently replaces current registration for a given kind string when a different
|
||||
// class is registered again for this kind. For simplicity's sake, throw an exception on any
|
||||
// re-registration.
|
||||
checkState(
|
||||
!registered,
|
||||
"Kind '%s' already registered, cannot register new @Entity %s",
|
||||
kind, clazz.getCanonicalName());
|
||||
kind,
|
||||
clazz.getCanonicalName());
|
||||
} else if (clazz.isAnnotationPresent(EntitySubclass.class)) {
|
||||
// Ensure that any @EntitySubclass classes have also had their parent @Entity registered,
|
||||
// which Objectify nominally requires but doesn't enforce in 4.x (though it may in 5.x).
|
||||
|
||||
@@ -73,6 +73,7 @@ import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.common.EntityGroupRoot;
|
||||
import google.registry.model.registrar.Registrar.BillingAccountEntry.CurrencyMapper;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.schema.replay.DatastoreAndSqlEntity;
|
||||
import google.registry.util.CidrAddressBlock;
|
||||
import java.security.cert.CertificateParsingException;
|
||||
import java.util.Comparator;
|
||||
@@ -107,11 +108,12 @@ import org.joda.time.DateTime;
|
||||
columnList = "ianaIdentifier",
|
||||
name = "registrar_iana_identifier_idx"),
|
||||
})
|
||||
public class Registrar extends ImmutableObject implements Buildable, Jsonifiable {
|
||||
public class Registrar extends ImmutableObject
|
||||
implements Buildable, Jsonifiable, DatastoreAndSqlEntity {
|
||||
|
||||
/** Represents the type of a registrar entity. */
|
||||
public enum Type {
|
||||
/** A real-world, third-party registrar. Should have non-null IANA and billing IDs. */
|
||||
/** A real-world, third-party registrar. Should have non-null IANA and billing IDs. */
|
||||
REAL(Objects::nonNull),
|
||||
|
||||
/**
|
||||
@@ -392,8 +394,6 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||
*/
|
||||
@Nullable
|
||||
@Mapify(CurrencyMapper.class)
|
||||
@org.hibernate.annotations.Type(
|
||||
type = "google.registry.persistence.converter.CurrencyToBillingMapUserType")
|
||||
Map<CurrencyUnit, BillingAccountEntry> billingAccountMap;
|
||||
|
||||
/** A billing account entry for this registrar, consisting of a currency and an account Id. */
|
||||
|
||||
@@ -19,6 +19,7 @@ import static com.google.common.base.Strings.emptyToNull;
|
||||
import static google.registry.util.DomainNameUtils.canonicalizeDomainName;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import google.registry.model.Buildable.GenericBuilder;
|
||||
import google.registry.model.ImmutableObject;
|
||||
@@ -83,6 +84,13 @@ public abstract class DomainLabelEntry<T extends Comparable<?>, D extends Domain
|
||||
"Label '%s' must be in puny-coded, lower-case form",
|
||||
getInstance().label);
|
||||
checkArgumentNotNull(getInstance().getValue(), "Value must be specified");
|
||||
// Verify that the label creates a valid SLD if we add a TLD to the end of it.
|
||||
// We require that the label is not already a full domain name including a dot.
|
||||
// Domain name validation is tricky, so let InternetDomainName handle it for us.
|
||||
checkArgument(
|
||||
InternetDomainName.from(getInstance().label + ".tld").parts().size() == 2,
|
||||
"Label %s must not be a multi-level domain name",
|
||||
getInstance().label);
|
||||
return super.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package google.registry.model.server;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.isAtOrAfter;
|
||||
|
||||
@@ -29,7 +28,6 @@ import com.googlecode.objectify.annotation.Id;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.NotBackedUp;
|
||||
import google.registry.model.annotations.NotBackedUp.Reason;
|
||||
import google.registry.schema.server.LockDao;
|
||||
import google.registry.util.RequestStatusChecker;
|
||||
import google.registry.util.RequestStatusCheckerImpl;
|
||||
import java.io.Serializable;
|
||||
@@ -41,8 +39,8 @@ import org.joda.time.Duration;
|
||||
/**
|
||||
* A lock on some shared resource.
|
||||
*
|
||||
* <p>Locks are either specific to a tld or global to the entire system, in which case a tld of
|
||||
* null is used.
|
||||
* <p>Locks are either specific to a tld or global to the entire system, in which case a tld of null
|
||||
* is used.
|
||||
*
|
||||
* <p>This is the "barebone" lock implementation, that requires manual locking and unlocking. For
|
||||
* safe calls that automatically lock and unlock, see LockHandler.
|
||||
@@ -197,18 +195,6 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
|
||||
// Checking if an unexpired lock still exists - if so, the lock can't be acquired.
|
||||
Lock lock = ofy().load().type(Lock.class).id(lockId).now();
|
||||
try {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
Optional<google.registry.schema.server.Lock> cloudSqlLockOptional =
|
||||
LockDao.load(resourceName, tld);
|
||||
LockDao.compare(Optional.ofNullable(lock), cloudSqlLockOptional);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.atSevere().withCause(e).log(
|
||||
"Issue loading and comparing lock from Cloud SQL");
|
||||
}
|
||||
if (lock != null) {
|
||||
logger.atInfo().log(
|
||||
"Loaded existing lock: %s for request: %s", lock.lockId, lock.requestLogId);
|
||||
@@ -233,25 +219,6 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
// don't need to be backed up.
|
||||
ofy().saveWithoutBackup().entity(newLock);
|
||||
|
||||
// create and save the lock to Cloud SQL
|
||||
try {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
google.registry.schema.server.Lock cloudSqlLock =
|
||||
google.registry.schema.server.Lock.create(
|
||||
resourceName,
|
||||
Optional.ofNullable(tld).orElse("GLOBAL"),
|
||||
requestStatusChecker.getLogId(),
|
||||
now,
|
||||
leaseLength);
|
||||
LockDao.save(cloudSqlLock);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.atSevere().withCause(e).log(
|
||||
"Error saving lock to Cloud SQL: %s", newLock);
|
||||
}
|
||||
|
||||
return AcquireResult.create(now, lock, newLock, lockState);
|
||||
});
|
||||
|
||||
@@ -270,36 +237,12 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
// this can happen if release() is called around the expiration time and the lock
|
||||
// expires underneath us.
|
||||
Lock loadedLock = ofy().load().type(Lock.class).id(lockId).now();
|
||||
try {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
Optional<google.registry.schema.server.Lock> cloudSqlLockOptional =
|
||||
LockDao.load(resourceName, tld);
|
||||
LockDao.compare(Optional.ofNullable(loadedLock), cloudSqlLockOptional);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.atSevere().withCause(e).log(
|
||||
"Issue loading and comparing lock from Cloud SQL");
|
||||
}
|
||||
if (Lock.this.equals(loadedLock)) {
|
||||
// Use noBackupOfy() so that we don't create a commit log entry for deleting the
|
||||
// lock.
|
||||
logger.atInfo().log("Deleting lock: %s", lockId);
|
||||
ofy().deleteWithoutBackup().entity(Lock.this);
|
||||
|
||||
// Remove the lock from Cloud SQL
|
||||
try {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
LockDao.delete(
|
||||
resourceName, Optional.ofNullable(tld).orElse("GLOBAL")));
|
||||
} catch (Exception e) {
|
||||
logger.atSevere().withCause(e).log(
|
||||
"Error deleting lock from Cloud SQL: %s", loadedLock);
|
||||
}
|
||||
|
||||
lockMetrics.recordRelease(
|
||||
resourceName, tld, new Duration(acquiredTime, tm().getTransactionTime()));
|
||||
} else {
|
||||
|
||||
@@ -16,6 +16,7 @@ package google.registry.module.frontend;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Subcomponent;
|
||||
import google.registry.batch.BatchModule;
|
||||
import google.registry.dns.DnsModule;
|
||||
import google.registry.flows.EppTlsAction;
|
||||
import google.registry.flows.FlowComponent;
|
||||
@@ -38,6 +39,7 @@ import google.registry.ui.server.registrar.RegistryLockVerifyAction;
|
||||
@RequestScope
|
||||
@Subcomponent(
|
||||
modules = {
|
||||
BatchModule.class,
|
||||
DnsModule.class,
|
||||
EppTlsModule.class,
|
||||
RegistrarConsoleModule.class,
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.PostLoad;
|
||||
import javax.persistence.PostPersist;
|
||||
import javax.persistence.PostRemove;
|
||||
import javax.persistence.PostUpdate;
|
||||
import javax.persistence.PrePersist;
|
||||
import javax.persistence.PreRemove;
|
||||
import javax.persistence.PreUpdate;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
/**
|
||||
* A listener class to invoke entity callbacks in cases where Hibernate doesn't invoke the callback
|
||||
* as expected.
|
||||
*
|
||||
* <p>JPA defines a few annotations, e.g. {@link PostLoad}, that we can use for the application to
|
||||
* react to certain events that occur inside the persistence mechanism. However, Hibernate only
|
||||
* supports a few basic use cases, e.g. defining a {@link PostLoad} method directly in an {@link
|
||||
* javax.persistence.Entity} class or in an {@link Embeddable} class. If the annotated method is
|
||||
* defined in an {@link Embeddable} class that is a property of another {@link Embeddable} class, or
|
||||
* it is defined in a parent class of the {@link Embeddable} class, Hibernate doesn't invoke it.
|
||||
*
|
||||
* <p>This listener is added in core/src/main/resources/META-INF/orm.xml as a default entity
|
||||
* listener whose annotated methods will be invoked by Hibernate when corresponding events happen.
|
||||
* For example, {@link EntityCallbacksListener#prePersist} will be invoked before the entity is
|
||||
* persisted to the database, then it will recursively invoke any other {@link PrePersist} method
|
||||
* that should be invoked but not handled by Hibernate due to the bug.
|
||||
*
|
||||
* @see <a
|
||||
* href="https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#events-jpa-callbacks">JPA
|
||||
* Callbacks</a>
|
||||
* @see <a href="https://hibernate.atlassian.net/browse/HHH-13316">HHH-13316</a>
|
||||
*/
|
||||
public class EntityCallbacksListener {
|
||||
|
||||
@PrePersist
|
||||
void prePersist(Object entity) {
|
||||
EntityCallbackExecutor.create(PrePersist.class).execute(entity, entity.getClass());
|
||||
}
|
||||
|
||||
@PreRemove
|
||||
void preRemove(Object entity) {
|
||||
EntityCallbackExecutor.create(PreRemove.class).execute(entity, entity.getClass());
|
||||
}
|
||||
|
||||
@PostPersist
|
||||
void postPersist(Object entity) {
|
||||
EntityCallbackExecutor.create(PostPersist.class).execute(entity, entity.getClass());
|
||||
}
|
||||
|
||||
@PostRemove
|
||||
void postRemove(Object entity) {
|
||||
EntityCallbackExecutor.create(PostRemove.class).execute(entity, entity.getClass());
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
void preUpdate(Object entity) {
|
||||
EntityCallbackExecutor.create(PreUpdate.class).execute(entity, entity.getClass());
|
||||
}
|
||||
|
||||
@PostUpdate
|
||||
void postUpdate(Object entity) {
|
||||
EntityCallbackExecutor.create(PostUpdate.class).execute(entity, entity.getClass());
|
||||
}
|
||||
|
||||
@PostLoad
|
||||
void postLoad(Object entity) {
|
||||
EntityCallbackExecutor.create(PostLoad.class).execute(entity, entity.getClass());
|
||||
}
|
||||
|
||||
private static class EntityCallbackExecutor {
|
||||
Class<? extends Annotation> callbackType;
|
||||
|
||||
private EntityCallbackExecutor(Class<? extends Annotation> callbackType) {
|
||||
this.callbackType = callbackType;
|
||||
}
|
||||
|
||||
private static EntityCallbackExecutor create(Class<? extends Annotation> callbackType) {
|
||||
return new EntityCallbackExecutor(callbackType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes eligible callbacks in {@link Embedded} properties recursively.
|
||||
*
|
||||
* @param entity the Java object of the entity class
|
||||
* @param entityType either the type of the entity or an ancestor type
|
||||
*/
|
||||
private void execute(Object entity, Class<?> entityType) {
|
||||
Class<?> parentType = entityType.getSuperclass();
|
||||
if (parentType != null && parentType.isAnnotationPresent(MappedSuperclass.class)) {
|
||||
execute(entity, parentType);
|
||||
}
|
||||
|
||||
findEmbeddedProperties(entity, entityType)
|
||||
.forEach(
|
||||
normalEmbedded -> {
|
||||
// For each normal embedded property, we don't execute its callback method because
|
||||
// it is handled by Hibernate. However, for the embedded property defined in the
|
||||
// entity's parent class, we need to treat it as a nested embedded property and
|
||||
// invoke its callback function.
|
||||
if (entity.getClass().equals(entityType)) {
|
||||
executeCallbackForNormalEmbeddedProperty(
|
||||
normalEmbedded, normalEmbedded.getClass());
|
||||
} else {
|
||||
executeCallbackForNestedEmbeddedProperty(
|
||||
normalEmbedded, normalEmbedded.getClass());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void executeCallbackForNestedEmbeddedProperty(
|
||||
Object nestedEmbeddedObject, Class<?> nestedEmbeddedType) {
|
||||
Class<?> parentType = nestedEmbeddedType.getSuperclass();
|
||||
if (parentType != null && parentType.isAnnotationPresent(MappedSuperclass.class)) {
|
||||
executeCallbackForNestedEmbeddedProperty(nestedEmbeddedObject, parentType);
|
||||
}
|
||||
|
||||
findEmbeddedProperties(nestedEmbeddedObject, nestedEmbeddedType)
|
||||
.forEach(
|
||||
embeddedProperty ->
|
||||
executeCallbackForNestedEmbeddedProperty(
|
||||
embeddedProperty, embeddedProperty.getClass()));
|
||||
|
||||
for (Method method : nestedEmbeddedType.getDeclaredMethods()) {
|
||||
if (method.isAnnotationPresent(callbackType)) {
|
||||
invokeMethod(method, nestedEmbeddedObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void executeCallbackForNormalEmbeddedProperty(
|
||||
Object normalEmbeddedObject, Class<?> normalEmbeddedType) {
|
||||
Class<?> parentType = normalEmbeddedType.getSuperclass();
|
||||
if (parentType != null && parentType.isAnnotationPresent(MappedSuperclass.class)) {
|
||||
executeCallbackForNormalEmbeddedProperty(normalEmbeddedObject, parentType);
|
||||
}
|
||||
|
||||
findEmbeddedProperties(normalEmbeddedObject, normalEmbeddedType)
|
||||
.forEach(
|
||||
embeddedProperty ->
|
||||
executeCallbackForNestedEmbeddedProperty(
|
||||
embeddedProperty, embeddedProperty.getClass()));
|
||||
}
|
||||
|
||||
private Stream<Object> findEmbeddedProperties(Object object, Class<?> clazz) {
|
||||
return Arrays.stream(clazz.getDeclaredFields())
|
||||
.filter(field -> !field.isAnnotationPresent(Transient.class))
|
||||
.filter(
|
||||
field ->
|
||||
field.isAnnotationPresent(Embedded.class)
|
||||
|| field.getType().isAnnotationPresent(Embeddable.class))
|
||||
.filter(field -> !Modifier.isStatic(field.getModifiers()))
|
||||
.map(field -> getFieldObject(field, object))
|
||||
.filter(Objects::nonNull);
|
||||
}
|
||||
|
||||
private static Object getFieldObject(Field field, Object object) {
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
return field.get(object);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void invokeMethod(Method method, Object object) {
|
||||
method.setAccessible(true);
|
||||
try {
|
||||
method.invoke(object);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
package google.registry.persistence;
|
||||
|
||||
import google.registry.persistence.converter.StringCollectionDescriptor;
|
||||
import google.registry.persistence.converter.StringMapDescriptor;
|
||||
import java.sql.Types;
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.dialect.PostgreSQL95Dialect;
|
||||
@@ -26,7 +27,7 @@ public class NomulusPostgreSQLDialect extends PostgreSQL95Dialect {
|
||||
registerColumnType(Types.VARCHAR, "text");
|
||||
registerColumnType(Types.TIMESTAMP_WITH_TIMEZONE, "timestamptz");
|
||||
registerColumnType(Types.TIMESTAMP, "timestamptz");
|
||||
registerColumnType(Types.OTHER, "hstore");
|
||||
registerColumnType(StringMapDescriptor.COLUMN_TYPE, StringMapDescriptor.COLUMN_NAME);
|
||||
registerColumnType(
|
||||
StringCollectionDescriptor.COLUMN_TYPE, StringCollectionDescriptor.COLUMN_DDL_NAME);
|
||||
}
|
||||
@@ -37,5 +38,7 @@ public class NomulusPostgreSQLDialect extends PostgreSQL95Dialect {
|
||||
super.contributeTypes(typeContributions, serviceRegistry);
|
||||
typeContributions.contributeJavaTypeDescriptor(StringCollectionDescriptor.getInstance());
|
||||
typeContributions.contributeSqlTypeDescriptor(StringCollectionDescriptor.getInstance());
|
||||
typeContributions.contributeJavaTypeDescriptor(StringMapDescriptor.getInstance());
|
||||
typeContributions.contributeSqlTypeDescriptor(StringMapDescriptor.getInstance());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,7 @@ package google.registry.persistence;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static google.registry.config.RegistryConfig.getHibernateConnectionIsolation;
|
||||
import static google.registry.config.RegistryConfig.getHibernateHikariConnectionTimeout;
|
||||
import static google.registry.config.RegistryConfig.getHibernateHikariIdleTimeout;
|
||||
import static google.registry.config.RegistryConfig.getHibernateHikariMaximumPoolSize;
|
||||
import static google.registry.config.RegistryConfig.getHibernateHikariMinimumIdle;
|
||||
import static google.registry.config.RegistryConfig.getHibernateLogSqlQueries;
|
||||
|
||||
import com.google.api.client.auth.oauth2.Credential;
|
||||
@@ -50,10 +48,7 @@ public class PersistenceModule {
|
||||
// This name must be the same as the one defined in persistence.xml.
|
||||
public static final String PERSISTENCE_UNIT_NAME = "nomulus";
|
||||
public static final String HIKARI_CONNECTION_TIMEOUT = "hibernate.hikari.connectionTimeout";
|
||||
public static final String HIKARI_MINIMUM_IDLE = "hibernate.hikari.minimumIdle";
|
||||
public static final String HIKARI_MAXIMUM_POOL_SIZE = "hibernate.hikari.maximumPoolSize";
|
||||
public static final String HIKARI_IDLE_TIMEOUT = "hibernate.hikari.idleTimeout";
|
||||
|
||||
public static final String HIKARI_DS_SOCKET_FACTORY = "hibernate.hikari.dataSource.socketFactory";
|
||||
public static final String HIKARI_DS_CLOUD_SQL_INSTANCE =
|
||||
"hibernate.hikari.dataSource.cloudSqlInstance";
|
||||
@@ -79,9 +74,7 @@ public class PersistenceModule {
|
||||
properties.put(Environment.ISOLATION, getHibernateConnectionIsolation());
|
||||
properties.put(Environment.SHOW_SQL, getHibernateLogSqlQueries());
|
||||
properties.put(HIKARI_CONNECTION_TIMEOUT, getHibernateHikariConnectionTimeout());
|
||||
properties.put(HIKARI_MINIMUM_IDLE, getHibernateHikariMinimumIdle());
|
||||
properties.put(HIKARI_MAXIMUM_POOL_SIZE, getHibernateHikariMaximumPoolSize());
|
||||
properties.put(HIKARI_IDLE_TIMEOUT, getHibernateHikariIdleTimeout());
|
||||
properties.put(Environment.DIALECT, NomulusPostgreSQLDialect.class.getName());
|
||||
return properties.build();
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import java.util.Optional;
|
||||
@@ -41,25 +42,31 @@ public class VKey<T> extends ImmutableObject {
|
||||
this.primaryKey = primaryKey;
|
||||
}
|
||||
|
||||
public static <T> VKey<T> create(
|
||||
Class<? extends T> kind, com.googlecode.objectify.Key<T> ofyKey, Object primaryKey) {
|
||||
return new VKey(kind, ofyKey, primaryKey);
|
||||
}
|
||||
|
||||
public static <T> VKey<T> createSql(Class<? extends T> kind, Object primaryKey) {
|
||||
return new VKey(kind, null, primaryKey);
|
||||
/** Creates a {@link VKey} which only contains the sql primary key. */
|
||||
public static <T> VKey<T> createSql(Class<? extends T> kind, Object sqlKey) {
|
||||
checkArgumentNotNull(kind, "kind must not be null");
|
||||
checkArgumentNotNull(sqlKey, "sqlKey must not be null");
|
||||
return new VKey(kind, null, sqlKey);
|
||||
}
|
||||
|
||||
/** Creates a {@link VKey} which only contains the ofy primary key. */
|
||||
public static <T> VKey<T> createOfy(
|
||||
Class<? extends T> kind, com.googlecode.objectify.Key<T> ofyKey) {
|
||||
Class<? extends T> kind, com.googlecode.objectify.Key<? extends T> ofyKey) {
|
||||
checkArgumentNotNull(kind, "kind must not be null");
|
||||
checkArgumentNotNull(ofyKey, "ofyKey must not be null");
|
||||
return new VKey(kind, ofyKey, null);
|
||||
}
|
||||
|
||||
/** Creates a {@link VKey} which only contains both sql and ofy primary key. */
|
||||
public static <T> VKey<T> create(
|
||||
Class<? extends T> kind, Object primaryKey, com.googlecode.objectify.Key ofyKey) {
|
||||
return new VKey(kind, ofyKey, primaryKey);
|
||||
Class<? extends T> kind, Object sqlKey, com.googlecode.objectify.Key ofyKey) {
|
||||
checkArgumentNotNull(kind, "kind must not be null");
|
||||
checkArgumentNotNull(sqlKey, "sqlKey must not be null");
|
||||
checkArgumentNotNull(ofyKey, "ofyKey must not be null");
|
||||
return new VKey(kind, ofyKey, sqlKey);
|
||||
}
|
||||
|
||||
/** Returns the type of the entity. */
|
||||
public Class<? extends T> getKind() {
|
||||
return this.kind;
|
||||
}
|
||||
@@ -72,7 +79,7 @@ public class VKey<T> extends ImmutableObject {
|
||||
|
||||
/** Returns the SQL primary key if it exists. */
|
||||
public Optional<Object> maybeGetSqlKey() {
|
||||
return Optional.of(this.primaryKey);
|
||||
return Optional.ofNullable(this.primaryKey);
|
||||
}
|
||||
|
||||
/** Returns the objectify key. */
|
||||
@@ -83,6 +90,6 @@ public class VKey<T> extends ImmutableObject {
|
||||
|
||||
/** Returns the objectify key if it exists. */
|
||||
public Optional<com.googlecode.objectify.Key<T>> maybeGetOfyKey() {
|
||||
return Optional.of(this.ofyKey);
|
||||
return Optional.ofNullable(this.ofyKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Entity;
|
||||
|
||||
/**
|
||||
* Annotation for {@link Entity} which id is long type and needs an {@link AttributeConverter} for
|
||||
* its VKey.
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
public @interface WithLongVKey {
|
||||
/**
|
||||
* Sets the suffix of the class name for the {@link AttributeConverter} generated by
|
||||
* LongVKeyProcessor. If not set, the suffix will be the type name of the VKey. Note that the
|
||||
* class name will be "VKeyConverter_" concatenated with the suffix.
|
||||
*/
|
||||
String classNameSuffix() default "";
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Entity;
|
||||
|
||||
/**
|
||||
* Annotation for {@link Entity} which id is string type and needs an {@link AttributeConverter} for
|
||||
* its VKey.
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
public @interface WithStringVKey {
|
||||
/**
|
||||
* Sets the suffix of the class name for the {@link AttributeConverter} generated by
|
||||
* StringVKeyProcessor. If not set, the suffix will be the type name of the VKey. Note that the
|
||||
* class name will be "VKeyConverter_" concatenated with the suffix.
|
||||
*/
|
||||
String classNameSuffix() default "";
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.persistence.converter;
|
||||
|
||||
import static google.registry.model.registrar.Registrar.BillingAccountEntry;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Converter;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
/** JPA converter for storing/retrieving {@link Map <CurrencyUnit, BillingAccountEntry>} objects. */
|
||||
@Converter(autoApply = true)
|
||||
public class CurrencyToBillingConverter
|
||||
extends StringMapConverterBase<CurrencyUnit, BillingAccountEntry> {
|
||||
|
||||
@Override
|
||||
Map.Entry<String, String> convertToDatabaseMapEntry(
|
||||
Map.Entry<CurrencyUnit, BillingAccountEntry> entry) {
|
||||
return Maps.immutableEntry(entry.getKey().getCode(), entry.getValue().getAccountId());
|
||||
}
|
||||
|
||||
@Override
|
||||
Map.Entry<CurrencyUnit, BillingAccountEntry> convertToEntityMapEntry(
|
||||
Map.Entry<String, String> entry) {
|
||||
CurrencyUnit currencyUnit = CurrencyUnit.of(entry.getKey());
|
||||
BillingAccountEntry billingAccountEntry =
|
||||
new BillingAccountEntry(currencyUnit, entry.getValue());
|
||||
return Maps.immutableEntry(currencyUnit, billingAccountEntry);
|
||||
}
|
||||
}
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.persistence.converter;
|
||||
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
|
||||
import google.registry.model.registrar.Registrar.BillingAccountEntry;
|
||||
import java.util.Map;
|
||||
import org.hibernate.usertype.UserType;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
/**
|
||||
* A custom {@link UserType} for storing/retrieving {@link Map<CurrencyUnit, BillingAccountEntry>}
|
||||
* objects.
|
||||
*/
|
||||
public class CurrencyToBillingMapUserType extends MapUserType {
|
||||
|
||||
@Override
|
||||
public Object toEntityTypeMap(Map<String, String> map) {
|
||||
return map == null
|
||||
? null
|
||||
: map.entrySet().stream()
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
entry -> CurrencyUnit.of(entry.getKey()),
|
||||
entry ->
|
||||
new BillingAccountEntry(
|
||||
CurrencyUnit.of(entry.getKey()), entry.getValue())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> toDbSupportedMap(Object map) {
|
||||
return map == null
|
||||
? null
|
||||
: ((Map<CurrencyUnit, BillingAccountEntry>) map)
|
||||
.entrySet().stream()
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
entry -> entry.getKey().getCode(),
|
||||
entry -> entry.getValue().getAccountId()));
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.persistence.converter;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Map;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.usertype.UserType;
|
||||
|
||||
/**
|
||||
* A custom {@link UserType} used to convert a Java {@link Map<String, String>} to/from PostgreSQL
|
||||
* hstore type. Per this <a href="https://www.postgresql.org/docs/current/hstore.html">doc</a>, as
|
||||
* hstore keys and values are simply text strings, the type of key and value in the Java map has to
|
||||
* be {@link String} as well.
|
||||
*/
|
||||
public class MapUserType extends MutableUserType {
|
||||
|
||||
@Override
|
||||
public int[] sqlTypes() {
|
||||
return new int[] {Types.OTHER};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class returnedClass() {
|
||||
return Map.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object nullSafeGet(
|
||||
ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
|
||||
throws HibernateException, SQLException {
|
||||
return toEntityTypeMap((Map<String, String>) rs.getObject(names[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nullSafeSet(
|
||||
PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
|
||||
throws HibernateException, SQLException {
|
||||
st.setObject(index, toDbSupportedMap(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass can override this method to convert the {@link Map<String, String>} to a {@link Map}
|
||||
* of specific type defined in the entity class.
|
||||
*/
|
||||
public Object toEntityTypeMap(Map<String, String> map) {
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass can override this method to convert the {@link Map} of specific type to a {@link
|
||||
* Map<String, String>} that can be stored in the hstore type column.
|
||||
*/
|
||||
public Map<String, String> toDbSupportedMap(Object map) {
|
||||
return (Map<String, String>) map;
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.persistence.converter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.usertype.UserType;
|
||||
|
||||
/**
|
||||
* An abstract class represents a mutable Hibernate user type which implements related methods
|
||||
* defined in {@link UserType}.
|
||||
*/
|
||||
public abstract class MutableUserType implements UserType {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object x, Object y) throws HibernateException {
|
||||
return Objects.equals(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(Object x) throws HibernateException {
|
||||
return x == null ? 0 : x.hashCode();
|
||||
}
|
||||
|
||||
// TODO(b/147489651): Investigate how to properly implement the below methods.
|
||||
@Override
|
||||
public Object deepCopy(Object value) throws HibernateException {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable disassemble(Object value) throws HibernateException {
|
||||
return (Serializable) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object assemble(Serializable cached, Object owner) throws HibernateException {
|
||||
return cached;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object replace(Object original, Object target, Object owner) throws HibernateException {
|
||||
return original;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.persistence.converter;
|
||||
|
||||
import google.registry.model.contact.Disclose.PostalInfoChoice;
|
||||
import google.registry.model.contact.PostalInfo;
|
||||
import java.util.List;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
/** JPA {@link AttributeConverter} for storing/retrieving {@link List < PostalInfoChoice >}. */
|
||||
@Converter(autoApply = true)
|
||||
public class PostalInfoChoiceListConverter extends StringListConverterBase<PostalInfoChoice> {
|
||||
|
||||
@Override
|
||||
String toString(PostalInfoChoice element) {
|
||||
return element.getType().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
PostalInfoChoice fromString(String value) {
|
||||
return PostalInfoChoice.create(PostalInfo.Type.valueOf(value));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.persistence.converter;
|
||||
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
|
||||
import google.registry.persistence.converter.StringMapDescriptor.StringMap;
|
||||
import java.util.Map;
|
||||
import javax.persistence.AttributeConverter;
|
||||
|
||||
/**
|
||||
* Base JPA converter for {@link Map} objects that are stored in a column with data type of hstore
|
||||
* in the database.
|
||||
*/
|
||||
public abstract class StringMapConverterBase<K, V>
|
||||
implements AttributeConverter<Map<K, V>, StringMap> {
|
||||
|
||||
abstract Map.Entry<String, String> convertToDatabaseMapEntry(Map.Entry<K, V> entry);
|
||||
|
||||
abstract Map.Entry<K, V> convertToEntityMapEntry(Map.Entry<String, String> entry);
|
||||
|
||||
@Override
|
||||
public StringMap convertToDatabaseColumn(Map<K, V> attribute) {
|
||||
return attribute == null
|
||||
? null
|
||||
: StringMap.create(
|
||||
attribute.entrySet().stream()
|
||||
.map(this::convertToDatabaseMapEntry)
|
||||
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<K, V> convertToEntityAttribute(StringMap dbData) {
|
||||
return dbData == null
|
||||
? null
|
||||
: dbData.getMap().entrySet().stream()
|
||||
.map(this::convertToEntityMapEntry)
|
||||
.collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.persistence.converter;
|
||||
|
||||
import static google.registry.persistence.converter.StringMapDescriptor.StringMap;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Map;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.AbstractTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.spi.JdbcRecommendedSqlTypeMappingContext;
|
||||
import org.hibernate.type.descriptor.sql.BasicBinder;
|
||||
import org.hibernate.type.descriptor.sql.BasicExtractor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
|
||||
/**
|
||||
* The {@link JavaTypeDescriptor} and {@link SqlTypeDescriptor} for {@link StringMap}.
|
||||
*
|
||||
* <p>A {@link StringMap} object is a simple wrapper for a {@link Map <String, String>} which can be
|
||||
* stored in a column with data type of hstore in the database. The {@link JavaTypeDescriptor} and
|
||||
* {@link SqlTypeDescriptor} is used by JPA/Hibernate to map between the map and hstore which is the
|
||||
* actual type that JDBC uses to read from and write to the database.
|
||||
*
|
||||
* @see <a
|
||||
* href="https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#basic-jpa-convert">JPA
|
||||
* 2.1 AttributeConverters</a>
|
||||
* @see <a href="https://www.postgresql.org/docs/current/hstore.html">hstore</a>
|
||||
*/
|
||||
public class StringMapDescriptor extends AbstractTypeDescriptor<StringMap>
|
||||
implements SqlTypeDescriptor {
|
||||
public static final int COLUMN_TYPE = Types.OTHER;
|
||||
public static final String COLUMN_NAME = "hstore";
|
||||
private static final StringMapDescriptor INSTANCE = new StringMapDescriptor();
|
||||
|
||||
protected StringMapDescriptor() {
|
||||
super(StringMap.class);
|
||||
}
|
||||
|
||||
public static StringMapDescriptor getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringMap fromString(String string) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Constructing StringMapDescriptor from string is not allowed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> X unwrap(StringMap value, Class<X> type, WrapperOptions options) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (Map.class.isAssignableFrom(type)) {
|
||||
return (X) value.getMap();
|
||||
}
|
||||
throw unknownUnwrap(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> StringMap wrap(X value, WrapperOptions options) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Map) {
|
||||
return StringMap.create((Map<String, String>) value);
|
||||
}
|
||||
throw unknownWrap(value.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlTypeDescriptor getJdbcRecommendedSqlType(JdbcRecommendedSqlTypeMappingContext context) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return COLUMN_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeRemapped() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>(javaTypeDescriptor, this) {
|
||||
@Override
|
||||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
st.setObject(index, getStringMap(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
st.setObject(name, getStringMap(value));
|
||||
}
|
||||
|
||||
private Map<String, String> getStringMap(X value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof StringMap) {
|
||||
return ((StringMap) value).getMap();
|
||||
} else {
|
||||
throw new UnsupportedOperationException(
|
||||
String.format(
|
||||
"Binding type %s is not supported by StringMapDescriptor",
|
||||
value.getClass().getName()));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>(javaTypeDescriptor, this) {
|
||||
@Override
|
||||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap(rs.getObject(name), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
return javaTypeDescriptor.wrap(statement.getObject(index), options);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, String name, WrapperOptions options)
|
||||
throws SQLException {
|
||||
return javaTypeDescriptor.wrap(statement.getObject(name), options);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** A simple wrapper class for {@link Map<String, String>}. */
|
||||
public static class StringMap {
|
||||
private Map<String, String> map;
|
||||
|
||||
private StringMap(Map<String, String> map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
/** Constructs an instance of {@link StringMap} from the given map. */
|
||||
public static StringMap create(Map<String, String> map) {
|
||||
return new StringMap(ImmutableMap.copyOf(map));
|
||||
}
|
||||
|
||||
/** Returns the underlying {@link Map<String, String>} object. */
|
||||
public Map<String, String> getMap() {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.persistence.converter;
|
||||
|
||||
import google.registry.persistence.VKey;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.AttributeConverter;
|
||||
|
||||
/** Converts VKey to a string column. */
|
||||
public abstract class VKeyConverter<T, C> implements AttributeConverter<VKey<? extends T>, C> {
|
||||
@Override
|
||||
@Nullable
|
||||
public C convertToDatabaseColumn(@Nullable VKey<? extends T> attribute) {
|
||||
return attribute == null ? null : (C) attribute.getSqlKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public VKey<? extends T> convertToEntityAttribute(@Nullable C dbData) {
|
||||
return dbData == null ? null : VKey.createSql(getAttributeClass(), dbData);
|
||||
}
|
||||
|
||||
/** Returns the class of the attribute. */
|
||||
protected abstract Class<T> getAttributeClass();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.schema.replay;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/** An entity that has the same Java object representation in SQL and Datastore. */
|
||||
public interface DatastoreAndSqlEntity extends DatastoreEntity, SqlEntity {
|
||||
|
||||
@Override
|
||||
default ImmutableList<DatastoreEntity> toDatastoreEntities() {
|
||||
return ImmutableList.of(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
default ImmutableList<SqlEntity> toSqlEntities() {
|
||||
return ImmutableList.of(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.schema.replay;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* An object that can be stored in Datastore and serialized using Objectify's {@link
|
||||
* com.googlecode.objectify.cmd.Saver#toEntity(Object)} code.
|
||||
*
|
||||
* <p>This is used when replaying {@link google.registry.model.ofy.CommitLogManifest}s to import
|
||||
* transactions and data into the secondary SQL store during the first, Datastore-primary, phase of
|
||||
* the migration.
|
||||
*/
|
||||
public interface DatastoreEntity {
|
||||
|
||||
ImmutableList<SqlEntity> toSqlEntities();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.schema.replay;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* An object that can be stored in Cloud SQL using {@link
|
||||
* javax.persistence.EntityManager#persist(Object)}
|
||||
*
|
||||
* <p>This will be used when replaying SQL transactions into Datastore, during the second,
|
||||
* SQL-primary, phase of the migration from Datastore to SQL.
|
||||
*/
|
||||
public interface SqlEntity {
|
||||
|
||||
ImmutableList<DatastoreEntity> toDatastoreEntities();
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.schema.tld;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.Column;
|
||||
@@ -26,7 +27,7 @@ import javax.persistence.Id;
|
||||
* <p>These are not persisted directly, but rather, using {@link PremiumList#getLabelsToPrices()}.
|
||||
*/
|
||||
@Entity
|
||||
public class PremiumEntry implements Serializable {
|
||||
public class PremiumEntry extends ImmutableObject implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(nullable = false)
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.collect.Multimap;
|
||||
@@ -39,6 +41,11 @@ final class CheckDomainCommand extends NonMutatingEppToolCommand {
|
||||
required = true)
|
||||
private List<String> mainParameters;
|
||||
|
||||
@Parameter(
|
||||
names = {"-t", "--token"},
|
||||
description = "Allocation token to use in the command, if desired")
|
||||
private String allocationToken;
|
||||
|
||||
@Inject
|
||||
@Config("registryAdminClientId")
|
||||
String registryAdminClientId;
|
||||
@@ -53,7 +60,11 @@ final class CheckDomainCommand extends NonMutatingEppToolCommand {
|
||||
Multimap<String, String> domainNameMap = validateAndGroupDomainNamesByTld(mainParameters);
|
||||
for (Collection<String> values : domainNameMap.asMap().values()) {
|
||||
setSoyTemplate(DomainCheckSoyInfo.getInstance(), DomainCheckSoyInfo.DOMAINCHECK);
|
||||
addSoyRecord(clientId, new SoyMapData("domainNames", values));
|
||||
SoyMapData soyMapData = new SoyMapData("domainNames", values);
|
||||
if (!isNullOrEmpty(allocationToken)) {
|
||||
soyMapData.put("allocationToken", allocationToken);
|
||||
}
|
||||
addSoyRecord(clientId, soyMapData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,20 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Sets.SetView;
|
||||
import java.io.File;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/** Compare two database backups. */
|
||||
/**
|
||||
* Compares two Datastore backups in V3 format on local file system. This is for use in tests and
|
||||
* experiments with small data sizes.
|
||||
*
|
||||
* <p>This utility only supports the current Datastore backup format (version 3). A backup is a
|
||||
* two-level directory hierarchy with data files in level-db format (output-*) and Datastore
|
||||
* metadata files (*.export_metadata).
|
||||
*/
|
||||
class CompareDbBackups {
|
||||
private static final String DS_V3_BACKUP_FILE_PREFIX = "output-";
|
||||
private static final Predicate<File> DATA_FILE_MATCHER =
|
||||
file -> file.isFile() && file.getName().startsWith(DS_V3_BACKUP_FILE_PREFIX);
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (args.length != 2) {
|
||||
@@ -29,9 +40,13 @@ class CompareDbBackups {
|
||||
}
|
||||
|
||||
ImmutableSet<ComparableEntity> entities1 =
|
||||
new RecordAccumulator().readDirectory(new File(args[0])).getComparableEntitySet();
|
||||
new RecordAccumulator()
|
||||
.readDirectory(new File(args[0]), DATA_FILE_MATCHER)
|
||||
.getComparableEntitySet();
|
||||
ImmutableSet<ComparableEntity> entities2 =
|
||||
new RecordAccumulator().readDirectory(new File(args[1])).getComparableEntitySet();
|
||||
new RecordAccumulator()
|
||||
.readDirectory(new File(args[1]), DATA_FILE_MATCHER)
|
||||
.getComparableEntitySet();
|
||||
|
||||
// Calculate the entities added and removed.
|
||||
SetView<ComparableEntity> added = Sets.difference(entities2, entities1);
|
||||
@@ -54,6 +69,10 @@ class CompareDbBackups {
|
||||
System.out.println(entity);
|
||||
}
|
||||
}
|
||||
|
||||
if (added.isEmpty() && removed.isEmpty()) {
|
||||
System.out.printf("\nBoth sets have the same %d entities.\n", entities1.size());
|
||||
}
|
||||
}
|
||||
|
||||
/** Print out multi-line text in a pretty ASCII header frame. */
|
||||
|
||||
@@ -24,6 +24,7 @@ import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STAT
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.batch.AsyncTaskEnqueuer;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
@@ -51,10 +52,14 @@ public final class DomainLockUtils {
|
||||
private static final int VERIFICATION_CODE_LENGTH = 32;
|
||||
|
||||
private final StringGenerator stringGenerator;
|
||||
private final AsyncTaskEnqueuer asyncTaskEnqueuer;
|
||||
|
||||
@Inject
|
||||
public DomainLockUtils(@Named("base58StringGenerator") StringGenerator stringGenerator) {
|
||||
public DomainLockUtils(
|
||||
@Named("base58StringGenerator") StringGenerator stringGenerator,
|
||||
AsyncTaskEnqueuer asyncTaskEnqueuer) {
|
||||
this.stringGenerator = stringGenerator;
|
||||
this.asyncTaskEnqueuer = asyncTaskEnqueuer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,35 +120,41 @@ public final class DomainLockUtils {
|
||||
|
||||
/** Verifies and applies the unlock request previously requested by a user. */
|
||||
public RegistryLock verifyAndApplyUnlock(String verificationCode, boolean isAdmin) {
|
||||
return jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
DateTime now = jpaTm().getTransactionTime();
|
||||
RegistryLock lock = getByVerificationCode(verificationCode);
|
||||
checkArgument(
|
||||
!lock.getUnlockCompletionTimestamp().isPresent(),
|
||||
"Domain %s is already unlocked",
|
||||
lock.getDomainName());
|
||||
RegistryLock lock =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
DateTime now = jpaTm().getTransactionTime();
|
||||
RegistryLock previousLock = getByVerificationCode(verificationCode);
|
||||
checkArgument(
|
||||
!previousLock.getUnlockCompletionTimestamp().isPresent(),
|
||||
"Domain %s is already unlocked",
|
||||
previousLock.getDomainName());
|
||||
|
||||
checkArgument(
|
||||
!lock.isUnlockRequestExpired(now),
|
||||
"The pending unlock has expired; please try again");
|
||||
checkArgument(
|
||||
!previousLock.isUnlockRequestExpired(now),
|
||||
"The pending unlock has expired; please try again");
|
||||
|
||||
checkArgument(
|
||||
isAdmin || !lock.isSuperuser(), "Non-admin user cannot complete admin unlock");
|
||||
checkArgument(
|
||||
isAdmin || !previousLock.isSuperuser(),
|
||||
"Non-admin user cannot complete admin unlock");
|
||||
|
||||
RegistryLock newLock =
|
||||
RegistryLockDao.save(lock.asBuilder().setUnlockCompletionTimestamp(now).build());
|
||||
tm().transact(() -> removeLockStatuses(newLock, isAdmin, now));
|
||||
return newLock;
|
||||
});
|
||||
RegistryLock newLock =
|
||||
RegistryLockDao.save(
|
||||
previousLock.asBuilder().setUnlockCompletionTimestamp(now).build());
|
||||
tm().transact(() -> removeLockStatuses(newLock, isAdmin, now));
|
||||
return newLock;
|
||||
});
|
||||
// Submit relock outside of the transaction to make sure that it fully succeeded
|
||||
submitRelockIfNecessary(lock);
|
||||
return lock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and applies a lock in one step -- this should only be used for admin actions, e.g.
|
||||
* Nomulus tool commands or relocks.
|
||||
* Creates and applies a lock in one step.
|
||||
*
|
||||
* <p>Note: in the case of relocks, isAdmin is determined by the previous lock.
|
||||
* <p>This should only be used for admin actions, e.g. Nomulus tool commands or relocks. Note: in
|
||||
* the case of relocks, isAdmin is determined by the previous lock.
|
||||
*/
|
||||
public RegistryLock administrativelyApplyLock(
|
||||
String domainName, String registrarId, @Nullable String registrarPocId, boolean isAdmin) {
|
||||
@@ -163,23 +174,34 @@ public final class DomainLockUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and applies an unlock in one step -- this should only be used for admin actions, e.g.
|
||||
* Nomulus tool commands.
|
||||
* Creates and applies an unlock in one step.
|
||||
*
|
||||
* <p>This should only be used for admin actions, e.g. Nomulus tool commands.
|
||||
*/
|
||||
public RegistryLock administrativelyApplyUnlock(
|
||||
String domainName, String registrarId, boolean isAdmin, Optional<Duration> relockDuration) {
|
||||
return jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
DateTime now = jpaTm().getTransactionTime();
|
||||
RegistryLock result =
|
||||
RegistryLockDao.save(
|
||||
createUnlockBuilder(domainName, registrarId, isAdmin, relockDuration)
|
||||
.setUnlockCompletionTimestamp(now)
|
||||
.build());
|
||||
tm().transact(() -> removeLockStatuses(result, isAdmin, now));
|
||||
return result;
|
||||
});
|
||||
RegistryLock lock =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
DateTime now = jpaTm().getTransactionTime();
|
||||
RegistryLock result =
|
||||
RegistryLockDao.save(
|
||||
createUnlockBuilder(domainName, registrarId, isAdmin, relockDuration)
|
||||
.setUnlockCompletionTimestamp(now)
|
||||
.build());
|
||||
tm().transact(() -> removeLockStatuses(result, isAdmin, now));
|
||||
return result;
|
||||
});
|
||||
// Submit relock outside of the transaction to make sure that it fully succeeded
|
||||
submitRelockIfNecessary(lock);
|
||||
return lock;
|
||||
}
|
||||
|
||||
private void submitRelockIfNecessary(RegistryLock lock) {
|
||||
if (lock.getRelockDuration().isPresent()) {
|
||||
asyncTaskEnqueuer.enqueueDomainRelock(lock);
|
||||
}
|
||||
}
|
||||
|
||||
private void setAsRelock(RegistryLock newLock) {
|
||||
|
||||
@@ -20,17 +20,18 @@ import com.google.storage.onestore.v3.OnestoreEntity.EntityProto;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/** Utility class that accumulates Entity records from level db files. */
|
||||
/** Accumulates Entity records from level db files under a directory hierarchy. */
|
||||
class RecordAccumulator {
|
||||
private final LevelDbLogReader reader = new LevelDbLogReader();
|
||||
|
||||
/** Recursively reads all records in the directory. */
|
||||
public final RecordAccumulator readDirectory(File dir) {
|
||||
public final RecordAccumulator readDirectory(File dir, Predicate<File> fileMatcher) {
|
||||
for (File child : dir.listFiles()) {
|
||||
if (child.isDirectory()) {
|
||||
readDirectory(child);
|
||||
} else if (child.isFile()) {
|
||||
readDirectory(child, fileMatcher);
|
||||
} else if (fileMatcher.test(child)) {
|
||||
try {
|
||||
reader.readFrom(new FileInputStream(child));
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -132,10 +132,8 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
|
||||
jcommander.parse(args);
|
||||
} catch (ParameterException e) {
|
||||
// If we failed to fully parse the command but at least found a valid command name, show only
|
||||
// the usage for that command. Otherwise, show full usage. Either way, rethrow the error.
|
||||
if (jcommander.getParsedCommand() == null) {
|
||||
jcommander.usage();
|
||||
} else {
|
||||
// the usage for that command.
|
||||
if (jcommander.getParsedCommand() != null) {
|
||||
jcommander.usage(jcommander.getParsedCommand());
|
||||
}
|
||||
// Don't rethrow if we said: nomulus command --help
|
||||
@@ -144,8 +142,13 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (showAllCommands) {
|
||||
String parsedCommand = jcommander.getParsedCommand();
|
||||
// Show the list of all commands either if requested or if no subcommand name was specified
|
||||
// (which does not throw a ParameterException parse error above).
|
||||
if (showAllCommands || parsedCommand == null) {
|
||||
if (parsedCommand == null) {
|
||||
System.out.println("The list of available subcommands is:");
|
||||
}
|
||||
commands.keySet().forEach(System.out::println);
|
||||
return;
|
||||
}
|
||||
@@ -161,8 +164,7 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
|
||||
// retrieving the first (and, by virtue of our usage, only) object from it.
|
||||
Command command =
|
||||
(Command)
|
||||
Iterables.getOnlyElement(
|
||||
jcommander.getCommands().get(jcommander.getParsedCommand()).getObjects());
|
||||
Iterables.getOnlyElement(jcommander.getCommands().get(parsedCommand).getObjects());
|
||||
loggingParams.configureLogging(); // Must be called after parameters are parsed.
|
||||
|
||||
try {
|
||||
|
||||
@@ -16,6 +16,7 @@ package google.registry.tools;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Component;
|
||||
import google.registry.batch.BatchModule;
|
||||
import google.registry.bigquery.BigqueryModule;
|
||||
import google.registry.config.CredentialModule.LocalCredentialJson;
|
||||
import google.registry.config.RegistryConfig.ConfigModule;
|
||||
@@ -54,6 +55,7 @@ import javax.inject.Singleton;
|
||||
modules = {
|
||||
AppEngineAdminApiModule.class,
|
||||
AuthModule.class,
|
||||
BatchModule.class,
|
||||
BigqueryModule.class,
|
||||
ConfigModule.class,
|
||||
CloudDnsWriterModule.class,
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.util.CollectionUtils.findDuplicates;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
|
||||
@@ -37,6 +38,13 @@ import org.joda.time.format.DateTimeFormatter;
|
||||
@Parameters(separators = " =", commandDescription = "Renew domain(s) via EPP.")
|
||||
final class RenewDomainCommand extends MutatingEppToolCommand {
|
||||
|
||||
@Parameter(
|
||||
names = {"-c", "--client"},
|
||||
description =
|
||||
"The registrar to execute as and bill the renewal to; otherwise each domain's sponsoring"
|
||||
+ " registrar. Renewals by non-sponsoring registrars require --superuser as well.")
|
||||
String clientId;
|
||||
|
||||
@Parameter(
|
||||
names = {"-p", "--period"},
|
||||
description = "Number of years to renew the registration for (defaults to 1).")
|
||||
@@ -63,7 +71,7 @@ final class RenewDomainCommand extends MutatingEppToolCommand {
|
||||
setSoyTemplate(RenewDomainSoyInfo.getInstance(), RenewDomainSoyInfo.RENEWDOMAIN);
|
||||
DomainBase domain = domainOptional.get();
|
||||
addSoyRecord(
|
||||
domain.getCurrentSponsorClientId(),
|
||||
isNullOrEmpty(clientId) ? domain.getCurrentSponsorClientId() : clientId,
|
||||
new SoyMapData(
|
||||
"domainName", domain.getFullyQualifiedDomainName(),
|
||||
"expirationDate", domain.getRegistrationExpirationTime().toString(DATE_FORMATTER),
|
||||
|
||||
@@ -2,4 +2,6 @@ handlers = java.util.logging.ConsoleHandler
|
||||
.level = INFO
|
||||
com.google.wrappers.base.GoogleInit.level = WARNING
|
||||
com.google.monitoring.metrics.MetricRegistryImpl.level = WARNING
|
||||
|
||||
com.google.cloud.sql.level = WARNING
|
||||
com.zaxxer.hikari.level = WARNING
|
||||
org.hibernate.level = WARNING
|
||||
|
||||
@@ -186,9 +186,7 @@ public final class RegistrarFormFields {
|
||||
.build();
|
||||
|
||||
public static final FormField<String, String> REGISTRY_LOCK_EMAIL_ADDRESS_FIELD =
|
||||
FormFields.EMAIL
|
||||
.asBuilderNamed("registryLockEmailAddress")
|
||||
.build();
|
||||
FormFields.EMAIL.asBuilderNamed("registryLockEmailAddress").build();
|
||||
|
||||
public static final FormField<Boolean, Boolean> CONTACT_VISIBLE_IN_WHOIS_AS_ADMIN_FIELD =
|
||||
FormField.named("visibleInWhoisAsAdmin", Boolean.class)
|
||||
|
||||
+32
-1
@@ -391,7 +391,8 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
* @throws FormException if the checks fail.
|
||||
*/
|
||||
void checkContactRequirements(
|
||||
Set<RegistrarContact> existingContacts, Set<RegistrarContact> updatedContacts) {
|
||||
ImmutableSet<RegistrarContact> existingContacts,
|
||||
ImmutableSet<RegistrarContact> updatedContacts) {
|
||||
// Check that no two contacts use the same email address.
|
||||
Set<String> emails = new HashSet<>();
|
||||
for (RegistrarContact contact : updatedContacts) {
|
||||
@@ -435,7 +436,12 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
throw new ContactRequirementException(
|
||||
"An abuse contact visible in domain WHOIS query must be designated");
|
||||
}
|
||||
checkContactRegistryLockRequirements(existingContacts, updatedContacts);
|
||||
}
|
||||
|
||||
private static void checkContactRegistryLockRequirements(
|
||||
ImmutableSet<RegistrarContact> existingContacts,
|
||||
ImmutableSet<RegistrarContact> updatedContacts) {
|
||||
// Any contact(s) with new passwords must be allowed to set them
|
||||
for (RegistrarContact updatedContact : updatedContacts) {
|
||||
if (updatedContact.isRegistryLockAllowed()
|
||||
@@ -463,6 +469,31 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Any previously-existing contacts with registry lock enabled cannot be deleted
|
||||
existingContacts.stream()
|
||||
.filter(RegistrarContact::isRegistryLockAllowed)
|
||||
.forEach(
|
||||
contact -> {
|
||||
Optional<RegistrarContact> updatedContactOptional =
|
||||
updatedContacts.stream()
|
||||
.filter(
|
||||
updatedContact ->
|
||||
updatedContact.getEmailAddress().equals(contact.getEmailAddress()))
|
||||
.findFirst();
|
||||
if (!updatedContactOptional.isPresent()) {
|
||||
throw new FormException(
|
||||
String.format(
|
||||
"Cannot delete the contact %s that has registry lock enabled",
|
||||
contact.getEmailAddress()));
|
||||
}
|
||||
if (!updatedContactOptional.get().isRegistryLockAllowed()) {
|
||||
throw new FormException(
|
||||
String.format(
|
||||
"Cannot remove the ability to use registry lock on the contact %s",
|
||||
contact.getEmailAddress()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -167,6 +167,7 @@ registry.registrar.RegistryLock.prototype.lockOrUnlockDomain_ = function(isLock,
|
||||
var domain = goog.dom.getRequiredElement('domain-lock-input-value').value;
|
||||
var passwordElem = goog.dom.getElement('domain-lock-password');
|
||||
var password = passwordElem == null ? null : passwordElem.value;
|
||||
var relockDuration = this.getRelockDurationFromModal_()
|
||||
goog.net.XhrIo.send('/registry-lock-post',
|
||||
e => this.fillLocksPage_(e),
|
||||
'POST',
|
||||
@@ -174,13 +175,30 @@ registry.registrar.RegistryLock.prototype.lockOrUnlockDomain_ = function(isLock,
|
||||
'clientId': this.clientId,
|
||||
'fullyQualifiedDomainName': domain,
|
||||
'isLock': isLock,
|
||||
'password': password
|
||||
'password': password,
|
||||
'relockDurationMillis': relockDuration
|
||||
}), {
|
||||
'X-CSRF-Token': this.xsrfToken,
|
||||
'Content-Type': 'application/json; charset=UTF-8'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration after which we will re-lock a locked domain. Will return null if we
|
||||
* are locking a domain, or if the user selects the "Never" option
|
||||
* @private
|
||||
*/
|
||||
registry.registrar.RegistryLock.prototype.getRelockDurationFromModal_ = function() {
|
||||
var inputElements = goog.dom.getElementsByTagNameAndClass("input", "relock-duration-input");
|
||||
for (var i = 0; i < inputElements.length; i++) {
|
||||
var elem = inputElements[i];
|
||||
if (elem.checked && elem.value !== "0") {
|
||||
return elem.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click handler for unlocking domains (button click).
|
||||
* @private
|
||||
|
||||
@@ -4,15 +4,17 @@
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
|
||||
http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd"
|
||||
version="2.2">
|
||||
<embeddable class="org.joda.money.Money" access="FIELD">
|
||||
<attributes>
|
||||
<embedded name="money" access="FIELD"/>
|
||||
</attributes>
|
||||
</embeddable>
|
||||
<embeddable class="org.joda.money.Money" access="FIELD" />
|
||||
<embeddable class="org.joda.money.BigMoney" access="FIELD">
|
||||
<attributes>
|
||||
<basic name="amount" access="FIELD"/>
|
||||
<basic name="currency" access="FIELD"/>
|
||||
</attributes>
|
||||
</embeddable>
|
||||
<persistence-unit-metadata>
|
||||
<persistence-unit-defaults>
|
||||
<entity-listeners>
|
||||
<entity-listener class="google.registry.persistence.EntityCallbacksListener" />
|
||||
</entity-listeners>
|
||||
</persistence-unit-defaults>
|
||||
</persistence-unit-metadata>
|
||||
</entity-mappings>
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
* Move tests to another (sub)project. This is not a big problem, but feels unnatural.
|
||||
* Use Hibernate's ServiceRegistry for bootstrapping (not JPA-compliant)
|
||||
-->
|
||||
<class>google.registry.model.contact.ContactResource</class>
|
||||
<class>google.registry.model.domain.DomainBase</class>
|
||||
<class>google.registry.model.host.HostResource</class>
|
||||
<class>google.registry.model.registrar.Registrar</class>
|
||||
<class>google.registry.model.registrar.RegistrarContact</class>
|
||||
<class>google.registry.schema.domain.RegistryLock</class>
|
||||
@@ -36,9 +38,11 @@
|
||||
<class>google.registry.persistence.converter.BloomFilterConverter</class>
|
||||
<class>google.registry.persistence.converter.CidrAddressBlockListConverter</class>
|
||||
<class>google.registry.persistence.converter.CreateAutoTimestampConverter</class>
|
||||
<class>google.registry.persistence.converter.CurrencyToBillingConverter</class>
|
||||
<class>google.registry.persistence.converter.CurrencyUnitConverter</class>
|
||||
<class>google.registry.persistence.converter.DateTimeConverter</class>
|
||||
<class>google.registry.persistence.converter.DurationConverter</class>
|
||||
<class>google.registry.persistence.converter.PostalInfoChoiceListConverter</class>
|
||||
<class>google.registry.persistence.converter.RegistrarPocSetConverter</class>
|
||||
<class>google.registry.persistence.converter.StatusValueSetConverter</class>
|
||||
<class>google.registry.persistence.converter.StringListConverter</class>
|
||||
@@ -46,6 +50,9 @@
|
||||
<class>google.registry.persistence.converter.UpdateAutoTimestampConverter</class>
|
||||
<class>google.registry.persistence.converter.ZonedDateTimeConverter</class>
|
||||
|
||||
<!-- Generated converters for VKey -->
|
||||
<class>google.registry.model.host.VKeyConverter_HostResource</class>
|
||||
|
||||
<!-- TODO(weiminyu): check out application-layer validation. -->
|
||||
<validation-mode>NONE</validation-mode>
|
||||
</persistence-unit>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
{template .domaincheck stricthtml="false"}
|
||||
{@param domainNames: list<string>}
|
||||
{@param? allocationToken: string|null}
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
@@ -39,6 +40,12 @@
|
||||
</fee:domain>
|
||||
{/for}
|
||||
</fee:check>
|
||||
{if isNonnull($allocationToken)}
|
||||
<allocationToken:allocationToken
|
||||
xmlns:allocationToken="urn:ietf:params:xml:ns:allocationToken-1.0">
|
||||
{$allocationToken}
|
||||
</allocationToken:allocationToken>
|
||||
{/if}
|
||||
</extension>
|
||||
<clTRID>RegistryTool</clTRID>
|
||||
</command>
|
||||
|
||||
@@ -145,6 +145,7 @@
|
||||
{param label: 'Email' /}
|
||||
{param namePrefix: $namePrefix /}
|
||||
{param name: 'emailAddress' /}
|
||||
{param disabled: not $readonly and $item['emailAddress'] != null /}
|
||||
{/call}
|
||||
{call registry.soy.forms.inputFieldRow data="all"}
|
||||
{param label: 'Phone' /}
|
||||
|
||||
@@ -132,6 +132,24 @@
|
||||
<input type="password" id="domain-lock-password">
|
||||
<br>
|
||||
{/if}
|
||||
{if not $isLock}
|
||||
<div>
|
||||
<br>
|
||||
<p>Automatically re-lock the domain after:</p>
|
||||
<input type="radio" name="relock-duration" id="one-hour-duration" value="3600000"
|
||||
class="relock-duration-input">
|
||||
<label for="one-hour-duration">1 hour</label><br>
|
||||
<input type="radio" name="relock-duration" id="six-hour-duration" value="21600000"
|
||||
class="relock-duration-input" checked>
|
||||
<label for="six-hour-duration">6 hours</label><br>
|
||||
<input type="radio" name="relock-duration" id="twenty-four-hour-duration" value="86400000"
|
||||
class="relock-duration-input">
|
||||
<label for="twenty-four-hour-duration">24 hours</label><br>
|
||||
<input type="radio" name="relock-duration" id="never-relock-duration" value="0"
|
||||
class="relock-duration-input">
|
||||
<label for="never-relock-duration">Never</label><br>
|
||||
</div>
|
||||
{/if}
|
||||
<div id="modal-error-message" hidden class="{css('kd-errormessage')}"></div>
|
||||
<div class="{css('buttons-div')}">
|
||||
<button id="domain-lock-cancel" class="{css('kd-button')}">Cancel</button>
|
||||
|
||||
@@ -36,6 +36,9 @@ public class DumpGoldenSchemaCommand extends PostgresqlCommand {
|
||||
// The mount point in the container.
|
||||
private static final String CONTAINER_MOUNT_POINT = "/tmp/pg_dump.out";
|
||||
|
||||
// Temporary workaround to fix permission issues on certain Linux distro (e. g. Arch Linux).
|
||||
private static final String CONTAINER_MOUNT_POINT_TMP = "/tmp/pg_dump.tmp";
|
||||
|
||||
@Parameter(
|
||||
names = {"--output", "-o"},
|
||||
description = "Output file",
|
||||
@@ -61,6 +64,11 @@ public class DumpGoldenSchemaCommand extends PostgresqlCommand {
|
||||
if (result.getExitCode() != 0) {
|
||||
throw new RuntimeException(result.toString());
|
||||
}
|
||||
result =
|
||||
postgresContainer.execInContainer("cp", CONTAINER_MOUNT_POINT_TMP, CONTAINER_MOUNT_POINT);
|
||||
if (result.getExitCode() != 0) {
|
||||
throw new RuntimeException(result.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,7 +87,7 @@ public class DumpGoldenSchemaCommand extends PostgresqlCommand {
|
||||
"-U",
|
||||
username,
|
||||
"-f",
|
||||
CONTAINER_MOUNT_POINT,
|
||||
CONTAINER_MOUNT_POINT_TMP,
|
||||
"--schema-only",
|
||||
"--no-owner",
|
||||
"--no-privileges",
|
||||
|
||||
@@ -50,7 +50,11 @@ import org.junit.runners.JUnit4;
|
||||
public class ExportCommitLogDiffActionTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
|
||||
public final AppEngineRule appEngine =
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.withOfyTestEntities(TestObject.class)
|
||||
.build();
|
||||
|
||||
/** Local GCS service available for testing. */
|
||||
private final GcsService gcsService = GcsServiceFactory.createGcsService();
|
||||
|
||||
@@ -71,7 +71,11 @@ public class RestoreCommitLogsActionTest {
|
||||
final GcsService gcsService = createGcsService();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
|
||||
public final AppEngineRule appEngine =
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.withOfyTestEntities(TestObject.class)
|
||||
.build();
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package google.registry.batch;
|
||||
|
||||
import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.PARAM_REQUESTED_TIME;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.PARAM_RESAVE_TIMES;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.PARAM_RESOURCE_KEY;
|
||||
@@ -23,18 +24,21 @@ import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_ACTIONS;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_DELETE;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_HOST_RENAME;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveContact;
|
||||
import static google.registry.testing.SqlHelper.saveRegistryLock;
|
||||
import static google.registry.testing.TaskQueueHelper.assertNoTasksEnqueued;
|
||||
import static google.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
import static google.registry.testing.TestLogHandlerUtils.assertLogMessage;
|
||||
import static org.joda.time.Duration.standardDays;
|
||||
import static org.joda.time.Duration.standardHours;
|
||||
import static org.joda.time.Duration.standardSeconds;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.flogger.LoggerConfig;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeSleeper;
|
||||
@@ -46,6 +50,7 @@ import google.registry.util.CapturingLogHandler;
|
||||
import google.registry.util.Retrier;
|
||||
import java.util.logging.Level;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -77,14 +82,18 @@ public class AsyncTaskEnqueuerTest extends ShardableTestCase {
|
||||
public void setUp() {
|
||||
LoggerConfig.getConfig(AsyncTaskEnqueuer.class).addHandler(logHandler);
|
||||
when(appEngineServiceUtils.getServiceHostname("backend")).thenReturn("backend.hostname.fake");
|
||||
asyncTaskEnqueuer =
|
||||
new AsyncTaskEnqueuer(
|
||||
getQueue(QUEUE_ASYNC_ACTIONS),
|
||||
getQueue(QUEUE_ASYNC_DELETE),
|
||||
getQueue(QUEUE_ASYNC_HOST_RENAME),
|
||||
standardSeconds(90),
|
||||
appEngineServiceUtils,
|
||||
new Retrier(new FakeSleeper(clock), 1));
|
||||
asyncTaskEnqueuer = createForTesting(appEngineServiceUtils, clock, standardSeconds(90));
|
||||
}
|
||||
|
||||
public static AsyncTaskEnqueuer createForTesting(
|
||||
AppEngineServiceUtils appEngineServiceUtils, FakeClock clock, Duration asyncDeleteDelay) {
|
||||
return new AsyncTaskEnqueuer(
|
||||
getQueue(QUEUE_ASYNC_ACTIONS),
|
||||
getQueue(QUEUE_ASYNC_DELETE),
|
||||
getQueue(QUEUE_ASYNC_HOST_RENAME),
|
||||
asyncDeleteDelay,
|
||||
appEngineServiceUtils,
|
||||
new Retrier(new FakeSleeper(clock), 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -137,4 +146,56 @@ public class AsyncTaskEnqueuerTest extends ShardableTestCase {
|
||||
assertNoTasksEnqueued(QUEUE_ASYNC_ACTIONS);
|
||||
assertLogMessage(logHandler, Level.INFO, "Ignoring async re-save");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnqueueRelock() {
|
||||
RegistryLock lock =
|
||||
saveRegistryLock(
|
||||
new RegistryLock.Builder()
|
||||
.setLockCompletionTimestamp(clock.nowUtc())
|
||||
.setUnlockRequestTimestamp(clock.nowUtc())
|
||||
.setUnlockCompletionTimestamp(clock.nowUtc())
|
||||
.isSuperuser(false)
|
||||
.setDomainName("example.tld")
|
||||
.setRepoId("repoId")
|
||||
.setRelockDuration(standardHours(6))
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setRegistrarPocId("someone@example.com")
|
||||
.setVerificationCode("hi")
|
||||
.build());
|
||||
asyncTaskEnqueuer.enqueueDomainRelock(lock);
|
||||
assertTasksEnqueued(
|
||||
QUEUE_ASYNC_ACTIONS,
|
||||
new TaskMatcher()
|
||||
.url(RelockDomainAction.PATH)
|
||||
.method("POST")
|
||||
.param(
|
||||
RelockDomainAction.OLD_UNLOCK_REVISION_ID_PARAM,
|
||||
String.valueOf(lock.getRevisionId()))
|
||||
.etaDelta(
|
||||
standardHours(6).minus(standardSeconds(30)),
|
||||
standardHours(6).plus(standardSeconds(30))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_enqueueRelock_noDuration() {
|
||||
RegistryLock lockWithoutDuration =
|
||||
saveRegistryLock(
|
||||
new RegistryLock.Builder()
|
||||
.isSuperuser(false)
|
||||
.setDomainName("example.tld")
|
||||
.setRepoId("repoId")
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setRegistrarPocId("someone@example.com")
|
||||
.setVerificationCode("hi")
|
||||
.build());
|
||||
assertThat(
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> asyncTaskEnqueuer.enqueueDomainRelock(lockWithoutDuration)))
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
String.format(
|
||||
"Lock with ID %s not configured for relock", lockWithoutDuration.getRevisionId()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,7 @@ import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
|
||||
import static com.google.common.collect.MoreCollectors.onlyElement;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth8.assertThat;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_ACTIONS;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_DELETE;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_HOST_RENAME;
|
||||
import static google.registry.batch.AsyncTaskMetrics.OperationResult.STALE;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.model.eppcommon.StatusValue.PENDING_DELETE;
|
||||
@@ -151,13 +149,8 @@ public class DeleteContactsAndHostsActionTest
|
||||
public void setup() {
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
enqueuer =
|
||||
new AsyncTaskEnqueuer(
|
||||
getQueue(QUEUE_ASYNC_ACTIONS),
|
||||
getQueue(QUEUE_ASYNC_DELETE),
|
||||
getQueue(QUEUE_ASYNC_HOST_RENAME),
|
||||
Duration.ZERO,
|
||||
mock(AppEngineServiceUtils.class),
|
||||
new Retrier(new FakeSleeper(clock), 1));
|
||||
AsyncTaskEnqueuerTest.createForTesting(
|
||||
mock(AppEngineServiceUtils.class), clock, Duration.ZERO);
|
||||
AsyncTaskMetrics asyncTaskMetricsMock = mock(AsyncTaskMetrics.class);
|
||||
action = new DeleteContactsAndHostsAction();
|
||||
action.asyncTaskMetrics = asyncTaskMetricsMock;
|
||||
|
||||
@@ -17,8 +17,6 @@ package google.registry.batch;
|
||||
import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth8.assertThat;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_ACTIONS;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_DELETE;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_HOST_RENAME;
|
||||
import static google.registry.batch.AsyncTaskMetrics.OperationType.DNS_REFRESH;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
@@ -86,13 +84,8 @@ public class RefreshDnsOnHostRenameActionTest
|
||||
public void setup() {
|
||||
createTld("tld");
|
||||
enqueuer =
|
||||
new AsyncTaskEnqueuer(
|
||||
getQueue(QUEUE_ASYNC_ACTIONS),
|
||||
getQueue(QUEUE_ASYNC_DELETE),
|
||||
getQueue(QUEUE_ASYNC_HOST_RENAME),
|
||||
Duration.ZERO,
|
||||
mock(AppEngineServiceUtils.class),
|
||||
new Retrier(new FakeSleeper(clock), 1));
|
||||
AsyncTaskEnqueuerTest.createForTesting(
|
||||
mock(AppEngineServiceUtils.class), clock, Duration.ZERO);
|
||||
AsyncTaskMetrics asyncTaskMetricsMock = mock(AsyncTaskMetrics.class);
|
||||
action = new RefreshDnsOnHostRenameAction();
|
||||
action.asyncTaskMetrics = asyncTaskMetricsMock;
|
||||
|
||||
@@ -28,6 +28,7 @@ import static google.registry.testing.SqlHelper.getRegistryLockByVerificationCod
|
||||
import static google.registry.testing.SqlHelper.saveRegistryLock;
|
||||
import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
@@ -39,8 +40,10 @@ import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.UserInfo;
|
||||
import google.registry.tools.DomainLockUtils;
|
||||
import google.registry.util.AppEngineServiceUtils;
|
||||
import google.registry.util.StringGenerator.Alphabets;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -58,7 +61,10 @@ public class RelockDomainActionTest {
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
private final FakeClock clock = new FakeClock();
|
||||
private final DomainLockUtils domainLockUtils =
|
||||
new DomainLockUtils(new DeterministicStringGenerator(Alphabets.BASE_58));
|
||||
new DomainLockUtils(
|
||||
new DeterministicStringGenerator(Alphabets.BASE_58),
|
||||
AsyncTaskEnqueuerTest.createForTesting(
|
||||
mock(AppEngineServiceUtils.class), clock, Duration.ZERO));
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngineRule =
|
||||
|
||||
@@ -14,14 +14,11 @@
|
||||
|
||||
package google.registry.batch;
|
||||
|
||||
import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.PARAM_REQUESTED_TIME;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.PARAM_RESOURCE_KEY;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.PATH_RESAVE_ENTITY;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_ACTIONS;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_DELETE;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_HOST_RENAME;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainBase;
|
||||
@@ -47,12 +44,10 @@ import google.registry.model.ofy.Ofy;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeSleeper;
|
||||
import google.registry.testing.InjectRule;
|
||||
import google.registry.testing.ShardableTestCase;
|
||||
import google.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import google.registry.util.AppEngineServiceUtils;
|
||||
import google.registry.util.Retrier;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
@@ -85,13 +80,7 @@ public class ResaveEntityActionTest extends ShardableTestCase {
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
when(appEngineServiceUtils.getServiceHostname("backend")).thenReturn("backend.hostname.fake");
|
||||
asyncTaskEnqueuer =
|
||||
new AsyncTaskEnqueuer(
|
||||
getQueue(QUEUE_ASYNC_ACTIONS),
|
||||
getQueue(QUEUE_ASYNC_DELETE),
|
||||
getQueue(QUEUE_ASYNC_HOST_RENAME),
|
||||
Duration.ZERO,
|
||||
appEngineServiceUtils,
|
||||
new Retrier(new FakeSleeper(clock), 1));
|
||||
AsyncTaskEnqueuerTest.createForTesting(appEngineServiceUtils, clock, Duration.ZERO);
|
||||
createTld("tld");
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,7 @@
|
||||
|
||||
package google.registry.flows;
|
||||
|
||||
import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_ACTIONS;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_DELETE;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_HOST_RENAME;
|
||||
import static org.joda.time.Duration.standardSeconds;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -26,6 +23,7 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.Subcomponent;
|
||||
import google.registry.batch.AsyncTaskEnqueuer;
|
||||
import google.registry.batch.AsyncTaskEnqueuerTest;
|
||||
import google.registry.config.RegistryConfig.ConfigModule;
|
||||
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
|
||||
import google.registry.dns.DnsQueue;
|
||||
@@ -42,10 +40,8 @@ import google.registry.tmch.TmchCertificateAuthority;
|
||||
import google.registry.tmch.TmchXmlSignature;
|
||||
import google.registry.util.AppEngineServiceUtils;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.Retrier;
|
||||
import google.registry.util.Sleeper;
|
||||
import javax.inject.Singleton;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** Dagger component for running EPP tests. */
|
||||
@Singleton
|
||||
@@ -84,20 +80,12 @@ interface EppTestComponent {
|
||||
}
|
||||
|
||||
public static FakesAndMocksModule create(
|
||||
FakeClock clock,
|
||||
EppMetric.Builder eppMetricBuilder,
|
||||
TmchXmlSignature tmchXmlSignature) {
|
||||
FakeClock clock, EppMetric.Builder eppMetricBuilder, TmchXmlSignature tmchXmlSignature) {
|
||||
FakesAndMocksModule instance = new FakesAndMocksModule();
|
||||
AppEngineServiceUtils appEngineServiceUtils = mock(AppEngineServiceUtils.class);
|
||||
when(appEngineServiceUtils.getServiceHostname("backend")).thenReturn("backend.hostname.fake");
|
||||
instance.asyncTaskEnqueuer =
|
||||
new AsyncTaskEnqueuer(
|
||||
getQueue(QUEUE_ASYNC_ACTIONS),
|
||||
getQueue(QUEUE_ASYNC_DELETE),
|
||||
getQueue(QUEUE_ASYNC_HOST_RENAME),
|
||||
Duration.standardSeconds(90),
|
||||
appEngineServiceUtils,
|
||||
new Retrier(new FakeSleeper(clock), 1));
|
||||
AsyncTaskEnqueuerTest.createForTesting(appEngineServiceUtils, clock, standardSeconds(90));
|
||||
instance.clock = clock;
|
||||
instance.domainFlowTmchUtils = new DomainFlowTmchUtils(tmchXmlSignature);
|
||||
instance.sleeper = new FakeSleeper(clock);
|
||||
|
||||
@@ -153,6 +153,8 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
|
||||
doSuccessfulTest(
|
||||
responseFilename,
|
||||
renewalYears,
|
||||
"TheRegistrar",
|
||||
UserPrivileges.NORMAL,
|
||||
substitutions,
|
||||
Money.of(USD, 11).multipliedBy(renewalYears));
|
||||
}
|
||||
@@ -160,13 +162,16 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
|
||||
private void doSuccessfulTest(
|
||||
String responseFilename,
|
||||
int renewalYears,
|
||||
String renewalClientId,
|
||||
UserPrivileges userPrivileges,
|
||||
Map<String, String> substitutions,
|
||||
Money totalRenewCost)
|
||||
throws Exception {
|
||||
assertTransactionalFlow(true);
|
||||
DateTime currentExpiration = reloadResourceByForeignKey().getRegistrationExpirationTime();
|
||||
DateTime newExpiration = currentExpiration.plusYears(renewalYears);
|
||||
runFlowAssertResponse(loadFile(responseFilename, substitutions));
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, userPrivileges, loadFile(responseFilename, substitutions));
|
||||
DomainBase domain = reloadResourceByForeignKey();
|
||||
HistoryEntry historyEntryDomainRenew =
|
||||
getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_RENEW);
|
||||
@@ -183,13 +188,13 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
|
||||
.and()
|
||||
.hasLastEppUpdateTime(clock.nowUtc())
|
||||
.and()
|
||||
.hasLastEppUpdateClientId("TheRegistrar");
|
||||
.hasLastEppUpdateClientId(renewalClientId);
|
||||
assertAboutHistoryEntries().that(historyEntryDomainRenew).hasPeriodYears(renewalYears);
|
||||
BillingEvent.OneTime renewBillingEvent =
|
||||
new BillingEvent.OneTime.Builder()
|
||||
.setReason(Reason.RENEW)
|
||||
.setTargetId(getUniqueIdFromCommand())
|
||||
.setClientId("TheRegistrar")
|
||||
.setClientId(renewalClientId)
|
||||
.setCost(totalRenewCost)
|
||||
.setPeriodYears(renewalYears)
|
||||
.setEventTime(clock.nowUtc())
|
||||
@@ -233,7 +238,7 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
|
||||
GracePeriod.create(
|
||||
GracePeriodStatus.RENEW,
|
||||
clock.nowUtc().plus(Registry.get("tld").getRenewGracePeriodLength()),
|
||||
"TheRegistrar",
|
||||
renewalClientId,
|
||||
null),
|
||||
renewBillingEvent));
|
||||
}
|
||||
@@ -256,6 +261,19 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "EXDATE", "2005-04-03T22:00:00.0Z"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_recurringClientIdIsSame_whenSuperuserOverridesRenewal() throws Exception {
|
||||
persistDomain();
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
doSuccessfulTest(
|
||||
"domain_renew_response.xml",
|
||||
5,
|
||||
"NewRegistrar",
|
||||
UserPrivileges.SUPERUSER,
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "EXDATE", "2005-04-03T22:00:00.0Z"),
|
||||
Money.of(USD, 55));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_customLogicFee() throws Exception {
|
||||
// The "costly-renew" domain has an additional RENEW fee of 100 from custom logic on top of the
|
||||
@@ -269,7 +287,13 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
|
||||
"FEE", "111.00");
|
||||
setEppInput("domain_renew_fee.xml", customFeeMap);
|
||||
persistDomain();
|
||||
doSuccessfulTest("domain_renew_response_fee.xml", 1, customFeeMap, Money.of(USD, 111));
|
||||
doSuccessfulTest(
|
||||
"domain_renew_response_fee.xml",
|
||||
1,
|
||||
"TheRegistrar",
|
||||
UserPrivileges.NORMAL,
|
||||
customFeeMap,
|
||||
Money.of(USD, 111));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -687,7 +711,7 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
|
||||
|
||||
@Test
|
||||
public void testFailure_unauthorizedClient() throws Exception {
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
persistActiveDomain(getUniqueIdFromCommand());
|
||||
EppException thrown = assertThrows(ResourceNotOwnedException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
@@ -695,7 +719,7 @@ public class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, D
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserUnauthorizedClient() throws Exception {
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
persistDomain();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE,
|
||||
|
||||
@@ -19,12 +19,10 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.googlecode.objectify.ObjectifyService;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import google.registry.model.common.CrossTldSingleton;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -35,19 +33,18 @@ import org.junit.runners.JUnit4;
|
||||
public class CreateAutoTimestampTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
|
||||
public final AppEngineRule appEngine =
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.withOfyTestEntities(TestObject.class)
|
||||
.build();
|
||||
|
||||
/** Timestamped class. */
|
||||
@Entity
|
||||
@Entity(name = "CatTestEntity")
|
||||
public static class TestObject extends CrossTldSingleton {
|
||||
CreateAutoTimestamp createTime = CreateAutoTimestamp.create(null);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ObjectifyService.register(TestObject.class);
|
||||
}
|
||||
|
||||
private TestObject reload() {
|
||||
return ofy().load().entity(new TestObject()).now();
|
||||
}
|
||||
|
||||
@@ -42,22 +42,33 @@ import java.util.Set;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Base class of all unit tests for entities which are persisted to Datastore via Objectify. */
|
||||
@RunWith(JUnit4.class)
|
||||
public abstract class EntityTestCase {
|
||||
|
||||
protected FakeClock fakeClock = new FakeClock(DateTime.now(UTC));
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine =
|
||||
AppEngineRule.builder().withDatastoreAndCloudSql().withClock(fakeClock).build();
|
||||
@Rule @RegisterExtension public final AppEngineRule appEngine;
|
||||
|
||||
@Rule public InjectRule inject = new InjectRule();
|
||||
@Rule @RegisterExtension public InjectRule inject = new InjectRule();
|
||||
|
||||
protected EntityTestCase() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
protected EntityTestCase(boolean enableJpaEntityCheck) {
|
||||
appEngine =
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.enableJpaEntityCoverageCheck(enableJpaEntityCheck)
|
||||
.withClock(fakeClock)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Before
|
||||
@BeforeEach
|
||||
public void injectClock() {
|
||||
inject.setStaticField(Ofy.class, "clock", fakeClock);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.ObjectifyService;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
@@ -39,7 +38,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -50,12 +48,11 @@ import org.junit.runners.JUnit4;
|
||||
public class ImmutableObjectTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
|
||||
|
||||
@Before
|
||||
public void register() {
|
||||
ObjectifyService.register(ValueObject.class);
|
||||
}
|
||||
public final AppEngineRule appEngine =
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.withOfyTestEntities(ValueObject.class)
|
||||
.build();
|
||||
|
||||
/** Simple subclass of ImmutableObject. */
|
||||
public static class SimpleObject extends ImmutableObject {
|
||||
|
||||
@@ -19,12 +19,10 @@ import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.googlecode.objectify.ObjectifyService;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import google.registry.model.common.CrossTldSingleton;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -35,19 +33,18 @@ import org.junit.runners.JUnit4;
|
||||
public class UpdateAutoTimestampTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
|
||||
public final AppEngineRule appEngine =
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.withOfyTestEntities(TestObject.class)
|
||||
.build();
|
||||
|
||||
/** Timestamped class. */
|
||||
@Entity
|
||||
@Entity(name = "UatTestEntity")
|
||||
public static class TestObject extends CrossTldSingleton {
|
||||
UpdateAutoTimestamp updateTime = UpdateAutoTimestamp.create(null);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ObjectifyService.register(TestObject.class);
|
||||
}
|
||||
|
||||
private TestObject reload() {
|
||||
return ofy().load().entity(new TestObject()).now();
|
||||
}
|
||||
|
||||
@@ -17,10 +17,13 @@ package google.registry.model.contact;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth8.assertThat;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.testing.ContactResourceSubject.assertAboutContacts;
|
||||
import static google.registry.testing.DatastoreHelper.cloneAndSetAutoTimestamps;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.SqlHelper.assertThrowForeignKeyViolation;
|
||||
import static google.registry.testing.SqlHelper.saveRegistrar;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
@@ -37,87 +40,119 @@ import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.transfer.TransferData;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import google.registry.persistence.VKey;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ContactResource}. */
|
||||
public class ContactResourceTest extends EntityTestCase {
|
||||
ContactResource originalContact;
|
||||
ContactResource contactResource;
|
||||
|
||||
@Before
|
||||
public ContactResourceTest() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
createTld("foobar");
|
||||
originalContact =
|
||||
new ContactResource.Builder()
|
||||
.setContactId("contact_id")
|
||||
.setRepoId("1-FOOBAR")
|
||||
.setCreationClientId("registrar1")
|
||||
.setLastEppUpdateTime(fakeClock.nowUtc())
|
||||
.setLastEppUpdateClientId("registrar2")
|
||||
.setLastTransferTime(fakeClock.nowUtc())
|
||||
.setPersistedCurrentSponsorClientId("registrar3")
|
||||
.setLocalizedPostalInfo(
|
||||
new PostalInfo.Builder()
|
||||
.setType(Type.LOCALIZED)
|
||||
.setAddress(
|
||||
new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("111 8th Ave", "4th Floor"))
|
||||
.setCity("New York")
|
||||
.setState("NY")
|
||||
.setZip("10011")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build())
|
||||
.setInternationalizedPostalInfo(
|
||||
new PostalInfo.Builder()
|
||||
.setType(Type.INTERNATIONALIZED)
|
||||
.setAddress(
|
||||
new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("111 8th Ave", "4th Floor"))
|
||||
.setCity("New York")
|
||||
.setState("NY")
|
||||
.setZip("10011")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build())
|
||||
.setVoiceNumber(new ContactPhoneNumber.Builder().setPhoneNumber("867-5309").build())
|
||||
.setFaxNumber(
|
||||
new ContactPhoneNumber.Builder()
|
||||
.setPhoneNumber("867-5309")
|
||||
.setExtension("1000")
|
||||
.build())
|
||||
.setEmailAddress("jenny@example.com")
|
||||
.setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("passw0rd")))
|
||||
.setDisclose(
|
||||
new Disclose.Builder()
|
||||
.setVoice(new PresenceMarker())
|
||||
.setEmail(new PresenceMarker())
|
||||
.setFax(new PresenceMarker())
|
||||
.setFlag(true)
|
||||
.setAddrs(ImmutableList.of(PostalInfoChoice.create(Type.INTERNATIONALIZED)))
|
||||
.setNames(ImmutableList.of(PostalInfoChoice.create(Type.INTERNATIONALIZED)))
|
||||
.setOrgs(ImmutableList.of(PostalInfoChoice.create(Type.INTERNATIONALIZED)))
|
||||
.build())
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.OK))
|
||||
.setTransferData(
|
||||
new TransferData.Builder()
|
||||
.setGainingClientId("gaining")
|
||||
.setLosingClientId("losing")
|
||||
.setPendingTransferExpirationTime(fakeClock.nowUtc())
|
||||
.setServerApproveEntities(
|
||||
ImmutableSet.of(Key.create(BillingEvent.OneTime.class, 1)))
|
||||
.setTransferRequestTime(fakeClock.nowUtc())
|
||||
.setTransferStatus(TransferStatus.SERVER_APPROVED)
|
||||
.setTransferRequestTrid(Trid.create("client-trid", "server-trid"))
|
||||
.build())
|
||||
.build();
|
||||
// Set up a new persisted ContactResource entity.
|
||||
contactResource =
|
||||
persistResource(
|
||||
cloneAndSetAutoTimestamps(
|
||||
new ContactResource.Builder()
|
||||
.setContactId("contact_id")
|
||||
.setRepoId("1-FOOBAR")
|
||||
.setCreationClientId("a registrar")
|
||||
.setLastEppUpdateTime(fakeClock.nowUtc())
|
||||
.setLastEppUpdateClientId("another registrar")
|
||||
.setLastTransferTime(fakeClock.nowUtc())
|
||||
.setPersistedCurrentSponsorClientId("a third registrar")
|
||||
.setLocalizedPostalInfo(
|
||||
new PostalInfo.Builder()
|
||||
.setType(Type.LOCALIZED)
|
||||
.setAddress(
|
||||
new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("111 8th Ave", "4th Floor"))
|
||||
.setCity("New York")
|
||||
.setState("NY")
|
||||
.setZip("10011")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build())
|
||||
.setInternationalizedPostalInfo(
|
||||
new PostalInfo.Builder()
|
||||
.setType(Type.INTERNATIONALIZED)
|
||||
.setAddress(
|
||||
new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("111 8th Ave", "4th Floor"))
|
||||
.setCity("New York")
|
||||
.setState("NY")
|
||||
.setZip("10011")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build())
|
||||
.setVoiceNumber(
|
||||
new ContactPhoneNumber.Builder().setPhoneNumber("867-5309").build())
|
||||
.setFaxNumber(
|
||||
new ContactPhoneNumber.Builder()
|
||||
.setPhoneNumber("867-5309")
|
||||
.setExtension("1000")
|
||||
.build())
|
||||
.setEmailAddress("jenny@example.com")
|
||||
.setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("passw0rd")))
|
||||
.setDisclose(
|
||||
new Disclose.Builder()
|
||||
.setVoice(new PresenceMarker())
|
||||
.setEmail(new PresenceMarker())
|
||||
.setFax(new PresenceMarker())
|
||||
.setFlag(true)
|
||||
.setAddrs(
|
||||
ImmutableList.of(PostalInfoChoice.create(Type.INTERNATIONALIZED)))
|
||||
.setNames(
|
||||
ImmutableList.of(PostalInfoChoice.create(Type.INTERNATIONALIZED)))
|
||||
.setOrgs(
|
||||
ImmutableList.of(PostalInfoChoice.create(Type.INTERNATIONALIZED)))
|
||||
.build())
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.OK))
|
||||
.setTransferData(
|
||||
new TransferData.Builder()
|
||||
.setGainingClientId("gaining")
|
||||
.setLosingClientId("losing")
|
||||
.setPendingTransferExpirationTime(fakeClock.nowUtc())
|
||||
.setServerApproveEntities(
|
||||
ImmutableSet.of(Key.create(BillingEvent.OneTime.class, 1)))
|
||||
.setTransferRequestTime(fakeClock.nowUtc())
|
||||
.setTransferStatus(TransferStatus.SERVER_APPROVED)
|
||||
.setTransferRequestTrid(Trid.create("client-trid", "server-trid"))
|
||||
.build())
|
||||
.build()));
|
||||
contactResource = persistResource(cloneAndSetAutoTimestamps(originalContact));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloudSqlPersistence_failWhenViolateForeignKeyConstraint() {
|
||||
assertThrowForeignKeyViolation(() -> jpaTm().transact(() -> jpaTm().saveNew(originalContact)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloudSqlPersistence_succeed() {
|
||||
saveRegistrar("registrar1");
|
||||
saveRegistrar("registrar2");
|
||||
saveRegistrar("registrar3");
|
||||
jpaTm().transact(() -> jpaTm().saveNew(originalContact));
|
||||
ContactResource persisted =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.load(VKey.createSql(ContactResource.class, originalContact.getRepoId())))
|
||||
.get();
|
||||
// TODO(b/153378849): Remove the hard code for postal info after resolving the issue that
|
||||
// @PostLoad doesn't work in Address
|
||||
ContactResource fixed =
|
||||
originalContact
|
||||
.asBuilder()
|
||||
.setCreationTime(persisted.getCreationTime())
|
||||
.setInternationalizedPostalInfo(persisted.getInternationalizedPostalInfo())
|
||||
.setLocalizedPostalInfo(persisted.getLocalizedPostalInfo())
|
||||
.setTransferData(null)
|
||||
.build();
|
||||
assertThat(persisted).isEqualTo(fixed);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -16,44 +16,67 @@ package google.registry.model.domain;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.testing.SqlHelper.assertThrowForeignKeyViolation;
|
||||
import static google.registry.testing.SqlHelper.saveRegistrar;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.EntityTestCase;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DesignatedContact.Type;
|
||||
import google.registry.model.domain.launch.LaunchNotice;
|
||||
import google.registry.model.domain.secdns.DelegationSignerData;
|
||||
import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageExtension;
|
||||
import google.registry.testing.DatastoreEntityExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import javax.persistence.EntityManager;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Verify that we can store/retrieve DomainBase objects from a SQL database. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class DomainBaseSqlTest extends EntityTestCase {
|
||||
public class DomainBaseSqlTest {
|
||||
|
||||
protected FakeClock fakeClock = new FakeClock(DateTime.now(UTC));
|
||||
|
||||
@RegisterExtension
|
||||
@Order(value = 1)
|
||||
DatastoreEntityExtension datastoreEntityExtension = new DatastoreEntityExtension();
|
||||
|
||||
@RegisterExtension
|
||||
JpaIntegrationWithCoverageExtension jpa =
|
||||
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationWithCoverageExtension();
|
||||
|
||||
DomainBase domain;
|
||||
Key<ContactResource> contactKey;
|
||||
Key<ContactResource> contact2Key;
|
||||
VKey<HostResource> host1VKey;
|
||||
HostResource host;
|
||||
|
||||
@Before
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
contactKey = Key.create(ContactResource.class, "contact_id1");
|
||||
contact2Key = Key.create(ContactResource.class, "contact_id2");
|
||||
|
||||
host1VKey = VKey.createSql(HostResource.class, "host1");
|
||||
|
||||
domain =
|
||||
new DomainBase.Builder()
|
||||
.setFullyQualifiedDomainName("example.com")
|
||||
.setRepoId("4-COM")
|
||||
.setCreationClientId("a registrar")
|
||||
.setCreationClientId("registrar1")
|
||||
.setLastEppUpdateTime(fakeClock.nowUtc())
|
||||
.setLastEppUpdateClientId("AnotherRegistrar")
|
||||
.setLastEppUpdateClientId("registrar2")
|
||||
.setLastTransferTime(fakeClock.nowUtc())
|
||||
.setNameservers(host1VKey)
|
||||
.setStatusValues(
|
||||
ImmutableSet.of(
|
||||
StatusValue.CLIENT_DELETE_PROHIBITED,
|
||||
@@ -65,7 +88,7 @@ public class DomainBaseSqlTest extends EntityTestCase {
|
||||
.setRegistrant(contactKey)
|
||||
.setContacts(ImmutableSet.of(DesignatedContact.create(Type.ADMIN, contact2Key)))
|
||||
.setSubordinateHosts(ImmutableSet.of("ns1.example.com"))
|
||||
.setPersistedCurrentSponsorClientId("losing")
|
||||
.setPersistedCurrentSponsorClientId("registrar3")
|
||||
.setRegistrationExpirationTime(fakeClock.nowUtc().plusYears(1))
|
||||
.setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("password")))
|
||||
.setDsData(ImmutableSet.of(DelegationSignerData.create(1, 2, 3, new byte[] {0, 1, 2})))
|
||||
@@ -73,16 +96,31 @@ public class DomainBaseSqlTest extends EntityTestCase {
|
||||
LaunchNotice.create("tcnid", "validatorId", START_OF_TIME, START_OF_TIME))
|
||||
.setSmdId("smdid")
|
||||
.build();
|
||||
|
||||
host =
|
||||
new HostResource.Builder()
|
||||
.setRepoId("host1")
|
||||
.setFullyQualifiedHostName("ns1.example.com")
|
||||
.setCreationClientId("registrar1")
|
||||
.setPersistedCurrentSponsorClientId("registrar2")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainBasePersistence() {
|
||||
saveRegistrar("registrar1");
|
||||
saveRegistrar("registrar2");
|
||||
saveRegistrar("registrar3");
|
||||
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
// Persist the domain.
|
||||
EntityManager em = jpaTm().getEntityManager();
|
||||
em.persist(domain);
|
||||
|
||||
// Persist the host.
|
||||
em.persist(host);
|
||||
});
|
||||
|
||||
jpaTm()
|
||||
@@ -111,4 +149,18 @@ public class DomainBaseSqlTest extends EntityTestCase {
|
||||
assertThat(result).isEqualTo(org);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForeignKeyConstraints() {
|
||||
assertThrowForeignKeyViolation(
|
||||
() -> {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
// Persist the domain without the associated host object.
|
||||
EntityManager em = jpaTm().getEntityManager();
|
||||
em.persist(domain);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package google.registry.model.ofy;
|
||||
|
||||
import static com.google.appengine.api.datastore.EntityTranslator.convertToPb;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.googlecode.objectify.ObjectifyService.register;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.model.ofy.CommitLogBucket.getBucketKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
@@ -47,7 +46,11 @@ import org.junit.runners.JUnit4;
|
||||
public class OfyCommitLogTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
|
||||
public final AppEngineRule appEngine =
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.withOfyTestEntities(TestVirtualObject.class, Root.class, Child.class)
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
@@ -56,8 +59,6 @@ public class OfyCommitLogTest {
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
register(Root.class);
|
||||
register(Child.class);
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,20 +31,21 @@ import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link RegistryLockDao}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public final class RegistryLockDaoTest {
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
|
||||
@Rule
|
||||
@RegisterExtension
|
||||
public final AppEngineRule appEngine =
|
||||
AppEngineRule.builder().withDatastoreAndCloudSql().withClock(fakeClock).build();
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.enableJpaEntityCoverageCheck(true)
|
||||
.withClock(fakeClock)
|
||||
.build();
|
||||
|
||||
@Test
|
||||
public void testSaveAndLoad_success() {
|
||||
|
||||
@@ -29,16 +29,14 @@ import google.registry.model.registry.label.PremiumList.PremiumListEntry;
|
||||
import google.registry.model.registry.label.PremiumList.PremiumListRevision;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import org.joda.money.Money;
|
||||
import org.junit.Rule;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.migrationsupport.rules.EnableRuleMigrationSupport;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link PremiumList}. */
|
||||
@EnableRuleMigrationSupport
|
||||
public class PremiumListTest {
|
||||
|
||||
@Rule
|
||||
@RegisterExtension
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
|
||||
|
||||
@BeforeEach
|
||||
|
||||
@@ -28,7 +28,6 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import google.registry.model.ofy.Ofy;
|
||||
import google.registry.model.server.Lock.LockState;
|
||||
import google.registry.schema.server.LockDao;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.InjectRule;
|
||||
@@ -65,19 +64,16 @@ public class LockTest {
|
||||
Optional<Lock> lock = Lock.acquire(RESOURCE_NAME, tld, leaseLength, requestStatusChecker, true);
|
||||
verify(Lock.lockMetrics).recordAcquire(RESOURCE_NAME, tld, expectedLockState);
|
||||
verifyNoMoreInteractions(Lock.lockMetrics);
|
||||
assertThat(LockDao.load(RESOURCE_NAME, tld)).isPresent();
|
||||
Lock.lockMetrics = null;
|
||||
return lock;
|
||||
}
|
||||
|
||||
private void release(Lock lock, String expectedTld, long expectedMillis) {
|
||||
assertThat(LockDao.load(RESOURCE_NAME, expectedTld)).isPresent();
|
||||
Lock.lockMetrics = mock(LockMetrics.class);
|
||||
lock.release();
|
||||
verify(Lock.lockMetrics)
|
||||
.recordRelease(RESOURCE_NAME, expectedTld, Duration.millis(expectedMillis));
|
||||
verifyNoMoreInteractions(Lock.lockMetrics);
|
||||
assertThat(LockDao.load(RESOURCE_NAME, expectedTld)).isEmpty();
|
||||
Lock.lockMetrics = null;
|
||||
}
|
||||
|
||||
|
||||
+6
-4
@@ -23,7 +23,6 @@ import static org.joda.time.Duration.standardHours;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.ObjectifyService;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import google.registry.model.common.CrossTldSingleton;
|
||||
import google.registry.model.ofy.CommitLogManifest;
|
||||
@@ -45,13 +44,17 @@ public class CommitLogRevisionsTranslatorFactoryTest {
|
||||
|
||||
private static final DateTime START_TIME = DateTime.parse("2000-01-01TZ");
|
||||
|
||||
@Entity
|
||||
@Entity(name = "ClrtfTestEntity")
|
||||
public static class TestObject extends CrossTldSingleton {
|
||||
ImmutableSortedMap<DateTime, Key<CommitLogManifest>> revisions = ImmutableSortedMap.of();
|
||||
}
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
|
||||
public final AppEngineRule appEngine =
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.withOfyTestEntities(TestObject.class)
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
@@ -60,7 +63,6 @@ public class CommitLogRevisionsTranslatorFactoryTest {
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ObjectifyService.register(TestObject.class);
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
|
||||
import java.lang.reflect.Method;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.PostLoad;
|
||||
import javax.persistence.PostPersist;
|
||||
import javax.persistence.PostRemove;
|
||||
import javax.persistence.PostUpdate;
|
||||
import javax.persistence.PrePersist;
|
||||
import javax.persistence.PreRemove;
|
||||
import javax.persistence.PreUpdate;
|
||||
import javax.persistence.Transient;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link EntityCallbacksListener}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class EntityCallbacksListenerTest {
|
||||
|
||||
@Rule
|
||||
public final JpaUnitTestRule jpaRule =
|
||||
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
|
||||
|
||||
@Test
|
||||
public void verifyAllCallbacks_executedExpectedTimes() {
|
||||
TestEntity testPersist = new TestEntity();
|
||||
jpaTm().transact(() -> jpaTm().saveNew(testPersist));
|
||||
checkAll(testPersist, 1, 0, 0, 0);
|
||||
|
||||
TestEntity testUpdate = new TestEntity();
|
||||
TestEntity updated =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
TestEntity merged = jpaTm().getEntityManager().merge(testUpdate);
|
||||
merged.foo++;
|
||||
jpaTm().getEntityManager().flush();
|
||||
return merged;
|
||||
});
|
||||
// Note that when we get the merged entity, its @PostLoad callbacks are also invoked
|
||||
checkAll(updated, 0, 1, 0, 1);
|
||||
|
||||
TestEntity testLoad =
|
||||
jpaTm().transact(() -> jpaTm().load(VKey.createSql(TestEntity.class, "id"))).get();
|
||||
checkAll(testLoad, 0, 0, 0, 1);
|
||||
|
||||
TestEntity testRemove =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
TestEntity removed = jpaTm().load(VKey.createSql(TestEntity.class, "id")).get();
|
||||
jpaTm().getEntityManager().remove(removed);
|
||||
return removed;
|
||||
});
|
||||
checkAll(testRemove, 0, 0, 1, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyAllManagedEntities_haveNoMethodWithEmbedded() {
|
||||
ImmutableSet<Class> violations =
|
||||
PersistenceXmlUtility.getManagedClasses().stream()
|
||||
.filter(clazz -> clazz.isAnnotationPresent(Entity.class))
|
||||
.filter(EntityCallbacksListenerTest::hasMethodAnnotatedWithEmbedded)
|
||||
.collect(toImmutableSet());
|
||||
assertWithMessage(
|
||||
"Found entity classes having methods annotated with @Embedded. EntityCallbacksListener"
|
||||
+ " only supports annotating fields with @Embedded.")
|
||||
.that(violations)
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyHasMethodAnnotatedWithEmbedded_work() {
|
||||
assertThat(hasMethodAnnotatedWithEmbedded(ViolationEntity.class)).isTrue();
|
||||
}
|
||||
|
||||
private static boolean hasMethodAnnotatedWithEmbedded(Class<?> entityType) {
|
||||
boolean result = false;
|
||||
Class<?> parentType = entityType.getSuperclass();
|
||||
if (parentType != null && parentType.isAnnotationPresent(MappedSuperclass.class)) {
|
||||
result = hasMethodAnnotatedWithEmbedded(parentType);
|
||||
}
|
||||
for (Method method : entityType.getDeclaredMethods()) {
|
||||
if (method.isAnnotationPresent(Embedded.class)) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void checkAll(
|
||||
TestEntity testEntity,
|
||||
int expectedPersist,
|
||||
int expectedUpdate,
|
||||
int expectedRemove,
|
||||
int expectedLoad) {
|
||||
assertThat(testEntity.entityEmbedded.entityEmbeddedNested.entityEmbeddedNestedPostPersist)
|
||||
.isEqualTo(expectedPersist);
|
||||
assertThat(testEntity.entityEmbedded.entityEmbeddedNested.entityEmbeddedNestedPrePersist)
|
||||
.isEqualTo(expectedPersist);
|
||||
|
||||
assertThat(testEntity.entityEmbedded.entityEmbeddedNested.entityEmbeddedNestedPreUpdate)
|
||||
.isEqualTo(expectedUpdate);
|
||||
assertThat(testEntity.entityEmbedded.entityEmbeddedNested.entityEmbeddedNestedPostUpdate)
|
||||
.isEqualTo(expectedUpdate);
|
||||
|
||||
assertThat(testEntity.entityEmbedded.entityEmbeddedNested.entityEmbeddedNestedPreRemove)
|
||||
.isEqualTo(expectedRemove);
|
||||
assertThat(testEntity.entityEmbedded.entityEmbeddedNested.entityEmbeddedNestedPostRemove)
|
||||
.isEqualTo(expectedRemove);
|
||||
|
||||
assertThat(testEntity.entityPostLoad).isEqualTo(expectedLoad);
|
||||
assertThat(testEntity.entityEmbedded.entityEmbeddedPostLoad).isEqualTo(expectedLoad);
|
||||
assertThat(testEntity.entityEmbedded.entityEmbeddedNested.entityEmbeddedNestedPostLoad)
|
||||
.isEqualTo(expectedLoad);
|
||||
assertThat(testEntity.entityEmbedded.entityEmbeddedParentPostLoad).isEqualTo(expectedLoad);
|
||||
|
||||
assertThat(testEntity.parentPostLoad).isEqualTo(expectedLoad);
|
||||
assertThat(testEntity.parentEmbedded.parentEmbeddedPostLoad).isEqualTo(expectedLoad);
|
||||
assertThat(testEntity.parentEmbedded.parentEmbeddedNested.parentEmbeddedNestedPostLoad)
|
||||
.isEqualTo(expectedLoad);
|
||||
assertThat(testEntity.parentEmbedded.parentEmbeddedParentPostLoad).isEqualTo(expectedLoad);
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity")
|
||||
private static class TestEntity extends ParentEntity {
|
||||
@Id String name = "id";
|
||||
int foo = 0;
|
||||
|
||||
@Transient int entityPostLoad = 0;
|
||||
|
||||
@Embedded EntityEmbedded entityEmbedded = new EntityEmbedded();
|
||||
|
||||
@PostLoad
|
||||
void entityPostLoad() {
|
||||
entityPostLoad++;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
private static class EntityEmbedded extends EntityEmbeddedParent {
|
||||
@Embedded EntityEmbeddedNested entityEmbeddedNested = new EntityEmbeddedNested();
|
||||
|
||||
@Transient int entityEmbeddedPostLoad = 0;
|
||||
|
||||
String entityEmbedded = "placeholder";
|
||||
|
||||
@PostLoad
|
||||
void entityEmbeddedPrePersist() {
|
||||
entityEmbeddedPostLoad++;
|
||||
}
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
private static class EntityEmbeddedParent {
|
||||
@Transient int entityEmbeddedParentPostLoad = 0;
|
||||
|
||||
String entityEmbeddedParent = "placeholder";
|
||||
|
||||
@PostLoad
|
||||
void entityEmbeddedParentPostLoad() {
|
||||
entityEmbeddedParentPostLoad++;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
private static class EntityEmbeddedNested {
|
||||
@Transient int entityEmbeddedNestedPrePersist = 0;
|
||||
@Transient int entityEmbeddedNestedPreRemove = 0;
|
||||
@Transient int entityEmbeddedNestedPostPersist = 0;
|
||||
@Transient int entityEmbeddedNestedPostRemove = 0;
|
||||
@Transient int entityEmbeddedNestedPreUpdate = 0;
|
||||
@Transient int entityEmbeddedNestedPostUpdate = 0;
|
||||
@Transient int entityEmbeddedNestedPostLoad = 0;
|
||||
|
||||
String entityEmbeddedNested = "placeholder";
|
||||
|
||||
@PrePersist
|
||||
void entityEmbeddedNestedPrePersist() {
|
||||
entityEmbeddedNestedPrePersist++;
|
||||
}
|
||||
|
||||
@PreRemove
|
||||
void entityEmbeddedNestedPreRemove() {
|
||||
entityEmbeddedNestedPreRemove++;
|
||||
}
|
||||
|
||||
@PostPersist
|
||||
void entityEmbeddedNestedPostPersist() {
|
||||
entityEmbeddedNestedPostPersist++;
|
||||
}
|
||||
|
||||
@PostRemove
|
||||
void entityEmbeddedNestedPostRemove() {
|
||||
entityEmbeddedNestedPostRemove++;
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
void entityEmbeddedNestedPreUpdate() {
|
||||
entityEmbeddedNestedPreUpdate++;
|
||||
}
|
||||
|
||||
@PostUpdate
|
||||
void entityEmbeddedNestedPostUpdate() {
|
||||
entityEmbeddedNestedPostUpdate++;
|
||||
}
|
||||
|
||||
@PostLoad
|
||||
void entityEmbeddedNestedPostLoad() {
|
||||
entityEmbeddedNestedPostLoad++;
|
||||
}
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
private static class ParentEntity {
|
||||
@Embedded ParentEmbedded parentEmbedded = new ParentEmbedded();
|
||||
@Transient int parentPostLoad = 0;
|
||||
|
||||
String parentEntity = "placeholder";
|
||||
|
||||
@PostLoad
|
||||
void parentPostLoad() {
|
||||
parentPostLoad++;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
private static class ParentEmbedded extends ParentEmbeddedParent {
|
||||
@Transient int parentEmbeddedPostLoad = 0;
|
||||
|
||||
String parentEmbedded = "placeholder";
|
||||
|
||||
@Embedded ParentEmbeddedNested parentEmbeddedNested = new ParentEmbeddedNested();
|
||||
|
||||
@PostLoad
|
||||
void parentEmbeddedPostLoad() {
|
||||
parentEmbeddedPostLoad++;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
private static class ParentEmbeddedNested {
|
||||
@Transient int parentEmbeddedNestedPostLoad = 0;
|
||||
|
||||
String parentEmbeddedNested = "placeholder";
|
||||
|
||||
@PostLoad
|
||||
void parentEmbeddedNestedPostLoad() {
|
||||
parentEmbeddedNestedPostLoad++;
|
||||
}
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
private static class ParentEmbeddedParent {
|
||||
@Transient int parentEmbeddedParentPostLoad = 0;
|
||||
|
||||
String parentEmbeddedParent = "placeholder";
|
||||
|
||||
@PostLoad
|
||||
void parentEmbeddedParentPostLoad() {
|
||||
parentEmbeddedParentPostLoad++;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
private static class ViolationEntity {
|
||||
|
||||
@Embedded
|
||||
EntityEmbedded getEntityEmbedded() {
|
||||
return new EntityEmbedded();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2020 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.
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.TestObject;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class VKeyTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngineRule =
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.withOfyTestEntities(TestObject.class)
|
||||
.build();
|
||||
|
||||
public VKeyTest() {}
|
||||
|
||||
@Test
|
||||
public void testOptionalAccessors() {
|
||||
VKey<TestObject> key =
|
||||
VKey.create(TestObject.class, "foo", Key.create(TestObject.create("foo")));
|
||||
assertThat(key.maybeGetSqlKey().isPresent()).isTrue();
|
||||
assertThat(key.maybeGetOfyKey().isPresent()).isTrue();
|
||||
|
||||
Key<TestObject> ofyKey = Key.create(TestObject.create("foo"));
|
||||
assertThat(VKey.createOfy(TestObject.class, ofyKey).maybeGetOfyKey().get()).isEqualTo(ofyKey);
|
||||
assertThat(VKey.createSql(TestObject.class, "foo").maybeGetSqlKey().get()).isEqualTo("foo");
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -32,7 +32,7 @@ import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link CidrAddressBlockListConverter}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class CidrAddressBlockListUserTypeTest {
|
||||
public class CidrAddressBlockListConverterTest {
|
||||
@Rule
|
||||
public final JpaUnitTestRule jpaRule =
|
||||
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
|
||||
+2
-4
@@ -25,16 +25,15 @@ import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link CurrencyToBillingMapUserType}. */
|
||||
/** Unit tests for {@link CurrencyToBillingConverter}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class CurrencyToBillingMapUserTypeTest {
|
||||
public class CurrencyToBillingConverterTest {
|
||||
@Rule
|
||||
public final JpaUnitTestRule jpaRule =
|
||||
new JpaTestRules.Builder()
|
||||
@@ -62,7 +61,6 @@ public class CurrencyToBillingMapUserTypeTest {
|
||||
|
||||
@Id String name = "id";
|
||||
|
||||
@Type(type = "google.registry.persistence.converter.CurrencyToBillingMapUserType")
|
||||
Map<CurrencyUnit, BillingAccountEntry> currencyToBilling;
|
||||
|
||||
private TestEntity() {}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user