mirror of
https://github.com/google/nomulus
synced 2026-08-10 09:16:12 +00:00
Compare commits
34
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85c11ca889 | ||
|
|
340bf40642 | ||
|
|
53ece5eda4 | ||
|
|
6c220567c8 | ||
|
|
c3e3a1353b | ||
|
|
ce480a5191 | ||
|
|
f2a2b2d2e2 | ||
|
|
906b054f4b | ||
|
|
a694e247cd | ||
|
|
022f397cd9 | ||
|
|
5dc058ec99 | ||
|
|
0fd7cf29b5 | ||
|
|
bc7f3546c7 | ||
|
|
658f61bd8f | ||
|
|
8ca8fff387 | ||
|
|
8bcfb1802e | ||
|
|
a259dee986 | ||
|
|
ebc8d54f94 | ||
|
|
e9ce389269 | ||
|
|
e07be9780e | ||
|
|
31b5abb9a1 | ||
|
|
aa4e242a34 | ||
|
|
964f264c9d | ||
|
|
cc018a6dac | ||
|
|
c25adbbd9c | ||
|
|
42edf16f3f | ||
|
|
36ab0cb45c | ||
|
|
34da498958 | ||
|
|
a3317b8552 | ||
|
|
9c7872dbb7 | ||
|
|
ff439f598d | ||
|
|
b0c13042a6 | ||
|
|
3009f754fa | ||
|
|
cc314d4838 |
@@ -2,7 +2,7 @@
|
||||
|
||||
| Internal Build | FOSS Build | LGTM | License | Code Search |
|
||||
|----------------|------------|------|---------|-------------|
|
||||
|[](https://storage.googleapis.com/domain-registry-kokoro/internal/index.html)|[](https://storage.googleapis.com/domain-registry-kokoro/foss/index.html)|[](https://lgtm.com/projects/g/google/nomulus/alerts/)|[](https://github.com/google/nomulus/blob/master/LICENSE)|[](https://sourcegraph.com/github.com/google/nomulus)|
|
||||
|[](https://storage.googleapis.com/domain-registry-kokoro/internal/index.html)|[](https://storage.googleapis.com/domain-registry-kokoro/foss/index.html)|[](https://lgtm.com/projects/g/google/nomulus/alerts/)|[](https://github.com/google/nomulus/blob/master/LICENSE)|[](https://sourcegraph.com/github.com/google/nomulus)|
|
||||
|
||||

|
||||
|
||||
|
||||
+22
-3
@@ -12,7 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
apply from: "${rootDir.path}/projects.gradle"
|
||||
apply plugin: 'war'
|
||||
|
||||
def environment = rootProject.environment
|
||||
@@ -26,14 +25,19 @@ project.convention.plugins['war'].webAppDirName =
|
||||
|
||||
apply plugin: 'com.google.cloud.tools.appengine'
|
||||
|
||||
def coreResourcesDir = "${rootDir}/core/build/resources/main"
|
||||
|
||||
// Get the web.xml file for the service.
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def coreResourcesDir = "${rootDir}/core/build/resources/main"
|
||||
war {
|
||||
from("${coreResourcesDir}/google/registry/ui/html") {
|
||||
include "*.html"
|
||||
@@ -68,6 +72,10 @@ appengine {
|
||||
if (!rootProject.prodOrSandboxEnv) {
|
||||
version = 'GCLOUD_CONFIG'
|
||||
}
|
||||
|
||||
// Don't set gcpProject directly, it gets overriden in ./build.gradle.
|
||||
// Do -P environment={crash,alpha} instead. For sandbox/production,
|
||||
// use Spinnaker.
|
||||
projectId = gcpProject
|
||||
}
|
||||
}
|
||||
@@ -92,4 +100,15 @@ explodeWar.doLast {
|
||||
|
||||
rootProject.deploy.dependsOn appengineDeployAll
|
||||
rootProject.stage.dependsOn appengineStage
|
||||
appengineDeployAll.dependsOn rootProject.verifyDeployment
|
||||
|
||||
// Impose verification for all of the deployment tasks. We haven't found a
|
||||
// better way to do this other than to apply to each of them independently.
|
||||
// If a new task gets added, it will still fail if "environment" is not defined
|
||||
// because gcpProject is null. We just won't get as friendly an error message.
|
||||
appengineDeployAll.configure rootProject.verifyDeploymentConfig
|
||||
appengineDeploy.configure rootProject.verifyDeploymentConfig
|
||||
appengineDeployCron.configure rootProject.verifyDeploymentConfig
|
||||
appengineDeployDispatch.configure rootProject.verifyDeploymentConfig
|
||||
appengineDeployDos.configure rootProject.verifyDeploymentConfig
|
||||
appengineDeployIndex.configure rootProject.verifyDeploymentConfig
|
||||
appengineDeployQueue.configure rootProject.verifyDeploymentConfig
|
||||
|
||||
+50
-10
@@ -109,21 +109,61 @@ task deploy {
|
||||
description = 'Deploys all services to App Engine.'
|
||||
}
|
||||
|
||||
task verifyDeployment {
|
||||
group = 'deployment'
|
||||
description = 'Ensure that one cannot deploy to production or sandbox.'
|
||||
doFirst {
|
||||
if (rootProject.prodOrSandboxEnv) {
|
||||
throw new GradleException("Cannot deploy to production or sandbox.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task stage {
|
||||
group = 'deployment'
|
||||
description = 'Generates application directories for all services.'
|
||||
}
|
||||
|
||||
// App-engine environment configuration. We set up all of the variables in
|
||||
// the root project.
|
||||
|
||||
def environments = ['production', 'sandbox', 'alpha', 'crash']
|
||||
|
||||
def gcpProject = null
|
||||
|
||||
apply from: "${rootDir.path}/projects.gradle"
|
||||
|
||||
if (environment == '') {
|
||||
// Keep the project null, this will prevent deployment. Set the
|
||||
// environment to "alpha" because other code needs this property to
|
||||
// explode the war file.
|
||||
environment = 'alpha'
|
||||
} else if (environment != 'production' && environment != 'sandbox') {
|
||||
gcpProject = projects[environment]
|
||||
if (gcpProject == null) {
|
||||
throw new GradleException("-Penvironment must be one of " +
|
||||
"${projects.keySet()}.")
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.ext.environment = environment
|
||||
rootProject.ext.gcpProject = gcpProject
|
||||
rootProject.ext.prodOrSandboxEnv = environment in ['production', 'sandbox']
|
||||
|
||||
// Function to verify that the deployment parameters have been set.
|
||||
def verifyDeploymentParams() {
|
||||
if (prodOrSandboxEnv) {
|
||||
// Do not deploy to prod or sandbox. Print a prominent error in bright red.
|
||||
System.err.println('\033[31;1m-----------------------------------------------------------------')
|
||||
System.err.println('*** DANGER WILL ROBINSON!')
|
||||
System.err.println('*** You may not deploy to production or sandbox from gradle. Do a')
|
||||
System.err.println('*** release from Spinnaker, see deployment playbook.')
|
||||
System.err.println('-----------------------------------------------------------------')
|
||||
throw new GradleException('Aborting. See prominent error above.')
|
||||
} else if (gcpProject == null) {
|
||||
def error = 'You must specify -P environment={alpha,crash}'
|
||||
System.err.println("\033[33;1m${error}\033[0m")
|
||||
throw GradleException("Aborting: ${error}")
|
||||
}
|
||||
}
|
||||
|
||||
// Closure that we can just drop into all of our deployment tasks.
|
||||
rootProject.ext.verifyDeploymentConfig = {
|
||||
doFirst { verifyDeploymentParams() }
|
||||
}
|
||||
|
||||
// Subproject configuration.
|
||||
|
||||
allprojects {
|
||||
// Skip no-op project
|
||||
if (project.name == 'services') return
|
||||
|
||||
@@ -20,9 +20,9 @@ com.google.cloud:google-cloud-storage:1.59.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.code.gson:gson:2.7
|
||||
com.google.common.html.types:types:1.0.4
|
||||
com.google.errorprone:error_prone_annotations:2.2.0
|
||||
com.google.errorprone:error_prone_annotations:2.3.2
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.0-beta1
|
||||
com.google.http-client:google-http-client-appengine:1.27.0
|
||||
@@ -50,8 +50,8 @@ org.apache.commons:commons-lang3:3.8.1
|
||||
org.apache.commons:commons-text:1.6
|
||||
org.apache.httpcomponents:httpclient:4.5.8
|
||||
org.apache.httpcomponents:httpcore:4.4.11
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.json:json:20160212
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
|
||||
@@ -20,9 +20,9 @@ com.google.cloud:google-cloud-storage:1.59.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.code.gson:gson:2.7
|
||||
com.google.common.html.types:types:1.0.4
|
||||
com.google.errorprone:error_prone_annotations:2.2.0
|
||||
com.google.errorprone:error_prone_annotations:2.3.2
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.0-beta1
|
||||
com.google.http-client:google-http-client-appengine:1.27.0
|
||||
@@ -50,8 +50,8 @@ org.apache.commons:commons-lang3:3.8.1
|
||||
org.apache.commons:commons-text:1.6
|
||||
org.apache.httpcomponents:httpclient:4.5.8
|
||||
org.apache.httpcomponents:httpcore:4.4.11
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.json:json:20160212
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
|
||||
@@ -20,9 +20,9 @@ com.google.cloud:google-cloud-storage:1.59.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.code.gson:gson:2.7
|
||||
com.google.common.html.types:types:1.0.4
|
||||
com.google.errorprone:error_prone_annotations:2.2.0
|
||||
com.google.errorprone:error_prone_annotations:2.3.2
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.0-beta1
|
||||
com.google.http-client:google-http-client-appengine:1.27.0
|
||||
@@ -50,8 +50,8 @@ org.apache.commons:commons-lang3:3.8.1
|
||||
org.apache.commons:commons-text:1.6
|
||||
org.apache.httpcomponents:httpclient:4.5.8
|
||||
org.apache.httpcomponents:httpcore:4.4.11
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.json:json:20160212
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
|
||||
@@ -20,9 +20,9 @@ com.google.cloud:google-cloud-storage:1.59.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.code.gson:gson:2.7
|
||||
com.google.common.html.types:types:1.0.4
|
||||
com.google.errorprone:error_prone_annotations:2.3.1
|
||||
com.google.errorprone:error_prone_annotations:2.3.2
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.0-beta1
|
||||
com.google.http-client:google-http-client-appengine:1.27.0
|
||||
@@ -35,8 +35,8 @@ com.google.oauth-client:google-oauth-client:1.27.0
|
||||
com.google.protobuf:protobuf-java-util:3.6.1
|
||||
com.google.protobuf:protobuf-java:3.6.1
|
||||
com.google.template:soy:2018-03-14
|
||||
com.google.truth.extensions:truth-java8-extension:0.45
|
||||
com.google.truth:truth:0.45
|
||||
com.google.truth.extensions:truth-java8-extension:1.0
|
||||
com.google.truth:truth:1.0
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
com.ibm.icu:icu4j:57.1
|
||||
commons-codec:commons-codec:1.11
|
||||
@@ -57,8 +57,8 @@ org.apache.commons:commons-text:1.6
|
||||
org.apache.httpcomponents:httpclient:4.5.8
|
||||
org.apache.httpcomponents:httpcore:4.4.11
|
||||
org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.json:json:20160212
|
||||
org.mockito:mockito-core:2.25.0
|
||||
|
||||
@@ -20,9 +20,9 @@ com.google.cloud:google-cloud-storage:1.59.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.code.gson:gson:2.7
|
||||
com.google.common.html.types:types:1.0.4
|
||||
com.google.errorprone:error_prone_annotations:2.3.1
|
||||
com.google.errorprone:error_prone_annotations:2.3.2
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.0-beta1
|
||||
com.google.http-client:google-http-client-appengine:1.27.0
|
||||
@@ -35,8 +35,8 @@ com.google.oauth-client:google-oauth-client:1.27.0
|
||||
com.google.protobuf:protobuf-java-util:3.6.1
|
||||
com.google.protobuf:protobuf-java:3.6.1
|
||||
com.google.template:soy:2018-03-14
|
||||
com.google.truth.extensions:truth-java8-extension:0.45
|
||||
com.google.truth:truth:0.45
|
||||
com.google.truth.extensions:truth-java8-extension:1.0
|
||||
com.google.truth:truth:1.0
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
com.ibm.icu:icu4j:57.1
|
||||
commons-codec:commons-codec:1.11
|
||||
@@ -57,8 +57,8 @@ org.apache.commons:commons-text:1.6
|
||||
org.apache.httpcomponents:httpclient:4.5.8
|
||||
org.apache.httpcomponents:httpcore:4.4.11
|
||||
org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.json:json:20160212
|
||||
org.mockito:mockito-core:2.25.0
|
||||
|
||||
@@ -20,9 +20,9 @@ com.google.cloud:google-cloud-storage:1.59.0
|
||||
com.google.code.findbugs:jsr305:3.0.2
|
||||
com.google.code.gson:gson:2.7
|
||||
com.google.common.html.types:types:1.0.4
|
||||
com.google.errorprone:error_prone_annotations:2.3.1
|
||||
com.google.errorprone:error_prone_annotations:2.3.2
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.0-beta1
|
||||
com.google.http-client:google-http-client-appengine:1.27.0
|
||||
@@ -35,8 +35,8 @@ com.google.oauth-client:google-oauth-client:1.27.0
|
||||
com.google.protobuf:protobuf-java-util:3.6.1
|
||||
com.google.protobuf:protobuf-java:3.6.1
|
||||
com.google.template:soy:2018-03-14
|
||||
com.google.truth.extensions:truth-java8-extension:0.45
|
||||
com.google.truth:truth:0.45
|
||||
com.google.truth.extensions:truth-java8-extension:1.0
|
||||
com.google.truth:truth:1.0
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
com.ibm.icu:icu4j:57.1
|
||||
commons-codec:commons-codec:1.11
|
||||
@@ -57,8 +57,8 @@ org.apache.commons:commons-text:1.6
|
||||
org.apache.httpcomponents:httpclient:4.5.8
|
||||
org.apache.httpcomponents:httpcore:4.4.11
|
||||
org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.json:json:20160212
|
||||
org.mockito:mockito-core:2.25.0
|
||||
|
||||
+37
-11
@@ -168,6 +168,7 @@ dependencies {
|
||||
compile deps['com.google.appengine:appengine-remote-api']
|
||||
compile deps['com.google.auth:google-auth-library-credentials']
|
||||
compile deps['com.google.auth:google-auth-library-oauth2-http']
|
||||
runtimeOnly deps['com.google.cloud.sql:postgres-socket-factory']
|
||||
compile deps['com.google.code.gson:gson']
|
||||
compile deps['com.google.auto.value:auto-value-annotations']
|
||||
compile deps['com.google.code.findbugs:jsr305']
|
||||
@@ -233,6 +234,7 @@ dependencies {
|
||||
// Known issue: nebula-lint misses inherited dependency.
|
||||
compile project(':third_party')
|
||||
compile project(':util')
|
||||
testRuntime project(':db')
|
||||
|
||||
// Include auto-value in compile until nebula-lint understands
|
||||
// annotationProcessor
|
||||
@@ -556,10 +558,38 @@ artifacts {
|
||||
testRuntime testJar
|
||||
}
|
||||
|
||||
task fragileTest(type: Test) {
|
||||
/**
|
||||
* We have to break out the test suites because some of the tests conflict
|
||||
* with one another, but unfortunately this breaks the "--tests" flag. The
|
||||
* --tests flag only applies to the task named on the command line (usually
|
||||
* just "test"), not for all tasks of type "Test".
|
||||
*
|
||||
* As a better solution, FilteringTest sets testNameIncludePatterns (the
|
||||
* internal property that --tests sets) from the value of the "testFilter"
|
||||
* property, allowing us to filter across all the tests in core without
|
||||
* explicitly specifying a test task or causing errors because there are no
|
||||
* matching tests in the main task.
|
||||
*
|
||||
* To use it, define "testFilter" to be a comma-separated collection of class
|
||||
* names (wildcards are allowed):
|
||||
*
|
||||
* ./gradlew test -P testFilter=*.FooBar,google.registry.tools.ShellCommandTest
|
||||
*/
|
||||
class FilteringTest extends Test {
|
||||
|
||||
void setTests(List<String> tests) {
|
||||
// Common exclude pattern. See README in parent directory for explanation.
|
||||
exclude "**/*TestCase.*", "**/*TestSuite.*"
|
||||
include tests
|
||||
if (project.testFilter) {
|
||||
testNameIncludePatterns = project.testFilter.split(',')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task fragileTest(type: FilteringTest) {
|
||||
// Common exclude pattern. See README in parent directory for explanation.
|
||||
exclude "**/*TestCase.*", "**/*TestSuite.*"
|
||||
include fragileTestPatterns
|
||||
tests = fragileTestPatterns
|
||||
|
||||
if (rootProject.findProperty("skipDockerIncompatibleTests") == "true") {
|
||||
exclude dockerIncompatibleTestPatterns
|
||||
@@ -569,10 +599,8 @@ task fragileTest(type: Test) {
|
||||
forkEvery 1
|
||||
}
|
||||
|
||||
task outcastTest(type: Test) {
|
||||
// Common exclude pattern. See README in parent directory for explanation.
|
||||
exclude "**/*TestCase.*", "**/*TestSuite.*"
|
||||
include outcastTestPatterns
|
||||
task outcastTest(type: FilteringTest) {
|
||||
tests = outcastTestPatterns
|
||||
|
||||
// Sets the maximum number of test executors that may exist at the same time.
|
||||
maxParallelForks 5
|
||||
@@ -628,10 +656,8 @@ task registryTool(type: JavaExec) {
|
||||
}
|
||||
}
|
||||
|
||||
task generateGoldenImages(type: Test) {
|
||||
// Common exclude pattern. See README in parent directory for explanation.
|
||||
exclude "**/*TestCase.*", "**/*TestSuite.*"
|
||||
include "**/webdriver/*"
|
||||
task generateGoldenImages(type: FilteringTest) {
|
||||
tests = ["**/webdriver/*"]
|
||||
|
||||
// Sets the maximum number of test executors that may exist at the same time.
|
||||
maxParallelForks 5
|
||||
|
||||
@@ -82,7 +82,7 @@ com.google.flogger:flogger-system-backend:0.3.1
|
||||
com.google.flogger:flogger:0.3.1
|
||||
com.google.flogger:google-extensions:0.3.1
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.2
|
||||
com.google.http-client:google-http-client-appengine:1.29.2
|
||||
@@ -94,8 +94,8 @@ com.google.inject.extensions:guice-multibindings:4.1.0
|
||||
com.google.inject:guice:4.1.0
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.google.jsinterop:jsinterop-annotations:1.0.2
|
||||
com.google.monitoring-client:metrics:1.0.4
|
||||
com.google.monitoring-client:stackdriver:1.0.4
|
||||
com.google.monitoring-client:metrics:1.0.6
|
||||
com.google.monitoring-client:stackdriver:1.0.6
|
||||
com.google.oauth-client:google-oauth-client-appengine:1.29.0
|
||||
com.google.oauth-client:google-oauth-client-java6:1.28.0
|
||||
com.google.oauth-client:google-oauth-client-jetty:1.28.0
|
||||
@@ -187,10 +187,10 @@ org.apache.httpcomponents:httpclient:4.5.8
|
||||
org.apache.httpcomponents:httpcore:4.4.11
|
||||
org.bouncycastle:bcpg-jdk15on:1.61
|
||||
org.bouncycastle:bcprov-jdk15on:1.61
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.jackson:jackson-core-asl:1.9.13
|
||||
org.codehaus.jackson:jackson-mapper-asl:1.9.13
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.dom4j:dom4j:2.1.1
|
||||
org.easymock:easymock:3.0
|
||||
org.glassfish.jaxb:jaxb-runtime:2.3.1
|
||||
|
||||
@@ -81,7 +81,7 @@ com.google.errorprone:error_prone_annotations:2.3.3
|
||||
com.google.flogger:flogger:0.3.1
|
||||
com.google.flogger:google-extensions:0.3.1
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.2
|
||||
com.google.http-client:google-http-client-appengine:1.29.2
|
||||
@@ -93,8 +93,8 @@ com.google.inject.extensions:guice-multibindings:4.1.0
|
||||
com.google.inject:guice:4.1.0
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.google.jsinterop:jsinterop-annotations:1.0.2
|
||||
com.google.monitoring-client:metrics:1.0.4
|
||||
com.google.monitoring-client:stackdriver:1.0.4
|
||||
com.google.monitoring-client:metrics:1.0.6
|
||||
com.google.monitoring-client:stackdriver:1.0.6
|
||||
com.google.oauth-client:google-oauth-client-appengine:1.29.0
|
||||
com.google.oauth-client:google-oauth-client-java6:1.28.0
|
||||
com.google.oauth-client:google-oauth-client-jetty:1.28.0
|
||||
@@ -185,10 +185,10 @@ org.apache.httpcomponents:httpclient:4.5.8
|
||||
org.apache.httpcomponents:httpcore:4.4.11
|
||||
org.bouncycastle:bcpg-jdk15on:1.61
|
||||
org.bouncycastle:bcprov-jdk15on:1.61
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.jackson:jackson-core-asl:1.9.13
|
||||
org.codehaus.jackson:jackson-mapper-asl:1.9.13
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.dom4j:dom4j:2.1.1
|
||||
org.easymock:easymock:3.0
|
||||
org.glassfish.jaxb:jaxb-runtime:2.3.1
|
||||
|
||||
@@ -10,6 +10,14 @@ com.fasterxml.jackson.core:jackson-annotations:2.9.8
|
||||
com.fasterxml.jackson.core:jackson-core:2.9.9
|
||||
com.fasterxml.jackson.core:jackson-databind:2.9.8
|
||||
com.fasterxml:classmate:1.3.4
|
||||
com.github.jnr:jffi:1.2.17
|
||||
com.github.jnr:jnr-a64asm:1.0.0
|
||||
com.github.jnr:jnr-constants:0.9.11
|
||||
com.github.jnr:jnr-enxio:0.19
|
||||
com.github.jnr:jnr-ffi:2.1.9
|
||||
com.github.jnr:jnr-posix:3.0.47
|
||||
com.github.jnr:jnr-unixsocket:0.21
|
||||
com.github.jnr:jnr-x86asm:1.0.2
|
||||
com.github.luben:zstd-jni:1.3.8-3
|
||||
com.google.api-client:google-api-client-appengine:1.29.0
|
||||
com.google.api-client:google-api-client-jackson2:1.27.0
|
||||
@@ -51,6 +59,7 @@ com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
|
||||
com.google.apis:google-api-services-monitoring:v3-rev426-1.23.0
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20181105-1.27.0
|
||||
com.google.apis:google-api-services-sheets:v4-rev483-1.22.0
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev56-1.23.0
|
||||
com.google.apis:google-api-services-storage:v1-rev20181109-1.27.0
|
||||
com.google.appengine.tools:appengine-gcs-client:0.6
|
||||
com.google.appengine.tools:appengine-mapreduce:0.9
|
||||
@@ -66,6 +75,8 @@ com.google.cloud.bigdataoss:gcsio:1.9.16
|
||||
com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
@@ -82,7 +93,7 @@ com.google.flogger:flogger-system-backend:0.3.1
|
||||
com.google.flogger:flogger:0.3.1
|
||||
com.google.flogger:google-extensions:0.3.1
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.2
|
||||
com.google.http-client:google-http-client-appengine:1.29.2
|
||||
@@ -94,8 +105,8 @@ com.google.inject.extensions:guice-multibindings:4.1.0
|
||||
com.google.inject:guice:4.1.0
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.google.jsinterop:jsinterop-annotations:1.0.2
|
||||
com.google.monitoring-client:metrics:1.0.4
|
||||
com.google.monitoring-client:stackdriver:1.0.4
|
||||
com.google.monitoring-client:metrics:1.0.6
|
||||
com.google.monitoring-client:stackdriver:1.0.6
|
||||
com.google.oauth-client:google-oauth-client-appengine:1.29.0
|
||||
com.google.oauth-client:google-oauth-client-java6:1.28.0
|
||||
com.google.oauth-client:google-oauth-client-jetty:1.28.0
|
||||
@@ -187,10 +198,10 @@ org.apache.httpcomponents:httpclient:4.5.8
|
||||
org.apache.httpcomponents:httpcore:4.4.11
|
||||
org.bouncycastle:bcpg-jdk15on:1.61
|
||||
org.bouncycastle:bcprov-jdk15on:1.61
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.jackson:jackson-core-asl:1.9.13
|
||||
org.codehaus.jackson:jackson-mapper-asl:1.9.13
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.dom4j:dom4j:2.1.1
|
||||
org.easymock:easymock:3.0
|
||||
org.glassfish.jaxb:jaxb-runtime:2.3.1
|
||||
@@ -211,11 +222,11 @@ org.mockito:mockito-core:1.9.5
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
org.objenesis:objenesis:1.2
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-analysis:7.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
org.ow2.asm:asm-tree:6.0
|
||||
org.ow2.asm:asm-util:6.0
|
||||
org.ow2.asm:asm:6.0
|
||||
org.ow2.asm:asm-tree:7.0
|
||||
org.ow2.asm:asm-util:7.0
|
||||
org.ow2.asm:asm:7.0
|
||||
org.postgresql:postgresql:42.2.6
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
|
||||
@@ -82,7 +82,7 @@ com.google.flogger:flogger-system-backend:0.3.1
|
||||
com.google.flogger:flogger:0.3.1
|
||||
com.google.flogger:google-extensions:0.3.1
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.2
|
||||
com.google.http-client:google-http-client-appengine:1.29.2
|
||||
@@ -94,8 +94,8 @@ com.google.inject.extensions:guice-multibindings:4.1.0
|
||||
com.google.inject:guice:4.1.0
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.google.jsinterop:jsinterop-annotations:1.0.2
|
||||
com.google.monitoring-client:metrics:1.0.4
|
||||
com.google.monitoring-client:stackdriver:1.0.4
|
||||
com.google.monitoring-client:metrics:1.0.6
|
||||
com.google.monitoring-client:stackdriver:1.0.6
|
||||
com.google.oauth-client:google-oauth-client-appengine:1.29.0
|
||||
com.google.oauth-client:google-oauth-client-java6:1.28.0
|
||||
com.google.oauth-client:google-oauth-client-jetty:1.28.0
|
||||
@@ -187,10 +187,10 @@ org.apache.httpcomponents:httpclient:4.5.8
|
||||
org.apache.httpcomponents:httpcore:4.4.11
|
||||
org.bouncycastle:bcpg-jdk15on:1.61
|
||||
org.bouncycastle:bcprov-jdk15on:1.61
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.jackson:jackson-core-asl:1.9.13
|
||||
org.codehaus.jackson:jackson-mapper-asl:1.9.13
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.dom4j:dom4j:2.1.1
|
||||
org.easymock:easymock:3.0
|
||||
org.glassfish.jaxb:jaxb-runtime:2.3.1
|
||||
|
||||
@@ -10,6 +10,14 @@ com.fasterxml.jackson.core:jackson-annotations:2.9.8
|
||||
com.fasterxml.jackson.core:jackson-core:2.9.9
|
||||
com.fasterxml.jackson.core:jackson-databind:2.9.8
|
||||
com.fasterxml:classmate:1.3.4
|
||||
com.github.jnr:jffi:1.2.17
|
||||
com.github.jnr:jnr-a64asm:1.0.0
|
||||
com.github.jnr:jnr-constants:0.9.11
|
||||
com.github.jnr:jnr-enxio:0.19
|
||||
com.github.jnr:jnr-ffi:2.1.9
|
||||
com.github.jnr:jnr-posix:3.0.47
|
||||
com.github.jnr:jnr-unixsocket:0.21
|
||||
com.github.jnr:jnr-x86asm:1.0.2
|
||||
com.github.luben:zstd-jni:1.3.8-3
|
||||
com.google.api-client:google-api-client-appengine:1.29.0
|
||||
com.google.api-client:google-api-client-jackson2:1.27.0
|
||||
@@ -51,6 +59,7 @@ com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
|
||||
com.google.apis:google-api-services-monitoring:v3-rev426-1.23.0
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20181105-1.27.0
|
||||
com.google.apis:google-api-services-sheets:v4-rev483-1.22.0
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev56-1.23.0
|
||||
com.google.apis:google-api-services-storage:v1-rev20181109-1.27.0
|
||||
com.google.appengine.tools:appengine-gcs-client:0.6
|
||||
com.google.appengine.tools:appengine-mapreduce:0.9
|
||||
@@ -66,6 +75,8 @@ com.google.cloud.bigdataoss:gcsio:1.9.16
|
||||
com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
@@ -82,7 +93,7 @@ com.google.flogger:flogger-system-backend:0.3.1
|
||||
com.google.flogger:flogger:0.3.1
|
||||
com.google.flogger:google-extensions:0.3.1
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.2
|
||||
com.google.http-client:google-http-client-appengine:1.29.2
|
||||
@@ -94,8 +105,8 @@ com.google.inject.extensions:guice-multibindings:4.1.0
|
||||
com.google.inject:guice:4.1.0
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.google.jsinterop:jsinterop-annotations:1.0.2
|
||||
com.google.monitoring-client:metrics:1.0.4
|
||||
com.google.monitoring-client:stackdriver:1.0.4
|
||||
com.google.monitoring-client:metrics:1.0.6
|
||||
com.google.monitoring-client:stackdriver:1.0.6
|
||||
com.google.oauth-client:google-oauth-client-appengine:1.29.0
|
||||
com.google.oauth-client:google-oauth-client-java6:1.28.0
|
||||
com.google.oauth-client:google-oauth-client-jetty:1.28.0
|
||||
@@ -187,10 +198,10 @@ org.apache.httpcomponents:httpclient:4.5.8
|
||||
org.apache.httpcomponents:httpcore:4.4.11
|
||||
org.bouncycastle:bcpg-jdk15on:1.61
|
||||
org.bouncycastle:bcprov-jdk15on:1.61
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.jackson:jackson-core-asl:1.9.13
|
||||
org.codehaus.jackson:jackson-mapper-asl:1.9.13
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.dom4j:dom4j:2.1.1
|
||||
org.easymock:easymock:3.0
|
||||
org.glassfish.jaxb:jaxb-runtime:2.3.1
|
||||
@@ -211,11 +222,11 @@ org.mockito:mockito-core:1.9.5
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
org.objenesis:objenesis:1.2
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-analysis:7.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
org.ow2.asm:asm-tree:6.0
|
||||
org.ow2.asm:asm-util:6.0
|
||||
org.ow2.asm:asm:6.0
|
||||
org.ow2.asm:asm-tree:7.0
|
||||
org.ow2.asm:asm-util:7.0
|
||||
org.ow2.asm:asm:7.0
|
||||
org.postgresql:postgresql:42.2.6
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
|
||||
@@ -83,8 +83,8 @@ com.google.flogger:flogger-system-backend:0.3.1
|
||||
com.google.flogger:flogger:0.3.1
|
||||
com.google.flogger:google-extensions:0.3.1
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava-testlib:25.0-jre
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava-testlib:28.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.2
|
||||
com.google.http-client:google-http-client-appengine:1.29.2
|
||||
@@ -96,9 +96,9 @@ com.google.inject.extensions:guice-multibindings:4.1.0
|
||||
com.google.inject:guice:4.1.0
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.google.jsinterop:jsinterop-annotations:1.0.2
|
||||
com.google.monitoring-client:contrib:1.0.4
|
||||
com.google.monitoring-client:metrics:1.0.4
|
||||
com.google.monitoring-client:stackdriver:1.0.4
|
||||
com.google.monitoring-client:contrib:1.0.6
|
||||
com.google.monitoring-client:metrics:1.0.6
|
||||
com.google.monitoring-client:stackdriver:1.0.6
|
||||
com.google.oauth-client:google-oauth-client-appengine:1.29.0
|
||||
com.google.oauth-client:google-oauth-client-java6:1.28.0
|
||||
com.google.oauth-client:google-oauth-client-jetty:1.28.0
|
||||
@@ -109,8 +109,8 @@ com.google.protobuf:protobuf-java-util:3.6.1
|
||||
com.google.protobuf:protobuf-java:3.6.1
|
||||
com.google.re2j:re2j:1.1
|
||||
com.google.template:soy:2018-03-14
|
||||
com.google.truth.extensions:truth-java8-extension:0.45
|
||||
com.google.truth:truth:0.45
|
||||
com.google.truth.extensions:truth-java8-extension:1.0
|
||||
com.google.truth:truth:1.0
|
||||
com.googlecode.charts4j:charts4j:1.3
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
com.googlecode.json-simple:json-simple:1.1.1
|
||||
@@ -208,10 +208,10 @@ org.bouncycastle:bcpg-jdk15on:1.61
|
||||
org.bouncycastle:bcpkix-jdk15on:1.61
|
||||
org.bouncycastle:bcprov-jdk15on:1.61
|
||||
org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.jackson:jackson-core-asl:1.9.13
|
||||
org.codehaus.jackson:jackson-mapper-asl:1.9.13
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.dom4j:dom4j:2.1.1
|
||||
org.easymock:easymock:3.0
|
||||
org.glassfish.jaxb:jaxb-runtime:2.3.1
|
||||
|
||||
@@ -82,8 +82,8 @@ com.google.errorprone:error_prone_annotations:2.3.3
|
||||
com.google.flogger:flogger:0.3.1
|
||||
com.google.flogger:google-extensions:0.3.1
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava-testlib:25.0-jre
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava-testlib:28.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.2
|
||||
com.google.http-client:google-http-client-appengine:1.29.2
|
||||
@@ -95,9 +95,9 @@ com.google.inject.extensions:guice-multibindings:4.1.0
|
||||
com.google.inject:guice:4.1.0
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.google.jsinterop:jsinterop-annotations:1.0.2
|
||||
com.google.monitoring-client:contrib:1.0.4
|
||||
com.google.monitoring-client:metrics:1.0.4
|
||||
com.google.monitoring-client:stackdriver:1.0.4
|
||||
com.google.monitoring-client:contrib:1.0.6
|
||||
com.google.monitoring-client:metrics:1.0.6
|
||||
com.google.monitoring-client:stackdriver:1.0.6
|
||||
com.google.oauth-client:google-oauth-client-appengine:1.29.0
|
||||
com.google.oauth-client:google-oauth-client-java6:1.28.0
|
||||
com.google.oauth-client:google-oauth-client-jetty:1.28.0
|
||||
@@ -108,8 +108,8 @@ com.google.protobuf:protobuf-java-util:3.6.1
|
||||
com.google.protobuf:protobuf-java:3.6.1
|
||||
com.google.re2j:re2j:1.1
|
||||
com.google.template:soy:2018-03-14
|
||||
com.google.truth.extensions:truth-java8-extension:0.45
|
||||
com.google.truth:truth:0.45
|
||||
com.google.truth.extensions:truth-java8-extension:1.0
|
||||
com.google.truth:truth:1.0
|
||||
com.googlecode.charts4j:charts4j:1.3
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
com.googlecode.json-simple:json-simple:1.1.1
|
||||
@@ -206,10 +206,10 @@ org.bouncycastle:bcpg-jdk15on:1.61
|
||||
org.bouncycastle:bcpkix-jdk15on:1.61
|
||||
org.bouncycastle:bcprov-jdk15on:1.61
|
||||
org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.jackson:jackson-core-asl:1.9.13
|
||||
org.codehaus.jackson:jackson-mapper-asl:1.9.13
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.dom4j:dom4j:2.1.1
|
||||
org.easymock:easymock:3.0
|
||||
org.glassfish.jaxb:jaxb-runtime:2.3.1
|
||||
|
||||
@@ -10,6 +10,14 @@ com.fasterxml.jackson.core:jackson-annotations:2.9.8
|
||||
com.fasterxml.jackson.core:jackson-core:2.9.9
|
||||
com.fasterxml.jackson.core:jackson-databind:2.9.8
|
||||
com.fasterxml:classmate:1.3.4
|
||||
com.github.jnr:jffi:1.2.17
|
||||
com.github.jnr:jnr-a64asm:1.0.0
|
||||
com.github.jnr:jnr-constants:0.9.11
|
||||
com.github.jnr:jnr-enxio:0.19
|
||||
com.github.jnr:jnr-ffi:2.1.9
|
||||
com.github.jnr:jnr-posix:3.0.47
|
||||
com.github.jnr:jnr-unixsocket:0.21
|
||||
com.github.jnr:jnr-x86asm:1.0.2
|
||||
com.github.luben:zstd-jni:1.3.8-3
|
||||
com.google.api-client:google-api-client-appengine:1.29.0
|
||||
com.google.api-client:google-api-client-jackson2:1.27.0
|
||||
@@ -51,6 +59,7 @@ com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
|
||||
com.google.apis:google-api-services-monitoring:v3-rev426-1.23.0
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20181105-1.27.0
|
||||
com.google.apis:google-api-services-sheets:v4-rev483-1.22.0
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev56-1.23.0
|
||||
com.google.apis:google-api-services-storage:v1-rev20181109-1.27.0
|
||||
com.google.appengine.tools:appengine-gcs-client:0.6
|
||||
com.google.appengine.tools:appengine-mapreduce:0.9
|
||||
@@ -67,6 +76,8 @@ com.google.cloud.bigdataoss:gcsio:1.9.16
|
||||
com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
@@ -83,8 +94,8 @@ com.google.flogger:flogger-system-backend:0.3.1
|
||||
com.google.flogger:flogger:0.3.1
|
||||
com.google.flogger:google-extensions:0.3.1
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava-testlib:25.0-jre
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava-testlib:28.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.2
|
||||
com.google.http-client:google-http-client-appengine:1.29.2
|
||||
@@ -96,9 +107,9 @@ com.google.inject.extensions:guice-multibindings:4.1.0
|
||||
com.google.inject:guice:4.1.0
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.google.jsinterop:jsinterop-annotations:1.0.2
|
||||
com.google.monitoring-client:contrib:1.0.4
|
||||
com.google.monitoring-client:metrics:1.0.4
|
||||
com.google.monitoring-client:stackdriver:1.0.4
|
||||
com.google.monitoring-client:contrib:1.0.6
|
||||
com.google.monitoring-client:metrics:1.0.6
|
||||
com.google.monitoring-client:stackdriver:1.0.6
|
||||
com.google.oauth-client:google-oauth-client-appengine:1.29.0
|
||||
com.google.oauth-client:google-oauth-client-java6:1.28.0
|
||||
com.google.oauth-client:google-oauth-client-jetty:1.28.0
|
||||
@@ -109,8 +120,8 @@ com.google.protobuf:protobuf-java-util:3.6.1
|
||||
com.google.protobuf:protobuf-java:3.6.1
|
||||
com.google.re2j:re2j:1.1
|
||||
com.google.template:soy:2018-03-14
|
||||
com.google.truth.extensions:truth-java8-extension:0.45
|
||||
com.google.truth:truth:0.45
|
||||
com.google.truth.extensions:truth-java8-extension:1.0
|
||||
com.google.truth:truth:1.0
|
||||
com.googlecode.charts4j:charts4j:1.3
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
com.googlecode.json-simple:json-simple:1.1.1
|
||||
@@ -208,12 +219,13 @@ org.bouncycastle:bcpg-jdk15on:1.61
|
||||
org.bouncycastle:bcpkix-jdk15on:1.61
|
||||
org.bouncycastle:bcprov-jdk15on:1.61
|
||||
org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.jackson:jackson-core-asl:1.9.13
|
||||
org.codehaus.jackson:jackson-mapper-asl:1.9.13
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.dom4j:dom4j:2.1.1
|
||||
org.easymock:easymock:3.0
|
||||
org.flywaydb:flyway-core:5.2.4
|
||||
org.glassfish.jaxb:jaxb-runtime:2.3.1
|
||||
org.glassfish.jaxb:txw2:2.3.1
|
||||
org.hamcrest:hamcrest-all:1.3
|
||||
@@ -234,11 +246,11 @@ org.mockito:mockito-core:2.25.0
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
org.objenesis:objenesis:2.6
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-analysis:7.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
org.ow2.asm:asm-tree:6.0
|
||||
org.ow2.asm:asm-util:6.0
|
||||
org.ow2.asm:asm:6.0
|
||||
org.ow2.asm:asm-tree:7.0
|
||||
org.ow2.asm:asm-util:7.0
|
||||
org.ow2.asm:asm:7.0
|
||||
org.postgresql:postgresql:42.2.6
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
|
||||
@@ -10,6 +10,14 @@ com.fasterxml.jackson.core:jackson-annotations:2.9.8
|
||||
com.fasterxml.jackson.core:jackson-core:2.9.9
|
||||
com.fasterxml.jackson.core:jackson-databind:2.9.8
|
||||
com.fasterxml:classmate:1.3.4
|
||||
com.github.jnr:jffi:1.2.17
|
||||
com.github.jnr:jnr-a64asm:1.0.0
|
||||
com.github.jnr:jnr-constants:0.9.11
|
||||
com.github.jnr:jnr-enxio:0.19
|
||||
com.github.jnr:jnr-ffi:2.1.9
|
||||
com.github.jnr:jnr-posix:3.0.47
|
||||
com.github.jnr:jnr-unixsocket:0.21
|
||||
com.github.jnr:jnr-x86asm:1.0.2
|
||||
com.github.luben:zstd-jni:1.3.8-3
|
||||
com.google.api-client:google-api-client-appengine:1.29.0
|
||||
com.google.api-client:google-api-client-jackson2:1.27.0
|
||||
@@ -51,6 +59,7 @@ com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
|
||||
com.google.apis:google-api-services-monitoring:v3-rev426-1.23.0
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20181105-1.27.0
|
||||
com.google.apis:google-api-services-sheets:v4-rev483-1.22.0
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev56-1.23.0
|
||||
com.google.apis:google-api-services-storage:v1-rev20181109-1.27.0
|
||||
com.google.appengine.tools:appengine-gcs-client:0.6
|
||||
com.google.appengine.tools:appengine-mapreduce:0.9
|
||||
@@ -67,6 +76,8 @@ com.google.cloud.bigdataoss:gcsio:1.9.16
|
||||
com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
@@ -83,8 +94,8 @@ com.google.flogger:flogger-system-backend:0.3.1
|
||||
com.google.flogger:flogger:0.3.1
|
||||
com.google.flogger:google-extensions:0.3.1
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava-testlib:25.0-jre
|
||||
com.google.guava:guava:27.1-jre
|
||||
com.google.guava:guava-testlib:28.1-jre
|
||||
com.google.guava:guava:28.1-jre
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.gwt:gwt-user:2.8.2
|
||||
com.google.http-client:google-http-client-appengine:1.29.2
|
||||
@@ -96,9 +107,9 @@ com.google.inject.extensions:guice-multibindings:4.1.0
|
||||
com.google.inject:guice:4.1.0
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.google.jsinterop:jsinterop-annotations:1.0.2
|
||||
com.google.monitoring-client:contrib:1.0.4
|
||||
com.google.monitoring-client:metrics:1.0.4
|
||||
com.google.monitoring-client:stackdriver:1.0.4
|
||||
com.google.monitoring-client:contrib:1.0.6
|
||||
com.google.monitoring-client:metrics:1.0.6
|
||||
com.google.monitoring-client:stackdriver:1.0.6
|
||||
com.google.oauth-client:google-oauth-client-appengine:1.29.0
|
||||
com.google.oauth-client:google-oauth-client-java6:1.28.0
|
||||
com.google.oauth-client:google-oauth-client-jetty:1.28.0
|
||||
@@ -109,8 +120,8 @@ com.google.protobuf:protobuf-java-util:3.6.1
|
||||
com.google.protobuf:protobuf-java:3.6.1
|
||||
com.google.re2j:re2j:1.1
|
||||
com.google.template:soy:2018-03-14
|
||||
com.google.truth.extensions:truth-java8-extension:0.45
|
||||
com.google.truth:truth:0.45
|
||||
com.google.truth.extensions:truth-java8-extension:1.0
|
||||
com.google.truth:truth:1.0
|
||||
com.googlecode.charts4j:charts4j:1.3
|
||||
com.googlecode.java-diff-utils:diffutils:1.3.0
|
||||
com.googlecode.json-simple:json-simple:1.1.1
|
||||
@@ -208,12 +219,13 @@ org.bouncycastle:bcpg-jdk15on:1.61
|
||||
org.bouncycastle:bcpkix-jdk15on:1.61
|
||||
org.bouncycastle:bcprov-jdk15on:1.61
|
||||
org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.5.2
|
||||
org.checkerframework:checker-qual:2.8.1
|
||||
org.codehaus.jackson:jackson-core-asl:1.9.13
|
||||
org.codehaus.jackson:jackson-mapper-asl:1.9.13
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.17
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.18
|
||||
org.dom4j:dom4j:2.1.1
|
||||
org.easymock:easymock:3.0
|
||||
org.flywaydb:flyway-core:5.2.4
|
||||
org.glassfish.jaxb:jaxb-runtime:2.3.1
|
||||
org.glassfish.jaxb:txw2:2.3.1
|
||||
org.hamcrest:hamcrest-all:1.3
|
||||
@@ -234,11 +246,11 @@ org.mockito:mockito-core:2.25.0
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
org.objenesis:objenesis:2.6
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-analysis:7.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
org.ow2.asm:asm-tree:6.0
|
||||
org.ow2.asm:asm-util:6.0
|
||||
org.ow2.asm:asm:6.0
|
||||
org.ow2.asm:asm-tree:7.0
|
||||
org.ow2.asm:asm-util:7.0
|
||||
org.ow2.asm:asm:7.0
|
||||
org.postgresql:postgresql:42.2.6
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
|
||||
@@ -1296,6 +1296,18 @@ public final class RegistryConfig {
|
||||
return config.registryTool.clientSecret;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("toolsCloudSqlJdbcUrl")
|
||||
public static String providesToolsCloudSqlJdbcUrl(RegistryConfigSettings config) {
|
||||
return config.registryTool.jdbcUrl;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("toolsCloudSqlUsername")
|
||||
public static String providesToolsCloudSqlUsername(RegistryConfigSettings config) {
|
||||
return config.registryTool.username;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("rdapTos")
|
||||
public static ImmutableList<String> provideRdapTos(RegistryConfigSettings config) {
|
||||
|
||||
@@ -213,5 +213,7 @@ public class RegistryConfigSettings {
|
||||
public static class RegistryTool {
|
||||
public String clientId;
|
||||
public String clientSecret;
|
||||
public String jdbcUrl;
|
||||
public String username;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,3 +422,6 @@ registryTool:
|
||||
clientId: YOUR_CLIENT_ID
|
||||
# OAuth client secret used by the tool.
|
||||
clientSecret: YOUR_CLIENT_SECRET
|
||||
# Nomulus tool uses a different jdbc url and user to connect to Cloud SQL
|
||||
jdbcUrl: jdbc:postgresql://localhost/tool
|
||||
username: toolusername
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportDomainLists&runInEmpty]]></url>
|
||||
<description>
|
||||
This job exports lists of all active domain names to Google Cloud Storage.
|
||||
This job exports lists of all active domain names to Google Drive and Google Cloud Storage.
|
||||
</description>
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportDomainLists&runInEmpty]]></url>
|
||||
<description>
|
||||
This job exports lists of all active domain names to Google Cloud Storage.
|
||||
This job exports lists of all active domain names to Google Drive and Google Cloud Storage.
|
||||
</description>
|
||||
<schedule>every 12 hours synchronized</schedule>
|
||||
<target>backend</target>
|
||||
|
||||
@@ -56,7 +56,7 @@ import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* A mapreduce that exports the list of active domains on all real TLDs to Google Cloud Storage.
|
||||
* A mapreduce that exports the list of active domains on all real TLDs to Google Drive and GCS.
|
||||
*
|
||||
* <p>Each TLD's active domain names are exported as a newline-delimited flat text file with the
|
||||
* name TLD.txt into the domain-lists bucket. Note that this overwrites the files in place.
|
||||
|
||||
@@ -123,6 +123,7 @@ public abstract class DummyKeyringModule {
|
||||
"not a real password",
|
||||
"not a real login",
|
||||
"not a real credential",
|
||||
"not a real password",
|
||||
"not a real password");
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ public final class InMemoryKeyring implements Keyring {
|
||||
private final String marksdbSmdrlLoginAndPassword;
|
||||
private final String jsonCredential;
|
||||
private final String cloudSqlPassword;
|
||||
private final String toolsCloudSqlPassword;
|
||||
|
||||
public InMemoryKeyring(
|
||||
PGPKeyPair rdeStagingKey,
|
||||
@@ -55,7 +56,8 @@ public final class InMemoryKeyring implements Keyring {
|
||||
String marksdbLordnPassword,
|
||||
String marksdbSmdrlLoginAndPassword,
|
||||
String jsonCredential,
|
||||
String cloudSqlPassword) {
|
||||
String cloudSqlPassword,
|
||||
String toolsCloudSqlPassword) {
|
||||
checkArgument(PgpHelper.isSigningKey(rdeSigningKey.getPublicKey()),
|
||||
"RDE signing key must support signing: %s", rdeSigningKey.getKeyID());
|
||||
checkArgument(rdeStagingKey.getPublicKey().isEncryptionKey(),
|
||||
@@ -82,6 +84,7 @@ public final class InMemoryKeyring implements Keyring {
|
||||
checkNotNull(marksdbSmdrlLoginAndPassword, "marksdbSmdrlLoginAndPassword");
|
||||
this.jsonCredential = checkNotNull(jsonCredential, "jsonCredential");
|
||||
this.cloudSqlPassword = checkNotNull(cloudSqlPassword, "cloudSqlPassword");
|
||||
this.toolsCloudSqlPassword = checkNotNull(toolsCloudSqlPassword, "toolsCloudSqlPassword");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -159,6 +162,11 @@ public final class InMemoryKeyring implements Keyring {
|
||||
return cloudSqlPassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolsCloudSqlPassword() {
|
||||
return toolsCloudSqlPassword;
|
||||
}
|
||||
|
||||
/** Does nothing. */
|
||||
@Override
|
||||
public void close() {}
|
||||
|
||||
@@ -42,6 +42,12 @@ public final class KeyModule {
|
||||
return keyring.getCloudSqlPassword();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Key("toolsCloudSqlPassword")
|
||||
static String providesToolsCloudSqlPassword(Keyring keyring) {
|
||||
return keyring.getToolsCloudSqlPassword();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Key("brdaReceiverKey")
|
||||
static PGPPublicKey provideBrdaReceiverKey(Keyring keyring) {
|
||||
|
||||
@@ -28,9 +28,12 @@ import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
@ThreadSafe
|
||||
public interface Keyring extends AutoCloseable {
|
||||
|
||||
/** Returns the password which is used to connect to the Cloud SQL database. */
|
||||
/** Returns the password which is used by App Engine to connect to the Cloud SQL database. */
|
||||
String getCloudSqlPassword();
|
||||
|
||||
/** Returns the password which is used by nomulus tool to connect to the Cloud SQL database. */
|
||||
String getToolsCloudSqlPassword();
|
||||
|
||||
/**
|
||||
* Returns the key which should be used to sign RDE deposits being uploaded to a third-party.
|
||||
*
|
||||
|
||||
@@ -75,7 +75,8 @@ public class KmsKeyring implements Keyring {
|
||||
MARKSDB_LORDN_PASSWORD_STRING,
|
||||
MARKSDB_SMDRL_LOGIN_STRING,
|
||||
RDE_SSH_CLIENT_PRIVATE_STRING,
|
||||
RDE_SSH_CLIENT_PUBLIC_STRING;
|
||||
RDE_SSH_CLIENT_PUBLIC_STRING,
|
||||
TOOLS_CLOUD_SQL_PASSWORD_STRING;
|
||||
|
||||
String getLabel() {
|
||||
return UPPER_UNDERSCORE.to(LOWER_HYPHEN, name());
|
||||
@@ -94,6 +95,11 @@ public class KmsKeyring implements Keyring {
|
||||
return getString(StringKeyLabel.CLOUD_SQL_PASSWORD_STRING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolsCloudSqlPassword() {
|
||||
return getString(StringKeyLabel.TOOLS_CLOUD_SQL_PASSWORD_STRING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PGPKeyPair getRdeSigningKey() {
|
||||
return getKeyPair(PrivateKeyLabel.RDE_SIGNING_PRIVATE);
|
||||
|
||||
@@ -33,6 +33,7 @@ import static google.registry.keyring.kms.KmsKeyring.StringKeyLabel.MARKSDB_SMDR
|
||||
import static google.registry.keyring.kms.KmsKeyring.StringKeyLabel.RDE_SSH_CLIENT_PRIVATE_STRING;
|
||||
import static google.registry.keyring.kms.KmsKeyring.StringKeyLabel.RDE_SSH_CLIENT_PUBLIC_STRING;
|
||||
import static google.registry.keyring.kms.KmsKeyring.StringKeyLabel.SAFE_BROWSING_API_KEY;
|
||||
import static google.registry.keyring.kms.KmsKeyring.StringKeyLabel.TOOLS_CLOUD_SQL_PASSWORD_STRING;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
@@ -106,6 +107,10 @@ public final class KmsUpdater {
|
||||
return setString(apiKey, SAFE_BROWSING_API_KEY);
|
||||
}
|
||||
|
||||
public KmsUpdater setToolsCloudSqlPassword(String password) {
|
||||
return setString(password, TOOLS_CLOUD_SQL_PASSWORD_STRING);
|
||||
}
|
||||
|
||||
public KmsUpdater setIcannReportingPassword(String password) {
|
||||
return setString(password, ICANN_REPORTING_PASSWORD_STRING);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
package google.registry.model.ofy;
|
||||
|
||||
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
||||
import google.registry.model.transaction.TransactionManager;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.registry;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
/** Data access object for {@link google.registry.schema.domain.RegistryLock}. */
|
||||
public final class RegistryLockDao {
|
||||
|
||||
/**
|
||||
* Returns the most recent version of the {@link RegistryLock} referred to by the verification
|
||||
* code (there may be two instances of the same code in the database--one after lock object
|
||||
* creation and one after verification.
|
||||
*/
|
||||
public static RegistryLock getByVerificationCode(String verificationCode) {
|
||||
return jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
EntityManager em = jpaTm().getEntityManager();
|
||||
Long revisionId =
|
||||
em.createQuery(
|
||||
"SELECT MAX(revisionId) FROM RegistryLock WHERE verificationCode ="
|
||||
+ " :verificationCode",
|
||||
Long.class)
|
||||
.setParameter("verificationCode", verificationCode)
|
||||
.getSingleResult();
|
||||
checkNotNull(revisionId, "No registry lock with this code");
|
||||
return em.find(RegistryLock.class, revisionId);
|
||||
});
|
||||
}
|
||||
|
||||
public static void save(RegistryLock registryLock) {
|
||||
checkNotNull(registryLock, "Null registry lock cannot be saved");
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(registryLock));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.tmch;
|
||||
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.schema.tmch.ClaimsList;
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
/** Data access object for {@link ClaimsList}. */
|
||||
public class ClaimsListDao {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private static void save(ClaimsList claimsList) {
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(claimsList));
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to save the given {@link ClaimsList} into Cloud SQL. If the save fails, the error will be
|
||||
* logged but no exception will be thrown.
|
||||
*
|
||||
* <p>This method is used during the dual-write phase of database migration as Datastore is still
|
||||
* the authoritative database.
|
||||
*/
|
||||
public static void trySave(ClaimsList claimsList) {
|
||||
try {
|
||||
ClaimsListDao.save(claimsList);
|
||||
logger.atInfo().log(
|
||||
"Inserted %,d claims into Cloud SQL, created at %s",
|
||||
claimsList.getLabelsToKeys().size(), claimsList.getTmdbGenerationTime());
|
||||
} catch (Throwable e) {
|
||||
logger.atSevere().withCause(e).log("Error inserting claims into Cloud SQL");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current revision of the {@link ClaimsList} in Cloud SQL. Throws exception if there
|
||||
* is no claims in the table.
|
||||
*/
|
||||
public static ClaimsList getCurrent() {
|
||||
return jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
EntityManager em = jpaTm().getEntityManager();
|
||||
Long revisionId =
|
||||
em.createQuery("SELECT MAX(revisionId) FROM ClaimsList", Long.class)
|
||||
.getSingleResult();
|
||||
return em.createQuery(
|
||||
"FROM ClaimsList cl LEFT JOIN FETCH cl.labelsToKeys WHERE cl.revisionId ="
|
||||
+ " :revisionId",
|
||||
ClaimsList.class)
|
||||
.setParameter("revisionId", revisionId)
|
||||
.getSingleResult();
|
||||
});
|
||||
}
|
||||
|
||||
private ClaimsListDao() {}
|
||||
}
|
||||
@@ -217,8 +217,7 @@ public class ClaimsListShard extends ImmutableObject {
|
||||
});
|
||||
}
|
||||
|
||||
public static ClaimsListShard create(
|
||||
DateTime creationTime, ImmutableMap<String, String> labelsToKeys) {
|
||||
public static ClaimsListShard create(DateTime creationTime, Map<String, String> labelsToKeys) {
|
||||
ClaimsListShard instance = new ClaimsListShard();
|
||||
instance.id = allocateId();
|
||||
instance.creationTime = checkNotNull(creationTime);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.transaction;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
/**
|
||||
* A dummy implementation for {@link JpaTransactionManager} which throws exception when any of its
|
||||
* method is invoked.
|
||||
*
|
||||
* <p>This is used to initialize the {@link TransactionManagerFactory#jpaTm} when running unit
|
||||
* tests, because obviously we cannot connect to the actual Cloud SQL backend in a unit test.
|
||||
*
|
||||
* <p>If a unit test needs to access the Cloud SQL database, it must add JpaTransactionManagerRule
|
||||
* as a JUnit rule in the test class.
|
||||
*/
|
||||
public class DummyJpaTransactionManager {
|
||||
|
||||
/** Constructs a dummy {@link JpaTransactionManager} instance. */
|
||||
public static JpaTransactionManager create() {
|
||||
return (JpaTransactionManager)
|
||||
Proxy.newProxyInstance(
|
||||
JpaTransactionManager.class.getClassLoader(),
|
||||
new Class[] {JpaTransactionManager.class},
|
||||
(proxy, method, args) -> {
|
||||
throw new UnsupportedOperationException(
|
||||
"JpaTransactionManager was not initialized as the runtime is detected as"
|
||||
+ " Unittest. Add JpaTransactionManagerRule in the unit test for"
|
||||
+ " initialization.");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -14,154 +14,10 @@
|
||||
|
||||
package google.registry.model.transaction;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.persistence.PersistenceModule.AppEngineEmf;
|
||||
import google.registry.util.Clock;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.EntityTransaction;
|
||||
import javax.persistence.PersistenceException;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Implementation of {@link TransactionManager} for JPA compatible database. */
|
||||
@Singleton
|
||||
public class JpaTransactionManager implements TransactionManager {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
// EntityManagerFactory is thread safe.
|
||||
private final EntityManagerFactory emf;
|
||||
private final Clock clock;
|
||||
// TODO(shicong): Investigate alternatives for managing transaction information. ThreadLocal adds
|
||||
// an unnecessary restriction that each request has to be processed by one thread synchronously.
|
||||
private final ThreadLocal<TransactionInfo> transactionInfo =
|
||||
ThreadLocal.withInitial(TransactionInfo::new);
|
||||
|
||||
@Inject
|
||||
JpaTransactionManager(@AppEngineEmf EntityManagerFactory emf, Clock clock) {
|
||||
this.emf = emf;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
public EntityManager getEntityManager() {
|
||||
if (transactionInfo.get().entityManager == null) {
|
||||
throw new PersistenceException(
|
||||
"No EntityManager has been initialized. getEntityManager() must be invoked in the scope"
|
||||
+ " of a transaction");
|
||||
}
|
||||
return transactionInfo.get().entityManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inTransaction() {
|
||||
return transactionInfo.get().inTransaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertInTransaction() {
|
||||
if (!inTransaction()) {
|
||||
throw new PersistenceException("Not in a transaction");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T transact(Work<T> work) {
|
||||
// TODO(shicong): Investigate removing transactNew functionality after migration as it may
|
||||
// be same as this one.
|
||||
if (inTransaction()) {
|
||||
return work.run();
|
||||
}
|
||||
TransactionInfo txnInfo = transactionInfo.get();
|
||||
txnInfo.entityManager = emf.createEntityManager();
|
||||
EntityTransaction txn = txnInfo.entityManager.getTransaction();
|
||||
try {
|
||||
txn.begin();
|
||||
txnInfo.inTransaction = true;
|
||||
txnInfo.transactionTime = clock.nowUtc();
|
||||
T result = work.run();
|
||||
txn.commit();
|
||||
return result;
|
||||
} catch (Throwable transactionException) {
|
||||
String rollbackMessage;
|
||||
try {
|
||||
txn.rollback();
|
||||
rollbackMessage = "transaction rolled back";
|
||||
} catch (Throwable rollbackException) {
|
||||
logger.atSevere().withCause(rollbackException).log("Rollback failed, suppressing error");
|
||||
rollbackMessage = "transaction rollback failed";
|
||||
}
|
||||
throw new PersistenceException(
|
||||
"Error during transaction, " + rollbackMessage, transactionException);
|
||||
} finally {
|
||||
txnInfo.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transact(Runnable work) {
|
||||
transact(
|
||||
() -> {
|
||||
work.run();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T transactNew(Work<T> work) {
|
||||
// TODO(shicong): Implements the functionality to start a new transaction.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transactNew(Runnable work) {
|
||||
// TODO(shicong): Implements the functionality to start a new transaction.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T transactNewReadOnly(Work<T> work) {
|
||||
// TODO(shicong): Implements read only transaction.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transactNewReadOnly(Runnable work) {
|
||||
// TODO(shicong): Implements read only transaction.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T doTransactionless(Work<T> work) {
|
||||
// TODO(shicong): Implements doTransactionless.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime getTransactionTime() {
|
||||
assertInTransaction();
|
||||
TransactionInfo txnInfo = transactionInfo.get();
|
||||
if (txnInfo.transactionTime == null) {
|
||||
throw new PersistenceException("In a transaction but transactionTime is null");
|
||||
}
|
||||
return txnInfo.transactionTime;
|
||||
}
|
||||
|
||||
private static class TransactionInfo {
|
||||
EntityManager entityManager;
|
||||
boolean inTransaction = false;
|
||||
DateTime transactionTime;
|
||||
|
||||
private void clear() {
|
||||
inTransaction = false;
|
||||
transactionTime = null;
|
||||
if (entityManager != null) {
|
||||
// Close this EntityManager just let the connection pool be able to reuse it, it doesn't
|
||||
// close the underlying database connection.
|
||||
entityManager.close();
|
||||
entityManager = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Sub-interface of {@link TransactionManager} which defines JPA related methods. */
|
||||
public interface JpaTransactionManager extends TransactionManager {
|
||||
/** Returns the {@link EntityManager} for the current request. */
|
||||
EntityManager getEntityManager();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.transaction;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.util.Clock;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.EntityTransaction;
|
||||
import javax.persistence.PersistenceException;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Implementation of {@link JpaTransactionManager} for JPA compatible database. */
|
||||
public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
// EntityManagerFactory is thread safe.
|
||||
private final EntityManagerFactory emf;
|
||||
private final Clock clock;
|
||||
// TODO(shicong): Investigate alternatives for managing transaction information. ThreadLocal adds
|
||||
// an unnecessary restriction that each request has to be processed by one thread synchronously.
|
||||
private final ThreadLocal<TransactionInfo> transactionInfo =
|
||||
ThreadLocal.withInitial(TransactionInfo::new);
|
||||
|
||||
public JpaTransactionManagerImpl(EntityManagerFactory emf, Clock clock) {
|
||||
this.emf = emf;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityManager getEntityManager() {
|
||||
if (transactionInfo.get().entityManager == null) {
|
||||
throw new PersistenceException(
|
||||
"No EntityManager has been initialized. getEntityManager() must be invoked in the scope"
|
||||
+ " of a transaction");
|
||||
}
|
||||
return transactionInfo.get().entityManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inTransaction() {
|
||||
return transactionInfo.get().inTransaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertInTransaction() {
|
||||
if (!inTransaction()) {
|
||||
throw new PersistenceException("Not in a transaction");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T transact(Work<T> work) {
|
||||
// TODO(shicong): Investigate removing transactNew functionality after migration as it may
|
||||
// be same as this one.
|
||||
if (inTransaction()) {
|
||||
return work.run();
|
||||
}
|
||||
TransactionInfo txnInfo = transactionInfo.get();
|
||||
txnInfo.entityManager = emf.createEntityManager();
|
||||
EntityTransaction txn = txnInfo.entityManager.getTransaction();
|
||||
try {
|
||||
txn.begin();
|
||||
txnInfo.inTransaction = true;
|
||||
txnInfo.transactionTime = clock.nowUtc();
|
||||
T result = work.run();
|
||||
txn.commit();
|
||||
return result;
|
||||
} catch (Throwable transactionException) {
|
||||
String rollbackMessage;
|
||||
try {
|
||||
txn.rollback();
|
||||
rollbackMessage = "transaction rolled back";
|
||||
} catch (Throwable rollbackException) {
|
||||
logger.atSevere().withCause(rollbackException).log("Rollback failed, suppressing error");
|
||||
rollbackMessage = "transaction rollback failed";
|
||||
}
|
||||
throw new PersistenceException(
|
||||
"Error during transaction, " + rollbackMessage, transactionException);
|
||||
} finally {
|
||||
txnInfo.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transact(Runnable work) {
|
||||
transact(
|
||||
() -> {
|
||||
work.run();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T transactNew(Work<T> work) {
|
||||
// TODO(shicong): Implements the functionality to start a new transaction.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transactNew(Runnable work) {
|
||||
// TODO(shicong): Implements the functionality to start a new transaction.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T transactNewReadOnly(Work<T> work) {
|
||||
// TODO(shicong): Implements read only transaction.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transactNewReadOnly(Runnable work) {
|
||||
// TODO(shicong): Implements read only transaction.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T doTransactionless(Work<T> work) {
|
||||
// TODO(shicong): Implements doTransactionless.
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime getTransactionTime() {
|
||||
assertInTransaction();
|
||||
TransactionInfo txnInfo = transactionInfo.get();
|
||||
if (txnInfo.transactionTime == null) {
|
||||
throw new PersistenceException("In a transaction but transactionTime is null");
|
||||
}
|
||||
return txnInfo.transactionTime;
|
||||
}
|
||||
|
||||
private static class TransactionInfo {
|
||||
EntityManager entityManager;
|
||||
boolean inTransaction = false;
|
||||
DateTime transactionTime;
|
||||
|
||||
private void clear() {
|
||||
inTransaction = false;
|
||||
transactionTime = null;
|
||||
if (entityManager != null) {
|
||||
// Close this EntityManager just let the connection pool be able to reuse it, it doesn't
|
||||
// close the underlying database connection.
|
||||
entityManager.close();
|
||||
entityManager = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
-10
@@ -16,19 +16,32 @@ package google.registry.model.transaction;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import google.registry.model.ofy.DatastoreTransactionManager;
|
||||
import google.registry.persistence.DaggerPersistenceComponent;
|
||||
import google.registry.persistence.PersistenceComponent;
|
||||
|
||||
/** Factory class to create {@link TransactionManager} instance. */
|
||||
// TODO: Rename this to PersistenceFactory and move to persistence package.
|
||||
public class TransactionManagerFactory {
|
||||
|
||||
private static final TransactionManager TM = createTransactionManager();
|
||||
|
||||
@VisibleForTesting static PersistenceComponent component = DaggerPersistenceComponent.create();
|
||||
@VisibleForTesting static JpaTransactionManager jpaTm = createJpaTransactionManager();
|
||||
|
||||
private TransactionManagerFactory() {}
|
||||
|
||||
private static JpaTransactionManager createJpaTransactionManager() {
|
||||
// TODO(shicong): There is currently no environment where we want to create a real JPA
|
||||
// transaction manager here. The unit tests that require one are all set up using
|
||||
// JpaTransactionManagerRule which launches its own PostgreSQL instance. When we actually have
|
||||
// PostgreSQL tables in production, ensure that all of the test environments are set up
|
||||
// correctly and restore the code that creates a JpaTransactionManager when
|
||||
// RegistryEnvironment.get() != UNITTEST.
|
||||
//
|
||||
// We removed the original code because it didn't work in sandbox (due to the absence of the
|
||||
// persistence.xml file, which has since been added), and then (after adding this) didn't work
|
||||
// in crash because the postgresql password hadn't been set up. Prior to restoring, we'll need
|
||||
// to do setup in all environments, and we probably only want to do this once we're actually
|
||||
// using Cloud SQL for one of the new tables.
|
||||
return DummyJpaTransactionManager.create();
|
||||
}
|
||||
|
||||
private static TransactionManager createTransactionManager() {
|
||||
// TODO: Determine how to provision TransactionManager after the dual-write. During the
|
||||
// dual-write transitional phase, we need the TransactionManager for both Datastore and Cloud
|
||||
@@ -36,6 +49,15 @@ public class TransactionManagerFactory {
|
||||
return new DatastoreTransactionManager(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets jpaTm to the implementation for Nomulus tool. Note that this method should be only used by
|
||||
* {@link google.registry.tools.RegistryCli} to initialize jpaTm.
|
||||
*/
|
||||
public static void initForTool() {
|
||||
// TODO(shicong): Uncomment the line below when we set up Cloud SQL instance in all environments
|
||||
// jpaTm = DaggerPersistenceComponent.create().nomulusToolJpaTransactionManager();
|
||||
}
|
||||
|
||||
/** Returns {@link TransactionManager} instance. */
|
||||
public static TransactionManager tm() {
|
||||
return TM;
|
||||
@@ -43,11 +65,6 @@ public class TransactionManagerFactory {
|
||||
|
||||
/** Returns {@link JpaTransactionManager} instance. */
|
||||
public static JpaTransactionManager jpaTm() {
|
||||
// TODO: Returns corresponding TransactionManager based on the runtime environment.
|
||||
// We have 3 kinds of runtime environment:
|
||||
// 1. App Engine
|
||||
// 2. Local JVM used by nomulus tool
|
||||
// 3. Unit test
|
||||
return component.jpaTransactionManager();
|
||||
return jpaTm;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.base.Charsets.US_ASCII;
|
||||
import static com.google.common.hash.Funnels.stringFunnel;
|
||||
|
||||
import com.google.common.hash.BloomFilter;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
/** JPA converter for ASCII String {@link BloomFilter}s. */
|
||||
@Converter(autoApply = true)
|
||||
public class BloomFilterConverter implements AttributeConverter<BloomFilter<String>, byte[]> {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public byte[] convertToDatabaseColumn(@Nullable BloomFilter<String> entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
try {
|
||||
entity.writeTo(bos);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Error saving Bloom filter data", e);
|
||||
}
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BloomFilter<String> convertToEntityAttribute(@Nullable byte[] columnValue) {
|
||||
if (columnValue == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return BloomFilter.readFrom(new ByteArrayInputStream(columnValue), stringFunnel(US_ASCII));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Error loading Bloom filter data", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import google.registry.model.CreateAutoTimestamp;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** JPA converter to for storing/retrieving CreateAutoTimestamp objects. */
|
||||
@Converter(autoApply = true)
|
||||
public class CreateAutoTimestampConverter
|
||||
implements AttributeConverter<CreateAutoTimestamp, Timestamp> {
|
||||
|
||||
@Override
|
||||
public Timestamp convertToDatabaseColumn(CreateAutoTimestamp entity) {
|
||||
DateTime dateTime = firstNonNull(entity.getTimestamp(), jpaTm().getTransactionTime());
|
||||
return Timestamp.from(DateTimeUtils.toZonedDateTime(dateTime).toInstant());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public CreateAutoTimestamp convertToEntityAttribute(@Nullable Timestamp columnValue) {
|
||||
if (columnValue == null) {
|
||||
return null;
|
||||
}
|
||||
ZonedDateTime zdt = ZonedDateTime.ofInstant(columnValue.toInstant(), ZoneOffset.UTC);
|
||||
return CreateAutoTimestamp.create(DateTimeUtils.toJodaDateTime(zdt));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package google.registry.persistence;
|
||||
|
||||
import java.sql.Types;
|
||||
import org.hibernate.dialect.PostgreSQL95Dialect;
|
||||
|
||||
/** Nomulus mapping rules for column types in Postgresql. */
|
||||
public class NomulusPostgreSQLDialect extends PostgreSQL95Dialect {
|
||||
public NomulusPostgreSQLDialect() {
|
||||
super();
|
||||
registerColumnType(Types.VARCHAR, "text");
|
||||
registerColumnType(Types.TIMESTAMP_WITH_TIMEZONE, "timestamptz");
|
||||
registerColumnType(Types.TIMESTAMP, "timestamptz");
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ import google.registry.config.CredentialModule;
|
||||
import google.registry.config.RegistryConfig.ConfigModule;
|
||||
import google.registry.keyring.kms.KmsModule;
|
||||
import google.registry.model.transaction.JpaTransactionManager;
|
||||
import google.registry.persistence.PersistenceModule.AppEngineJpaTm;
|
||||
import google.registry.persistence.PersistenceModule.NomulusToolJpaTm;
|
||||
import google.registry.util.UtilsModule;
|
||||
import javax.inject.Singleton;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
@@ -34,5 +36,10 @@ import javax.persistence.EntityManagerFactory;
|
||||
UtilsModule.class
|
||||
})
|
||||
public interface PersistenceComponent {
|
||||
JpaTransactionManager jpaTransactionManager();
|
||||
|
||||
@AppEngineJpaTm
|
||||
JpaTransactionManager appEngineJpaTransactionManager();
|
||||
|
||||
@NomulusToolJpaTm
|
||||
JpaTransactionManager nomulusToolJpaTransactionManager();
|
||||
}
|
||||
|
||||
@@ -29,11 +29,14 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.keyring.kms.KmsKeyring;
|
||||
import google.registry.model.transaction.JpaTransactionManager;
|
||||
import google.registry.model.transaction.JpaTransactionManagerImpl;
|
||||
import google.registry.util.Clock;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.inject.Qualifier;
|
||||
import javax.inject.Singleton;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Persistence;
|
||||
import org.hibernate.cfg.Environment;
|
||||
@@ -61,6 +64,8 @@ public class PersistenceModule {
|
||||
// SessionFactory is created. Setting it to 'none' to turn off the feature.
|
||||
properties.put(Environment.HBM2DDL_AUTO, "none");
|
||||
|
||||
// Hibernate converts any date to this timezone when writing to the database.
|
||||
properties.put(Environment.JDBC_TIME_ZONE, "UTC");
|
||||
properties.put(
|
||||
Environment.PHYSICAL_NAMING_STRATEGY, NomulusNamingStrategy.class.getCanonicalName());
|
||||
|
||||
@@ -70,28 +75,60 @@ public class PersistenceModule {
|
||||
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();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@AppEngineEmf
|
||||
public static EntityManagerFactory providesAppEngineEntityManagerFactory(
|
||||
@Singleton
|
||||
@AppEngineJpaTm
|
||||
public static JpaTransactionManager providesAppEngineJpaTm(
|
||||
@Config("cloudSqlJdbcUrl") String jdbcUrl,
|
||||
@Config("cloudSqlUsername") String username,
|
||||
@Config("cloudSqlInstanceConnectionName") String instanceConnectionName,
|
||||
KmsKeyring kmsKeyring,
|
||||
@DefaultHibernateConfigs ImmutableMap<String, String> defaultConfigs) {
|
||||
String password = kmsKeyring.getCloudSqlPassword();
|
||||
|
||||
@DefaultHibernateConfigs ImmutableMap<String, String> defaultConfigs,
|
||||
Clock clock) {
|
||||
HashMap<String, String> overrides = Maps.newHashMap(defaultConfigs);
|
||||
|
||||
// For Java users, the Cloud SQL JDBC Socket Factory can provide authenticated connections.
|
||||
// See https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory for details.
|
||||
overrides.put("socketFactory", "com.google.cloud.sql.postgres.SocketFactory");
|
||||
overrides.put("cloudSqlInstance", instanceConnectionName);
|
||||
|
||||
EntityManagerFactory emf = create(jdbcUrl, username, password, ImmutableMap.copyOf(overrides));
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(emf::close));
|
||||
return emf;
|
||||
overrides.put(Environment.URL, jdbcUrl);
|
||||
overrides.put(Environment.USER, username);
|
||||
overrides.put(Environment.PASS, kmsKeyring.getCloudSqlPassword());
|
||||
|
||||
return new JpaTransactionManagerImpl(create(overrides), clock);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@NomulusToolJpaTm
|
||||
public static JpaTransactionManager providesNomulusToolJpaTm(
|
||||
@Config("toolsCloudSqlJdbcUrl") String jdbcUrl,
|
||||
@Config("toolsCloudSqlUsername") String username,
|
||||
@Config("cloudSqlInstanceConnectionName") String instanceConnectionName,
|
||||
KmsKeyring kmsKeyring,
|
||||
@DefaultHibernateConfigs ImmutableMap<String, String> defaultConfigs,
|
||||
Clock clock) {
|
||||
|
||||
// Cloud SQL JDBC Socket Factory library requires the jdbc url to include all connection
|
||||
// information, otherwise the connection initialization will fail. See here for more details:
|
||||
// https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory
|
||||
String fullJdbcUrl =
|
||||
new StringBuilder(jdbcUrl)
|
||||
.append("?cloudSqlInstance=" + instanceConnectionName)
|
||||
.append("&socketFactory=com.google.cloud.sql.postgres.SocketFactory")
|
||||
.append("&user=" + username)
|
||||
.append("&password=" + kmsKeyring.getCloudSqlPassword())
|
||||
.toString();
|
||||
|
||||
HashMap<String, String> overrides = Maps.newHashMap(defaultConfigs);
|
||||
overrides.put(Environment.URL, fullJdbcUrl);
|
||||
|
||||
return new JpaTransactionManagerImpl(create(overrides), clock);
|
||||
}
|
||||
|
||||
/** Constructs the {@link EntityManagerFactory} instance. */
|
||||
@@ -102,25 +139,37 @@ public class PersistenceModule {
|
||||
properties.put(Environment.URL, jdbcUrl);
|
||||
properties.put(Environment.USER, username);
|
||||
properties.put(Environment.PASS, password);
|
||||
|
||||
return create(ImmutableMap.copyOf(properties));
|
||||
}
|
||||
|
||||
private static EntityManagerFactory create(Map<String, String> properties) {
|
||||
// If there are no annotated classes, we can create the EntityManagerFactory from the generic
|
||||
// method. Otherwise we have to use a more tailored approach. Note that this adds to the set
|
||||
// of annotated classes defined in the configuration, it does not override them.
|
||||
EntityManagerFactory emf =
|
||||
Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME, properties);
|
||||
Persistence.createEntityManagerFactory(
|
||||
PERSISTENCE_UNIT_NAME, ImmutableMap.copyOf(properties));
|
||||
checkState(
|
||||
emf != null,
|
||||
"Persistence.createEntityManagerFactory() returns a null EntityManagerFactory");
|
||||
return emf;
|
||||
}
|
||||
|
||||
/** Dagger qualifier for the {@link EntityManagerFactory} used for App Engine application. */
|
||||
/** Dagger qualifier for {@link JpaTransactionManager} used for App Engine application. */
|
||||
@Qualifier
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AppEngineEmf {}
|
||||
@interface AppEngineJpaTm {}
|
||||
|
||||
/** Dagger qualifier for {@link JpaTransactionManager} used for Nomulus tool. */
|
||||
@Qualifier
|
||||
@Documented
|
||||
@interface NomulusToolJpaTm {}
|
||||
|
||||
/** Dagger qualifier for the default Hibernate configurations. */
|
||||
// TODO(shicong): Change annotations in this class to none public or put them in a top level
|
||||
// package
|
||||
@Qualifier
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DefaultHibernateConfigs {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package google.registry.persistence;
|
||||
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import google.registry.model.UpdateAutoTimestamp;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
/** JPA converter for storing/retrieving UpdateAutoTimestamp objects. */
|
||||
@Converter(autoApply = true)
|
||||
public class UpdateAutoTimestampConverter
|
||||
implements AttributeConverter<UpdateAutoTimestamp, Timestamp> {
|
||||
|
||||
@Override
|
||||
public Timestamp convertToDatabaseColumn(UpdateAutoTimestamp entity) {
|
||||
return Timestamp.from(DateTimeUtils.toZonedDateTime(jpaTm().getTransactionTime()).toInstant());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public UpdateAutoTimestamp convertToEntityAttribute(@Nullable Timestamp columnValue) {
|
||||
if (columnValue == null) {
|
||||
return null;
|
||||
}
|
||||
ZonedDateTime zdt = ZonedDateTime.ofInstant(columnValue.toInstant(), ZoneOffset.UTC);
|
||||
return UpdateAutoTimestamp.create(DateTimeUtils.toJodaDateTime(zdt));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
/**
|
||||
* JPA converter to for storing/retrieving {@link ZonedDateTime} objects.
|
||||
*
|
||||
* <p>Hibernate provides a default converter for {@link ZonedDateTime}, but it converts timestamp to
|
||||
* a non-normalized format, e.g., 2019-09-01T01:01:01Z will be converted to
|
||||
* 2019-09-01T01:01:01Z[UTC]. This converter solves that problem by explicitly calling {@link
|
||||
* ZoneId#normalized()} to normalize the zone id.
|
||||
*/
|
||||
@Converter(autoApply = true)
|
||||
public class ZonedDateTimeConverter implements AttributeConverter<ZonedDateTime, Timestamp> {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Timestamp convertToDatabaseColumn(@Nullable ZonedDateTime attribute) {
|
||||
return attribute == null ? null : Timestamp.from(attribute.toInstant());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ZonedDateTime convertToEntityAttribute(@Nullable Timestamp dbData) {
|
||||
return dbData == null
|
||||
? null
|
||||
: ZonedDateTime.ofInstant(dbData.toInstant(), ZoneId.of("UTC").normalized());
|
||||
}
|
||||
}
|
||||
@@ -15,13 +15,15 @@
|
||||
package google.registry.schema.domain;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.util.DateTimeUtils.toJodaDateTime;
|
||||
import static google.registry.util.DateTimeUtils.toZonedDateTime;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.CreateAutoTimestamp;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Optional;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
@@ -54,14 +56,17 @@ import org.joda.time.DateTime;
|
||||
* Unique constraint to get around Hibernate's failure to handle auto-increment field in
|
||||
* composite primary key.
|
||||
*
|
||||
* <p>Note: because of this index, physical columns must be declared in the {@link Column}
|
||||
* annotations for {@link RegistryLock#revisionId} and {@link RegistryLock#repoId} fields.
|
||||
* <p>Note: indexes use the camelCase version of the field names because the {@link
|
||||
* google.registry.persistence.NomulusNamingStrategy} does not translate the field name into the
|
||||
* snake_case column name until the write itself.
|
||||
*/
|
||||
indexes =
|
||||
@Index(
|
||||
name = "idx_registry_lock_repo_id_revision_id",
|
||||
columnList = "repo_id, revision_id",
|
||||
unique = true))
|
||||
indexes = {
|
||||
@Index(
|
||||
name = "idx_registry_lock_repo_id_revision_id",
|
||||
columnList = "repoId, revisionId",
|
||||
unique = true),
|
||||
@Index(name = "idx_registry_lock_verification_code", columnList = "verificationCode")
|
||||
})
|
||||
public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||
|
||||
/** Describes the action taken by the user. */
|
||||
@@ -72,11 +77,11 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "revision_id", nullable = false)
|
||||
@Column(nullable = false)
|
||||
private Long revisionId;
|
||||
|
||||
/** EPP repo ID of the domain in question. */
|
||||
@Column(name = "repo_id", nullable = false)
|
||||
@Column(nullable = false)
|
||||
private String repoId;
|
||||
|
||||
// TODO (b/140568328): remove this when everything is in Cloud SQL and we can join on "domain"
|
||||
@@ -102,7 +107,7 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||
|
||||
/** Creation timestamp is when the lock/unlock is first requested. */
|
||||
@Column(nullable = false)
|
||||
private ZonedDateTime creationTimestamp;
|
||||
private CreateAutoTimestamp creationTimestamp = CreateAutoTimestamp.create(null);
|
||||
|
||||
/**
|
||||
* Completion timestamp is when the user has verified the lock/unlock, when this object de facto
|
||||
@@ -146,11 +151,12 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||
}
|
||||
|
||||
public DateTime getCreationTimestamp() {
|
||||
return toJodaDateTime(creationTimestamp);
|
||||
return creationTimestamp.getTimestamp();
|
||||
}
|
||||
|
||||
public DateTime getCompletionTimestamp() {
|
||||
return toJodaDateTime(completionTimestamp);
|
||||
/** Returns the completion timestamp, or empty if this lock has not been completed yet. */
|
||||
public Optional<DateTime> getCompletionTimestamp() {
|
||||
return Optional.ofNullable(completionTimestamp).map(DateTimeUtils::toJodaDateTime);
|
||||
}
|
||||
|
||||
public String getVerificationCode() {
|
||||
@@ -165,9 +171,16 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||
return revisionId;
|
||||
}
|
||||
|
||||
public void setCompletionTimestamp(DateTime dateTime) {
|
||||
this.completionTimestamp = toZonedDateTime(dateTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder asBuilder() {
|
||||
return new Builder(clone(this));
|
||||
RegistryLock clone = clone(this);
|
||||
// Revision ID should be different for every object
|
||||
clone.revisionId = null;
|
||||
return new Builder(clone);
|
||||
}
|
||||
|
||||
/** Builder for {@link google.registry.schema.domain.RegistryLock}. */
|
||||
@@ -184,7 +197,6 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||
checkArgumentNotNull(getInstance().domainName, "Domain name cannot be null");
|
||||
checkArgumentNotNull(getInstance().registrarId, "Registrar ID cannot be null");
|
||||
checkArgumentNotNull(getInstance().action, "Action cannot be null");
|
||||
checkArgumentNotNull(getInstance().creationTimestamp, "Creation timestamp cannot be null");
|
||||
checkArgumentNotNull(getInstance().verificationCode, "Verification codecannot be null");
|
||||
checkArgument(
|
||||
getInstance().registrarPocId != null || getInstance().isSuperuser,
|
||||
@@ -217,8 +229,8 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCreationTimestamp(DateTime creationTimestamp) {
|
||||
getInstance().creationTimestamp = toZonedDateTime(creationTimestamp);
|
||||
public Builder setCreationTimestamp(CreateAutoTimestamp creationTimestamp) {
|
||||
getInstance().creationTimestamp = creationTimestamp;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,14 @@
|
||||
|
||||
package google.registry.schema.tld;
|
||||
|
||||
import static com.google.common.base.Charsets.US_ASCII;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.hash.Funnels.stringFunnel;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.hash.BloomFilter;
|
||||
import google.registry.model.CreateAutoTimestamp;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Map;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
@@ -26,10 +30,12 @@ import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.MapKeyColumn;
|
||||
import javax.persistence.Table;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* A list of premium prices for domain names.
|
||||
@@ -40,47 +46,55 @@ import org.joda.money.CurrencyUnit;
|
||||
* This is fine though, because we only use the list with the highest revisionId.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "PremiumList")
|
||||
@Table(indexes = {@Index(columnList = "name", name = "premiumlist_name_idx")})
|
||||
public class PremiumList {
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "revision_id")
|
||||
@Column(nullable = false)
|
||||
private Long revisionId;
|
||||
|
||||
@Column(name = "creation_timestamp", nullable = false)
|
||||
private ZonedDateTime creationTimestamp;
|
||||
@Column(nullable = false)
|
||||
private CreateAutoTimestamp creationTimestamp = CreateAutoTimestamp.create(null);
|
||||
|
||||
@Column(name = "currency", nullable = false)
|
||||
@Column(nullable = false)
|
||||
private CurrencyUnit currency;
|
||||
|
||||
@ElementCollection
|
||||
@CollectionTable(
|
||||
name = "PremiumEntry",
|
||||
joinColumns = @JoinColumn(name = "revision_id", referencedColumnName = "revision_id"))
|
||||
@MapKeyColumn(name = "domain_label")
|
||||
joinColumns = @JoinColumn(name = "revisionId", referencedColumnName = "revisionId"))
|
||||
@MapKeyColumn(name = "domainLabel")
|
||||
@Column(name = "price", nullable = false)
|
||||
private Map<String, BigDecimal> labelsToPrices;
|
||||
|
||||
private PremiumList(
|
||||
ZonedDateTime creationTimestamp,
|
||||
CurrencyUnit currency,
|
||||
Map<String, BigDecimal> labelsToPrices) {
|
||||
this.creationTimestamp = creationTimestamp;
|
||||
@Column(nullable = false)
|
||||
private BloomFilter<String> bloomFilter;
|
||||
|
||||
private PremiumList(String name, CurrencyUnit currency, Map<String, BigDecimal> labelsToPrices) {
|
||||
this.name = name;
|
||||
this.currency = currency;
|
||||
this.labelsToPrices = labelsToPrices;
|
||||
// ASCII is used for the charset because all premium list domain labels are stored punycoded.
|
||||
this.bloomFilter = BloomFilter.create(stringFunnel(US_ASCII), labelsToPrices.size());
|
||||
labelsToPrices.keySet().forEach(this.bloomFilter::put);
|
||||
}
|
||||
|
||||
// Hibernate requires this default constructor.
|
||||
private PremiumList() {}
|
||||
|
||||
// TODO(mcilwain): Change creationTimestamp to Joda DateTime.
|
||||
/** Constructs a {@link PremiumList} object. */
|
||||
public static PremiumList create(
|
||||
ZonedDateTime creationTimestamp,
|
||||
CurrencyUnit currency,
|
||||
Map<String, BigDecimal> labelsToPrices) {
|
||||
return new PremiumList(creationTimestamp, currency, labelsToPrices);
|
||||
String name, CurrencyUnit currency, Map<String, BigDecimal> labelsToPrices) {
|
||||
return new PremiumList(name, currency, labelsToPrices);
|
||||
}
|
||||
|
||||
/** Returns the name of the premium list, which is usually also a TLD string. */
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/** Returns the ID of this revision, or throws if null. */
|
||||
@@ -91,12 +105,23 @@ public class PremiumList {
|
||||
}
|
||||
|
||||
/** Returns the creation time of this revision of the premium list. */
|
||||
public ZonedDateTime getCreationTimestamp() {
|
||||
return creationTimestamp;
|
||||
public DateTime getCreationTimestamp() {
|
||||
return creationTimestamp.getTimestamp();
|
||||
}
|
||||
|
||||
/** Returns a {@link Map} of domain labels to prices. */
|
||||
public Map<String, BigDecimal> getLabelsToPrices() {
|
||||
return labelsToPrices;
|
||||
public ImmutableMap<String, BigDecimal> getLabelsToPrices() {
|
||||
return ImmutableMap.copyOf(labelsToPrices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Bloom filter to determine whether a label might be premium, or is definitely not.
|
||||
*
|
||||
* <p>If the domain label might be premium, then the next step is to check for the existence of a
|
||||
* corresponding row in the PremiumListEntry table. Otherwise, we know for sure it's not premium,
|
||||
* and no DB load is required.
|
||||
*/
|
||||
public BloomFilter<String> getBloomFilter() {
|
||||
return bloomFilter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.schema.tld;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
/** Data access object class for {@link PremiumList}. */
|
||||
public class PremiumListDao {
|
||||
|
||||
/** Persist a new premium list to Cloud SQL. */
|
||||
public static void saveNew(PremiumList premiumList) {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
checkArgument(
|
||||
!checkExists(premiumList.getName()),
|
||||
"A premium list of this name already exists: %s.",
|
||||
premiumList.getName());
|
||||
jpaTm().getEntityManager().persist(premiumList);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the premium list of the given name exists.
|
||||
*
|
||||
* <p>This means that at least one premium list revision must exist for the given name.
|
||||
*/
|
||||
public static boolean checkExists(String premiumListName) {
|
||||
return jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery("SELECT 1 FROM PremiumList WHERE name = :name", Integer.class)
|
||||
.setParameter("name", premiumListName)
|
||||
.setMaxResults(1)
|
||||
.getResultList()
|
||||
.size()
|
||||
> 0);
|
||||
}
|
||||
|
||||
private PremiumListDao() {}
|
||||
}
|
||||
@@ -15,7 +15,11 @@
|
||||
package google.registry.schema.tmch;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static google.registry.util.DateTimeUtils.toJodaDateTime;
|
||||
import static google.registry.util.DateTimeUtils.toZonedDateTime;
|
||||
|
||||
import google.registry.model.CreateAutoTimestamp;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -29,6 +33,7 @@ import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.MapKeyColumn;
|
||||
import javax.persistence.Table;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* A list of TMCH claims labels and their associated claims keys.
|
||||
@@ -40,26 +45,29 @@ import javax.persistence.Table;
|
||||
* highest {@link #revisionId}.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "ClaimsList")
|
||||
public class ClaimsList {
|
||||
@Table
|
||||
public class ClaimsList extends ImmutableObject {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "revision_id")
|
||||
@Column
|
||||
private Long revisionId;
|
||||
|
||||
@Column(name = "creation_timestamp", nullable = false)
|
||||
private ZonedDateTime creationTimestamp;
|
||||
@Column(nullable = false)
|
||||
private CreateAutoTimestamp creationTimestamp = CreateAutoTimestamp.create(null);
|
||||
|
||||
@Column(nullable = false)
|
||||
private ZonedDateTime tmdbGenerationTime;
|
||||
|
||||
@ElementCollection
|
||||
@CollectionTable(
|
||||
name = "ClaimsEntry",
|
||||
joinColumns = @JoinColumn(name = "revision_id", referencedColumnName = "revision_id"))
|
||||
@MapKeyColumn(name = "domain_label", nullable = false)
|
||||
@Column(name = "claim_key", nullable = false)
|
||||
joinColumns = @JoinColumn(name = "revisionId", referencedColumnName = "revisionId"))
|
||||
@MapKeyColumn(name = "domainLabel", nullable = false)
|
||||
@Column(name = "claimKey", nullable = false)
|
||||
private Map<String, String> labelsToKeys;
|
||||
|
||||
private ClaimsList(ZonedDateTime creationTimestamp, Map<String, String> labelsToKeys) {
|
||||
this.creationTimestamp = creationTimestamp;
|
||||
private ClaimsList(ZonedDateTime tmdbGenerationTime, Map<String, String> labelsToKeys) {
|
||||
this.tmdbGenerationTime = tmdbGenerationTime;
|
||||
this.labelsToKeys = labelsToKeys;
|
||||
}
|
||||
|
||||
@@ -67,9 +75,8 @@ public class ClaimsList {
|
||||
private ClaimsList() {}
|
||||
|
||||
/** Constructs a {@link ClaimsList} object. */
|
||||
public static ClaimsList create(
|
||||
ZonedDateTime creationTimestamp, Map<String, String> labelsToKeys) {
|
||||
return new ClaimsList(creationTimestamp, labelsToKeys);
|
||||
public static ClaimsList create(DateTime creationTimestamp, Map<String, String> labelsToKeys) {
|
||||
return new ClaimsList(toZonedDateTime(creationTimestamp), labelsToKeys);
|
||||
}
|
||||
|
||||
/** Returns the revision id of this claims list, or throws exception if it is null. */
|
||||
@@ -79,9 +86,14 @@ public class ClaimsList {
|
||||
return revisionId;
|
||||
}
|
||||
|
||||
/** Returns the TMDB generation time of this claims list. */
|
||||
public DateTime getTmdbGenerationTime() {
|
||||
return toJodaDateTime(tmdbGenerationTime);
|
||||
}
|
||||
|
||||
/** Returns the creation time of this claims list. */
|
||||
public ZonedDateTime getCreationTimestamp() {
|
||||
return creationTimestamp;
|
||||
public DateTime getCreationTimestamp() {
|
||||
return creationTimestamp.getTimestamp();
|
||||
}
|
||||
|
||||
/** Returns an {@link Map} mapping domain label to its lookup key. */
|
||||
|
||||
@@ -18,7 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.tmch.ClaimsListShard;
|
||||
import google.registry.schema.tmch.ClaimsList;
|
||||
import java.util.List;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -34,11 +34,11 @@ import org.joda.time.DateTime;
|
||||
public class ClaimsListParser {
|
||||
|
||||
/**
|
||||
* Converts the lines from the DNL CSV file into a {@link ClaimsListShard} object.
|
||||
* Converts the lines from the DNL CSV file into a {@link ClaimsList} object.
|
||||
*
|
||||
* <p>Please note that this does <b>not</b> insert the object into Datastore.
|
||||
*/
|
||||
public static ClaimsListShard parse(List<String> lines) {
|
||||
public static ClaimsList parse(List<String> lines) {
|
||||
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<>();
|
||||
|
||||
// First line: <version>,<DNL List creation datetime>
|
||||
@@ -74,6 +74,6 @@ public class ClaimsListParser {
|
||||
builder.put(label, lookupKey);
|
||||
}
|
||||
|
||||
return ClaimsListShard.create(creationTime, builder.build());
|
||||
return ClaimsList.create(creationTime, builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ import static google.registry.request.Action.Method.POST;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.keyring.api.KeyModule.Key;
|
||||
import google.registry.model.tmch.ClaimsListDao;
|
||||
import google.registry.model.tmch.ClaimsListShard;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.schema.tmch.ClaimsList;
|
||||
import java.io.IOException;
|
||||
import java.security.SignatureException;
|
||||
import java.util.List;
|
||||
@@ -54,10 +56,14 @@ public final class TmchDnlAction implements Runnable {
|
||||
} catch (SignatureException | IOException | PGPException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
ClaimsListShard claims = ClaimsListParser.parse(lines);
|
||||
claims.save();
|
||||
ClaimsList claims = ClaimsListParser.parse(lines);
|
||||
ClaimsListShard claimsListShard =
|
||||
ClaimsListShard.create(claims.getTmdbGenerationTime(), claims.getLabelsToKeys());
|
||||
claimsListShard.save();
|
||||
logger.atInfo().log(
|
||||
"Inserted %,d claims into Datastore, created at %s",
|
||||
claims.size(), claims.getCreationTime());
|
||||
claimsListShard.size(), claimsListShard.getCreationTime());
|
||||
|
||||
ClaimsListDao.trySave(claims);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.tools;
|
||||
|
||||
/**
|
||||
* Marker interface for commands that use Cloud Sql.
|
||||
*
|
||||
* <p>Just implementing this is sufficient to use Cloud Sql; {@link RegistryTool} will install it as
|
||||
* needed.
|
||||
*/
|
||||
interface CommandWithCloudSql extends CommandWithRemoteApi {}
|
||||
@@ -16,6 +16,7 @@ package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static google.registry.security.JsonHttp.JSON_SAFETY_PREFIX;
|
||||
import static google.registry.tools.server.CreateOrUpdatePremiumListAction.ALSO_CLOUD_SQL_PARAM;
|
||||
import static google.registry.tools.server.CreateOrUpdatePremiumListAction.INPUT_PARAM;
|
||||
import static google.registry.tools.server.CreateOrUpdatePremiumListAction.NAME_PARAM;
|
||||
import static google.registry.util.ListNamingUtils.convertFilePathToName;
|
||||
@@ -57,6 +58,12 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand
|
||||
required = true)
|
||||
Path inputFile;
|
||||
|
||||
@Parameter(
|
||||
names = {"--also_cloud_sql"},
|
||||
description =
|
||||
"Persist premium list to Cloud SQL in addition to Datastore; defaults to false.")
|
||||
boolean alsoCloudSql;
|
||||
|
||||
protected AppEngineConnection connection;
|
||||
protected int inputLineCount;
|
||||
|
||||
@@ -67,7 +74,7 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand
|
||||
|
||||
abstract String getCommandPath();
|
||||
|
||||
ImmutableMap<String, ?> getParameterMap() {
|
||||
ImmutableMap<String, String> getParameterMap() {
|
||||
return ImmutableMap.of();
|
||||
}
|
||||
|
||||
@@ -88,14 +95,15 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand
|
||||
|
||||
@Override
|
||||
public String execute() throws Exception {
|
||||
ImmutableMap.Builder<String, Object> params = new ImmutableMap.Builder<>();
|
||||
ImmutableMap.Builder<String, String> params = new ImmutableMap.Builder<>();
|
||||
params.put(NAME_PARAM, name);
|
||||
params.put(ALSO_CLOUD_SQL_PARAM, Boolean.toString(alsoCloudSql));
|
||||
String inputFileContents = new String(Files.readAllBytes(inputFile), UTF_8);
|
||||
String requestBody =
|
||||
Joiner.on('&').withKeyValueSeparator("=").join(
|
||||
ImmutableMap.of(INPUT_PARAM, URLEncoder.encode(inputFileContents, UTF_8.toString())));
|
||||
|
||||
ImmutableMap<String, ?> extraParams = getParameterMap();
|
||||
ImmutableMap<String, String> extraParams = getParameterMap();
|
||||
if (extraParams != null) {
|
||||
params.putAll(extraParams);
|
||||
}
|
||||
@@ -110,7 +118,7 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand
|
||||
|
||||
// TODO(user): refactor this behavior into a better general-purpose
|
||||
// response validation that can be re-used across the new client/server commands.
|
||||
String extractServerResponse(String response) {
|
||||
private String extractServerResponse(String response) {
|
||||
Map<String, Object> responseMap = toMap(JSONValue.parse(stripJsonPrefix(response)));
|
||||
|
||||
// TODO(user): consider using jart's FormField Framework.
|
||||
@@ -127,7 +135,7 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand
|
||||
}
|
||||
|
||||
// TODO(user): figure out better place to put this method to make it re-usable
|
||||
static String stripJsonPrefix(String json) {
|
||||
private static String stripJsonPrefix(String json) {
|
||||
Verify.verify(json.startsWith(JSON_SAFETY_PREFIX));
|
||||
return json.substring(JSON_SAFETY_PREFIX.length());
|
||||
}
|
||||
|
||||
@@ -36,12 +36,11 @@ public class CreatePremiumListCommand extends CreateOrUpdatePremiumListCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
ImmutableMap<String, ?> getParameterMap() {
|
||||
ImmutableMap<String, String> getParameterMap() {
|
||||
if (override) {
|
||||
return ImmutableMap.of("override", override);
|
||||
return ImmutableMap.of("override", "true");
|
||||
} else {
|
||||
return ImmutableMap.of();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,32 +19,23 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.domain.DesignatedContact;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.secdns.DelegationSignerData;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.transfer.BaseTransferObject;
|
||||
import google.registry.model.transfer.TransferData;
|
||||
import google.registry.persistence.NomulusNamingStrategy;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.schema.tld.PremiumList;
|
||||
import google.registry.schema.tmch.ClaimsList;
|
||||
import google.registry.persistence.NomulusPostgreSQLDialect;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.Types;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.PostgreSQL95Dialect;
|
||||
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
|
||||
import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
|
||||
import org.hibernate.tool.hbm2ddl.SchemaExport;
|
||||
import org.hibernate.tool.schema.TargetType;
|
||||
import org.joda.time.Period;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
|
||||
/**
|
||||
@@ -57,22 +48,6 @@ import org.testcontainers.containers.PostgreSQLContainer;
|
||||
@Parameters(separators = " =", commandDescription = "Generate PostgreSQL schema.")
|
||||
public class GenerateSqlSchemaCommand implements Command {
|
||||
|
||||
// TODO(mmuller): These should be read from persistence.xml so we don't need to maintain two
|
||||
// separate lists of all SQL table classes.
|
||||
private static final ImmutableSet<Class> SQL_TABLE_CLASSES =
|
||||
ImmutableSet.of(
|
||||
BaseTransferObject.class,
|
||||
ClaimsList.class,
|
||||
DelegationSignerData.class,
|
||||
DesignatedContact.class,
|
||||
DomainBase.class,
|
||||
GracePeriod.class,
|
||||
Period.class,
|
||||
PremiumList.class,
|
||||
RegistryLock.class,
|
||||
TransferData.class,
|
||||
Trid.class);
|
||||
|
||||
@VisibleForTesting
|
||||
public static final String DB_OPTIONS_CLASH =
|
||||
"Database host and port may not be specified along with the option to start a "
|
||||
@@ -159,7 +134,9 @@ public class GenerateSqlSchemaCommand implements Command {
|
||||
|
||||
MetadataSources metadata =
|
||||
new MetadataSources(new StandardServiceRegistryBuilder().applySettings(settings).build());
|
||||
SQL_TABLE_CLASSES.forEach(metadata::addAnnotatedClass);
|
||||
|
||||
addAnnotatedClasses(metadata, settings);
|
||||
|
||||
SchemaExport schemaExport = new SchemaExport();
|
||||
schemaExport.setHaltOnError(true);
|
||||
schemaExport.setFormat(true);
|
||||
@@ -199,12 +176,29 @@ public class GenerateSqlSchemaCommand implements Command {
|
||||
}
|
||||
}
|
||||
|
||||
/** Nomulus mapping rules for column types in Postgresql. */
|
||||
public static class NomulusPostgreSQLDialect extends PostgreSQL95Dialect {
|
||||
public NomulusPostgreSQLDialect() {
|
||||
super();
|
||||
registerColumnType(Types.VARCHAR, "text");
|
||||
registerColumnType(Types.TIMESTAMP, "timestamptz");
|
||||
private void addAnnotatedClasses(MetadataSources metadata, Map<String, String> settings) {
|
||||
ParsedPersistenceXmlDescriptor descriptor =
|
||||
PersistenceXmlParser.locatePersistenceUnits(settings).stream()
|
||||
.filter(unit -> PersistenceModule.PERSISTENCE_UNIT_NAME.equals(unit.getName()))
|
||||
.findFirst()
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new IllegalArgumentException(
|
||||
String.format(
|
||||
"Could not find persistence unit with name %s",
|
||||
PersistenceModule.PERSISTENCE_UNIT_NAME)));
|
||||
|
||||
List<String> classNames = descriptor.getManagedClassNames();
|
||||
for (String className : classNames) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(className);
|
||||
metadata.addAnnotatedClass(clazz);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Could not load class with name %s present in persistence.xml", className),
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,9 @@ final class GetKeyringSecretCommand implements CommandWithRemoteApi {
|
||||
case CLOUD_SQL_PASSWORD:
|
||||
out.write(KeySerializer.serializeString(keyring.getCloudSqlPassword()));
|
||||
break;
|
||||
case TOOLS_CLOUD_SQL_PASSWORD:
|
||||
out.write(KeySerializer.serializeString(keyring.getToolsCloudSqlPassword()));
|
||||
break;
|
||||
case ICANN_REPORTING_PASSWORD:
|
||||
out.write(KeySerializer.serializeString(keyring.getIcannReportingPassword()));
|
||||
break;
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import google.registry.config.RegistryConfig;
|
||||
import google.registry.model.ofy.ObjectifyService;
|
||||
import google.registry.model.transaction.TransactionManagerFactory;
|
||||
import google.registry.tools.AuthModule.LoginRequiredException;
|
||||
import google.registry.tools.params.ParameterFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -210,6 +211,8 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
|
||||
}
|
||||
|
||||
// CommandWithRemoteApis need to have the remote api installed to work.
|
||||
// CommandWithCloudSql extends CommandWithRemoteApi so the command will also get the remote
|
||||
// api installed. This is because the DB password is stored in Datastore.
|
||||
if (command instanceof CommandWithRemoteApi) {
|
||||
if (installer == null) {
|
||||
installer = new RemoteApiInstaller();
|
||||
@@ -233,6 +236,10 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
|
||||
ofy().clearSessionCache();
|
||||
}
|
||||
|
||||
if (command instanceof CommandWithCloudSql) {
|
||||
TransactionManagerFactory.initForTool();
|
||||
}
|
||||
|
||||
command.run();
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,9 @@ final class UpdateKmsKeyringCommand implements CommandWithRemoteApi {
|
||||
case CLOUD_SQL_PASSWORD:
|
||||
kmsUpdater.setCloudSqlPassword(deserializeString(input));
|
||||
break;
|
||||
case TOOLS_CLOUD_SQL_PASSWORD:
|
||||
kmsUpdater.setToolsCloudSqlPassword(deserializeString(input));
|
||||
break;
|
||||
case ICANN_REPORTING_PASSWORD:
|
||||
kmsUpdater.setIcannReportingPassword(deserializeString(input));
|
||||
break;
|
||||
|
||||
@@ -21,7 +21,9 @@ import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.io.Files;
|
||||
import google.registry.model.tmch.ClaimsListDao;
|
||||
import google.registry.model.tmch.ClaimsListShard;
|
||||
import google.registry.schema.tmch.ClaimsList;
|
||||
import google.registry.tmch.ClaimsListParser;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -35,9 +37,14 @@ final class UploadClaimsListCommand extends ConfirmingCommand implements Command
|
||||
@Parameter(description = "Claims list filename")
|
||||
private List<String> mainParameters = new ArrayList<>();
|
||||
|
||||
@Parameter(
|
||||
names = {"--also_cloud_sql"},
|
||||
description = "Persist claims list to Cloud SQL in addition to Datastore; defaults to false.")
|
||||
boolean alsoCloudSql;
|
||||
|
||||
private String claimsListFilename;
|
||||
|
||||
private ClaimsListShard claimsList;
|
||||
private ClaimsList claimsList;
|
||||
|
||||
@Override
|
||||
protected void init() throws IOException {
|
||||
@@ -56,7 +63,10 @@ final class UploadClaimsListCommand extends ConfirmingCommand implements Command
|
||||
|
||||
@Override
|
||||
public String execute() {
|
||||
claimsList.save();
|
||||
ClaimsListShard.create(claimsList.getTmdbGenerationTime(), claimsList.getLabelsToKeys()).save();
|
||||
if (alsoCloudSql) {
|
||||
ClaimsListDao.trySave(claimsList);
|
||||
}
|
||||
return String.format("Successfully uploaded claims list %s", claimsListFilename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,5 +38,5 @@ public enum KeyringKeyName {
|
||||
RDE_STAGING_KEY_PAIR,
|
||||
RDE_STAGING_PUBLIC_KEY,
|
||||
SAFE_BROWSING_API_KEY,
|
||||
TOOLS_CLOUD_SQL_PASSWORD,
|
||||
}
|
||||
|
||||
|
||||
+69
-9
@@ -14,17 +14,28 @@
|
||||
|
||||
package google.registry.tools.server;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.flogger.LazyArgs.lazy;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.model.registry.label.PremiumList;
|
||||
import google.registry.model.registry.label.PremiumList.PremiumListEntry;
|
||||
import google.registry.request.JsonResponse;
|
||||
import google.registry.request.Parameter;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
/**
|
||||
* Abstract base class for actions that update premium lists.
|
||||
*/
|
||||
/** Abstract base class for actions that update premium lists. */
|
||||
public abstract class CreateOrUpdatePremiumListAction implements Runnable {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
@@ -33,24 +44,70 @@ public abstract class CreateOrUpdatePremiumListAction implements Runnable {
|
||||
|
||||
public static final String NAME_PARAM = "name";
|
||||
public static final String INPUT_PARAM = "inputData";
|
||||
public static final String ALSO_CLOUD_SQL_PARAM = "alsoCloudSql";
|
||||
|
||||
@Inject JsonResponse response;
|
||||
@Inject @Parameter("premiumListName") String name;
|
||||
@Inject @Parameter(INPUT_PARAM) String inputData;
|
||||
|
||||
@Inject
|
||||
@Parameter("premiumListName")
|
||||
String name;
|
||||
|
||||
@Inject
|
||||
@Parameter(INPUT_PARAM)
|
||||
String inputData;
|
||||
|
||||
@Inject
|
||||
@Parameter(ALSO_CLOUD_SQL_PARAM)
|
||||
boolean alsoCloudSql;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
savePremiumList();
|
||||
saveToDatastore();
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.atInfo().withCause(e).log(
|
||||
"Usage error in attempting to save premium list from nomulus tool command");
|
||||
response.setPayload(ImmutableMap.of("error", e.toString(), "status", "error"));
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
logger.atSevere().withCause(e).log(
|
||||
"Unexpected error saving premium list from nomulus tool command");
|
||||
"Unexpected error saving premium list to Datastore from nomulus tool command");
|
||||
response.setPayload(ImmutableMap.of("error", e.toString(), "status", "error"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (alsoCloudSql) {
|
||||
try {
|
||||
saveToCloudSql();
|
||||
} catch (Throwable e) {
|
||||
logger.atSevere().withCause(e).log(
|
||||
"Unexpected error saving premium list to Cloud SQL from nomulus tool command");
|
||||
response.setPayload(ImmutableMap.of("error", e.toString(), "status", "error"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
google.registry.schema.tld.PremiumList parseInputToPremiumList() {
|
||||
List<String> inputDataPreProcessed =
|
||||
Splitter.on('\n').omitEmptyStrings().splitToList(inputData);
|
||||
|
||||
ImmutableMap<String, PremiumListEntry> prices =
|
||||
new PremiumList.Builder().setName(name).build().parse(inputDataPreProcessed);
|
||||
ImmutableSet<CurrencyUnit> currencies =
|
||||
prices.values().stream()
|
||||
.map(e -> e.getValue().getCurrencyUnit())
|
||||
.distinct()
|
||||
.collect(toImmutableSet());
|
||||
checkArgument(
|
||||
currencies.size() == 1,
|
||||
"The Cloud SQL schema requires exactly one currency, but got: %s",
|
||||
ImmutableSortedSet.copyOf(currencies));
|
||||
CurrencyUnit currency = Iterables.getOnlyElement(currencies);
|
||||
|
||||
Map<String, BigDecimal> priceAmounts =
|
||||
Maps.transformValues(prices, ple -> ple.getValue().getAmount());
|
||||
return google.registry.schema.tld.PremiumList.create(name, currency, priceAmounts);
|
||||
}
|
||||
|
||||
/** Logs the premium list data at INFO, truncated if too long. */
|
||||
@@ -64,6 +121,9 @@ public abstract class CreateOrUpdatePremiumListAction implements Runnable {
|
||||
: (inputData.substring(0, MAX_LOGGING_PREMIUM_LIST_LENGTH) + "<truncated>")));
|
||||
}
|
||||
|
||||
/** Creates a new premium list or updates an existing one. */
|
||||
protected abstract void savePremiumList();
|
||||
/** Saves the premium list to Datastore. */
|
||||
protected abstract void saveToDatastore();
|
||||
|
||||
/** Saves the premium list to Cloud SQL. */
|
||||
protected abstract void saveToCloudSql();
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import google.registry.model.registry.label.PremiumList;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.schema.tld.PremiumListDao;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -50,7 +51,7 @@ public class CreatePremiumListAction extends CreateOrUpdatePremiumListAction {
|
||||
@Inject CreatePremiumListAction() {}
|
||||
|
||||
@Override
|
||||
protected void savePremiumList() {
|
||||
protected void saveToDatastore() {
|
||||
checkArgument(
|
||||
!doesPremiumListExist(name), "A premium list of this name already exists: %s.", name);
|
||||
if (!override) {
|
||||
@@ -71,4 +72,22 @@ public class CreatePremiumListAction extends CreateOrUpdatePremiumListAction {
|
||||
logger.atInfo().log(message);
|
||||
response.setPayload(ImmutableMap.of("status", "success", "message", message));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveToCloudSql() {
|
||||
if (!override) {
|
||||
assertTldExists(name);
|
||||
}
|
||||
logger.atInfo().log("Saving premium list to Cloud SQL for TLD %s", name);
|
||||
// TODO(mcilwain): Call logInputData() here once Datastore persistence is removed.
|
||||
|
||||
google.registry.schema.tld.PremiumList premiumList = parseInputToPremiumList();
|
||||
PremiumListDao.saveNew(premiumList);
|
||||
|
||||
String message =
|
||||
String.format(
|
||||
"Saved premium list %s with %d entries", name, premiumList.getLabelsToPrices().size());
|
||||
logger.atInfo().log(message);
|
||||
// TODO(mcilwain): Call response.setPayload(...) here once Datastore persistence is removed.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,12 @@ public class ToolsServerModule {
|
||||
return extractRequiredParameter(req, CreatePremiumListAction.INPUT_PARAM);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter("alsoCloudSql")
|
||||
static boolean provideAlsoCloudSql(HttpServletRequest req) {
|
||||
return extractBooleanParameter(req, CreatePremiumListAction.ALSO_CLOUD_SQL_PARAM);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter("premiumListName")
|
||||
static String provideName(HttpServletRequest req) {
|
||||
|
||||
@@ -46,7 +46,7 @@ public class UpdatePremiumListAction extends CreateOrUpdatePremiumListAction {
|
||||
@Inject UpdatePremiumListAction() {}
|
||||
|
||||
@Override
|
||||
protected void savePremiumList() {
|
||||
protected void saveToDatastore() {
|
||||
Optional<PremiumList> existingPremiumList = PremiumList.getUncached(name);
|
||||
checkArgument(
|
||||
existingPremiumList.isPresent(),
|
||||
@@ -67,4 +67,11 @@ public class UpdatePremiumListAction extends CreateOrUpdatePremiumListAction {
|
||||
logger.atInfo().log(message);
|
||||
response.setPayload(ImmutableMap.of("status", "success", "message", message));
|
||||
}
|
||||
|
||||
// TODO(mcilwain): Implement this in a subsequent PR.
|
||||
@Override
|
||||
protected void saveToCloudSql() {
|
||||
throw new UnsupportedOperationException(
|
||||
"Updating of premium lists in Cloud SQL is not supported yet");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,12 @@
|
||||
<class>google.registry.model.transfer.TransferData</class>
|
||||
<class>google.registry.model.eppcommon.Trid</class>
|
||||
|
||||
<!-- Customized type converters -->
|
||||
<class>google.registry.persistence.BloomFilterConverter</class>
|
||||
<class>google.registry.persistence.CreateAutoTimestampConverter</class>
|
||||
<class>google.registry.persistence.UpdateAutoTimestampConverter</class>
|
||||
<class>google.registry.persistence.ZonedDateTimeConverter</class>
|
||||
|
||||
<!-- TODO(weiminyu): check out application-layer validation. -->
|
||||
<validation-mode>NONE</validation-mode>
|
||||
</persistence-unit>
|
||||
|
||||
@@ -37,17 +37,18 @@
|
||||
{/call}
|
||||
|
||||
<p>Please work with the registrant to mitigate any security issues and have the
|
||||
domains delisted.</p>
|
||||
domains delisted. If you believe that any of the domains were reported in error, or are still
|
||||
receiving reports for issues that have been remediated,
|
||||
please <a href="https://safebrowsing.google.com/safebrowsing/report_error/?hl=en">submit a
|
||||
request</a> to have the site reviewed.</p>
|
||||
|
||||
{call .resourceList}
|
||||
{param resources: $resources /}
|
||||
{/call}
|
||||
|
||||
<p>You will continue to receive a monthly summary of all domains managed by your registrar
|
||||
that remain on our lists of potential security threats. You will additionally receive a daily
|
||||
notice when any new domains that are added to these lists. Once the registrant has resolved
|
||||
the security issues and followed the steps to have his or her domain reviewed and delisted
|
||||
it will automatically be removed from our monthly reporting.</p>
|
||||
that remain on our lists of potential security threats. You will also receive a daily
|
||||
notice when any new domains are added to these lists.</p>
|
||||
|
||||
<p>If you have any questions regarding this notice, please contact {$replyToEmail}.</p>
|
||||
{/template}
|
||||
@@ -79,11 +80,14 @@
|
||||
{param resources: $resources /}
|
||||
{/call}
|
||||
|
||||
<p>If you believe that any of the domains were reported in error, or are still receiving
|
||||
reports for issues that have been remediated,
|
||||
please <a href="https://safebrowsing.google.com/safebrowsing/report_error/?hl=en">submit
|
||||
a request</a> to have the site reviewed.</p>
|
||||
|
||||
<p>You will continue to receive daily notices when new domains managed by your registrar
|
||||
are flagged for abuse, as well as a monthly summary of all of your domains under management
|
||||
that remain flagged for abuse. Once the registrant has resolved the security issues and
|
||||
followed the steps to have his or her domain reviewed and delisted it will automatically
|
||||
be removed from our reporting.</p>
|
||||
that remain flagged for abuse.</p>
|
||||
|
||||
<p>If you would like to change the email to which these notices are sent please update your
|
||||
abuse contact using your registrar portal account.</p>
|
||||
|
||||
@@ -16,7 +16,7 @@ package google.registry.dns.writer.dnsupdate;
|
||||
|
||||
import static com.google.common.io.BaseEncoding.base16;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainBase;
|
||||
import static google.registry.testing.DatastoreHelper.newHostResource;
|
||||
@@ -450,9 +450,10 @@ public class DnsUpdateWriterTest {
|
||||
return fixIterator(Record.class, set.rrs());
|
||||
}
|
||||
}
|
||||
assert_().fail(
|
||||
"No record set found for resource '%s' type '%s'",
|
||||
resourceName, Type.string(recordType));
|
||||
assertWithMessage(
|
||||
"No record set found for resource '%s' type '%s'",
|
||||
resourceName, Type.string(recordType))
|
||||
.fail();
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
package google.registry.documentation;
|
||||
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.util.BuildPathUtils.getProjectRoot;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
@@ -53,7 +53,7 @@ public class FlowDocumentationTest {
|
||||
// Don't use Truth's isEqualTo() because the output is huge and unreadable for large files.
|
||||
DocumentationGenerator generator = new DocumentationGenerator();
|
||||
if (!generator.generateMarkdown().equals(goldenMarkdown)) {
|
||||
assert_().fail(UPDATE_INSTRUCTIONS);
|
||||
assertWithMessage(UPDATE_INSTRUCTIONS).fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,15 @@ public class KmsKeyringTest {
|
||||
assertThat(cloudSqlPassword).isEqualTo("cloud-sql-password-stringmoo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getToolsCloudSqlPassword() throws Exception {
|
||||
saveCleartextSecret("tools-cloud-sql-password-string");
|
||||
|
||||
String toolsCloudSqlPassword = keyring.getToolsCloudSqlPassword();
|
||||
|
||||
assertThat(toolsCloudSqlPassword).isEqualTo("tools-cloud-sql-password-stringmoo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getRdeSigningKey() throws Exception {
|
||||
saveKeyPairSecret("rde-signing-public", "rde-signing-private");
|
||||
|
||||
@@ -99,6 +99,16 @@ public class KmsUpdaterTest {
|
||||
"cloud-sql-password-string", "cloud-sql-password-string/foo", getCiphertext("value1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_setToolsCloudSqlPassword() {
|
||||
updater.setToolsCloudSqlPassword("value1").update();
|
||||
|
||||
verifySecretAndSecretRevisionWritten(
|
||||
"tools-cloud-sql-password-string",
|
||||
"tools-cloud-sql-password-string/foo",
|
||||
getCiphertext("value1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_setIcannReportingPassword() {
|
||||
updater.setIcannReportingPassword("value1").update();
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
package google.registry.mapreduce.inputs;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.mapreduce.inputs.EppResourceInputs.createChildEntityInput;
|
||||
import static google.registry.model.index.EppResourceIndexBucket.getBucketKey;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
@@ -290,7 +290,7 @@ public class ChildEntityInputTest {
|
||||
seen.add(reader.next());
|
||||
try {
|
||||
ImmutableObject o = reader.next();
|
||||
assert_().fail("Unexpected element: " + o);
|
||||
assertWithMessage("Unexpected element: %s", o).fail();
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
package google.registry.mapreduce.inputs;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import com.google.appengine.tools.mapreduce.Input;
|
||||
import com.google.appengine.tools.mapreduce.InputReader;
|
||||
@@ -65,7 +65,7 @@ public final class CommitLogManifestInputTest {
|
||||
seen.add(reader.next());
|
||||
try {
|
||||
Key<CommitLogManifest> key = reader.next();
|
||||
assert_().fail("Unexpected element: " + key);
|
||||
assertWithMessage("Unexpected element: %s", key).fail();
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,7 @@ public final class CommitLogManifestInputTest {
|
||||
key = reader.next();
|
||||
seen.add(key);
|
||||
}
|
||||
assert_().fail("Unexpected element: " + key);
|
||||
assertWithMessage("Unexpected element: %s", key).fail();
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ public final class CommitLogManifestInputTest {
|
||||
key = reader.next();
|
||||
seen.add(key);
|
||||
}
|
||||
assert_().fail("Unexpected element: " + key);
|
||||
assertWithMessage("Unexpected element: %s", key).fail();
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
package google.registry.mapreduce.inputs;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.mapreduce.inputs.EppResourceInputs.createEntityInput;
|
||||
import static google.registry.mapreduce.inputs.EppResourceInputs.createKeyInput;
|
||||
import static google.registry.model.index.EppResourceIndexBucket.getBucketKey;
|
||||
@@ -123,7 +123,7 @@ public class EppResourceInputsTest {
|
||||
seen.add(reader.next());
|
||||
try {
|
||||
Key<DomainBase> key = reader.next();
|
||||
assert_().fail("Unexpected element: " + key);
|
||||
assertWithMessage("Unexpected element: %s", key).fail();
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
}
|
||||
@@ -148,7 +148,7 @@ public class EppResourceInputsTest {
|
||||
seen.add(reader.next());
|
||||
try {
|
||||
DomainBase domain = reader.next();
|
||||
assert_().fail("Unexpected element: " + domain);
|
||||
assertWithMessage("Unexpected element: %s", domain).fail();
|
||||
} catch (NoSuchElementException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package google.registry.model;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
@@ -127,10 +126,10 @@ public abstract class EntityTestCase {
|
||||
// If the field's type was not indexable (because it's not a supported Datastore type) then
|
||||
// this error will be thrown. If we expected no indexing, that's fine. Otherwise, fail.
|
||||
if (indexed || !e.getMessage().endsWith(" is not a supported property type.")) {
|
||||
assert_().fail(String.format("%s was %sindexed", fieldPath, indexed ? "not " : ""));
|
||||
assertWithMessage("%s was %sindexed", fieldPath, indexed ? "not " : "").fail();
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
assert_().fail(String.format("%s (indexed=%b): %s", fieldPath, indexed, e.getMessage()));
|
||||
assertWithMessage("%s (indexed=%b): %s", fieldPath, indexed, e.getMessage()).fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.registry;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||
|
||||
import google.registry.model.transaction.JpaTransactionManagerRule;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.schema.domain.RegistryLock.Action;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.PersistenceException;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link RegistryLockDao}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public final class RegistryLockDaoTest {
|
||||
|
||||
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||
|
||||
@Rule
|
||||
public final JpaTransactionManagerRule jpaTmRule =
|
||||
new JpaTransactionManagerRule.Builder().build();
|
||||
|
||||
@Test
|
||||
public void testSaveAndLoad_success() {
|
||||
RegistryLock lock = createLock();
|
||||
RegistryLockDao.save(lock);
|
||||
RegistryLock fromDatabase = RegistryLockDao.getByVerificationCode(lock.getVerificationCode());
|
||||
assertThat(fromDatabase.getDomainName()).isEqualTo(lock.getDomainName());
|
||||
assertThat(fromDatabase.getVerificationCode()).isEqualTo(lock.getVerificationCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveAndLoad_failure_differentCode() {
|
||||
RegistryLock lock = createLock();
|
||||
RegistryLockDao.save(lock);
|
||||
PersistenceException exception =
|
||||
assertThrows(
|
||||
PersistenceException.class,
|
||||
() -> RegistryLockDao.getByVerificationCode(UUID.randomUUID().toString()));
|
||||
assertThat(exception)
|
||||
.hasCauseThat()
|
||||
.hasMessageThat()
|
||||
.isEqualTo("No registry lock with this code");
|
||||
assertThat(exception).hasCauseThat().isInstanceOf(NullPointerException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveTwiceAndLoad_returnsLatest() {
|
||||
RegistryLock lock = createLock();
|
||||
jpaTm().transact(() -> RegistryLockDao.save(lock));
|
||||
jpaTmRule.getTxnClock().advanceOneMilli();
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
RegistryLock secondLock =
|
||||
RegistryLockDao.getByVerificationCode(lock.getVerificationCode());
|
||||
secondLock.setCompletionTimestamp(jpaTmRule.getTxnClock().nowUtc());
|
||||
RegistryLockDao.save(secondLock);
|
||||
});
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
RegistryLock fromDatabase =
|
||||
RegistryLockDao.getByVerificationCode(lock.getVerificationCode());
|
||||
assertThat(fromDatabase.getCompletionTimestamp().get())
|
||||
.isEqualTo(jpaTmRule.getTxnClock().nowUtc());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_saveNull() {
|
||||
assertThrows(NullPointerException.class, () -> RegistryLockDao.save(null));
|
||||
}
|
||||
|
||||
private RegistryLock createLock() {
|
||||
return new RegistryLock.Builder()
|
||||
.setRepoId("repoId")
|
||||
.setDomainName("example.test")
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setAction(Action.LOCK)
|
||||
.setVerificationCode(UUID.randomUUID().toString())
|
||||
.isSuperuser(true)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.tmch;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.transaction.JpaTransactionManagerRule;
|
||||
import google.registry.schema.tmch.ClaimsList;
|
||||
import google.registry.testing.FakeClock;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link ClaimsListDao}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class ClaimsListDaoTest {
|
||||
|
||||
private FakeClock fakeClock = new FakeClock();
|
||||
|
||||
@Rule
|
||||
public final JpaTransactionManagerRule jpaTmRule =
|
||||
new JpaTransactionManagerRule.Builder().build();
|
||||
|
||||
@Test
|
||||
public void trySave_insertsClaimsListSuccessfully() {
|
||||
ClaimsList claimsList =
|
||||
ClaimsList.create(fakeClock.nowUtc(), ImmutableMap.of("label1", "key1", "label2", "key2"));
|
||||
ClaimsListDao.trySave(claimsList);
|
||||
ClaimsList insertedClaimsList = ClaimsListDao.getCurrent();
|
||||
assertClaimsListEquals(claimsList, insertedClaimsList);
|
||||
assertThat(insertedClaimsList.getCreationTimestamp())
|
||||
.isEqualTo(jpaTmRule.getTxnClock().nowUtc());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trySave_noExceptionThrownWhenSaveFail() {
|
||||
ClaimsList claimsList =
|
||||
ClaimsList.create(fakeClock.nowUtc(), ImmutableMap.of("label1", "key1", "label2", "key2"));
|
||||
ClaimsListDao.trySave(claimsList);
|
||||
ClaimsList insertedClaimsList = ClaimsListDao.getCurrent();
|
||||
assertClaimsListEquals(claimsList, insertedClaimsList);
|
||||
// Save ClaimsList with existing revisionId should fail because revisionId is the primary key.
|
||||
ClaimsListDao.trySave(insertedClaimsList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trySave_claimsListWithNoEntries() {
|
||||
ClaimsList claimsList = ClaimsList.create(fakeClock.nowUtc(), ImmutableMap.of());
|
||||
ClaimsListDao.trySave(claimsList);
|
||||
ClaimsList insertedClaimsList = ClaimsListDao.getCurrent();
|
||||
assertClaimsListEquals(claimsList, insertedClaimsList);
|
||||
assertThat(insertedClaimsList.getLabelsToKeys()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrent_throwsNoResultExceptionIfTableIsEmpty() {
|
||||
PersistenceException thrown =
|
||||
assertThrows(PersistenceException.class, () -> ClaimsListDao.getCurrent());
|
||||
assertThat(thrown).hasCauseThat().isInstanceOf(NoResultException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCurrent_returnsLatestClaims() {
|
||||
ClaimsList oldClaimsList =
|
||||
ClaimsList.create(fakeClock.nowUtc(), ImmutableMap.of("label1", "key1", "label2", "key2"));
|
||||
ClaimsList newClaimsList =
|
||||
ClaimsList.create(fakeClock.nowUtc(), ImmutableMap.of("label3", "key3", "label4", "key4"));
|
||||
ClaimsListDao.trySave(oldClaimsList);
|
||||
ClaimsListDao.trySave(newClaimsList);
|
||||
assertClaimsListEquals(newClaimsList, ClaimsListDao.getCurrent());
|
||||
}
|
||||
|
||||
private void assertClaimsListEquals(ClaimsList left, ClaimsList right) {
|
||||
assertThat(left.getRevisionId()).isEqualTo(right.getRevisionId());
|
||||
assertThat(left.getTmdbGenerationTime()).isEqualTo(right.getTmdbGenerationTime());
|
||||
assertThat(left.getLabelsToKeys()).isEqualTo(right.getLabelsToKeys());
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.transaction;
|
||||
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** JUnit test for {@link DummyJpaTransactionManager} */
|
||||
@RunWith(JUnit4.class)
|
||||
public class DummyJpaTransactionManagerTest {
|
||||
|
||||
@Test
|
||||
public void throwsExceptionWhenAnyMethodIsInvoked() {
|
||||
assertThrows(UnsupportedOperationException.class, () -> jpaTm().transact(() -> null));
|
||||
assertThrows(UnsupportedOperationException.class, () -> jpaTm().getTransactionTime());
|
||||
}
|
||||
}
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.transaction;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||
import static google.registry.testing.TestDataHelper.fileClassPath;
|
||||
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.math.BigInteger;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceException;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link JpaTransactionManagerImpl}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class JpaTransactionManagerImplTest {
|
||||
@Rule
|
||||
public final JpaTransactionManagerRule jpaTmRule =
|
||||
new JpaTransactionManagerRule.Builder()
|
||||
.withInitScript(fileClassPath(getClass(), "test_schema.sql"))
|
||||
.build();
|
||||
|
||||
@Test
|
||||
public void inTransaction_returnsCorrespondingResult() {
|
||||
assertThat(jpaTm().inTransaction()).isFalse();
|
||||
jpaTm().transact(() -> assertThat(jpaTm().inTransaction()).isTrue());
|
||||
assertThat(jpaTm().inTransaction()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertInTransaction_throwsExceptionWhenNotInTransaction() {
|
||||
assertThrows(PersistenceException.class, () -> jpaTm().assertInTransaction());
|
||||
jpaTm().transact(() -> jpaTm().assertInTransaction());
|
||||
assertThrows(PersistenceException.class, () -> jpaTm().assertInTransaction());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTransactionTime_throwsExceptionWhenNotInTransaction() {
|
||||
FakeClock txnClock = jpaTmRule.getTxnClock();
|
||||
txnClock.advanceOneMilli();
|
||||
assertThrows(PersistenceException.class, () -> jpaTm().getTransactionTime());
|
||||
jpaTm().transact(() -> assertThat(jpaTm().getTransactionTime()).isEqualTo(txnClock.nowUtc()));
|
||||
assertThrows(PersistenceException.class, () -> jpaTm().getTransactionTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transact_succeeds() {
|
||||
assertPersonEmpty();
|
||||
assertCompanyEmpty();
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
insertPerson(10);
|
||||
insertCompany("Foo");
|
||||
insertCompany("Bar");
|
||||
});
|
||||
assertPersonCount(1);
|
||||
assertPersonExist(10);
|
||||
assertCompanyCount(2);
|
||||
assertCompanyExist("Foo");
|
||||
assertCompanyExist("Bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transact_hasNoEffectWithPartialSuccess() {
|
||||
assertPersonEmpty();
|
||||
assertCompanyEmpty();
|
||||
assertThrows(
|
||||
RuntimeException.class,
|
||||
() ->
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
insertPerson(10);
|
||||
insertCompany("Foo");
|
||||
throw new RuntimeException();
|
||||
}));
|
||||
assertPersonEmpty();
|
||||
assertCompanyEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transact_reusesExistingTransaction() {
|
||||
assertPersonEmpty();
|
||||
assertCompanyEmpty();
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
insertPerson(10);
|
||||
insertCompany("Foo");
|
||||
insertCompany("Bar");
|
||||
}));
|
||||
assertPersonCount(1);
|
||||
assertPersonExist(10);
|
||||
assertCompanyCount(2);
|
||||
assertCompanyExist("Foo");
|
||||
assertCompanyExist("Bar");
|
||||
}
|
||||
|
||||
private void insertPerson(int age) {
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery(String.format("INSERT INTO Person (age) VALUES (%d)", age))
|
||||
.executeUpdate();
|
||||
}
|
||||
|
||||
private void insertCompany(String name) {
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery(String.format("INSERT INTO Company (name) VALUES ('%s')", name))
|
||||
.executeUpdate();
|
||||
}
|
||||
|
||||
private void assertPersonExist(int age) {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
EntityManager em = jpaTm().getEntityManager();
|
||||
Integer maybeAge =
|
||||
(Integer)
|
||||
em.createNativeQuery(
|
||||
String.format("SELECT age FROM Person WHERE age = %d", age))
|
||||
.getSingleResult();
|
||||
assertThat(maybeAge).isEqualTo(age);
|
||||
});
|
||||
}
|
||||
|
||||
private void assertCompanyExist(String name) {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
String maybeName =
|
||||
(String)
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery(
|
||||
String.format("SELECT name FROM Company WHERE name = '%s'", name))
|
||||
.getSingleResult();
|
||||
assertThat(maybeName).isEqualTo(name);
|
||||
});
|
||||
}
|
||||
|
||||
private void assertPersonCount(int count) {
|
||||
assertThat(countTable("Person")).isEqualTo(count);
|
||||
}
|
||||
|
||||
private void assertCompanyCount(int count) {
|
||||
assertThat(countTable("Company")).isEqualTo(count);
|
||||
}
|
||||
|
||||
private void assertPersonEmpty() {
|
||||
assertPersonCount(0);
|
||||
}
|
||||
|
||||
private void assertCompanyEmpty() {
|
||||
assertCompanyCount(0);
|
||||
}
|
||||
|
||||
private int countTable(String tableName) {
|
||||
return jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
BigInteger colCount =
|
||||
(BigInteger)
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery(String.format("SELECT COUNT(*) FROM %s", tableName))
|
||||
.getSingleResult();
|
||||
return colCount.intValue();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.transaction;
|
||||
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
import static org.testcontainers.containers.PostgreSQLContainer.POSTGRESQL_PORT;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.io.Resources;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
|
||||
import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
|
||||
import org.hibernate.jpa.boot.spi.Bootstrap;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.testcontainers.containers.JdbcDatabaseContainer;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
|
||||
/**
|
||||
* JUnit Rule to provision {@link JpaTransactionManagerImpl} backed by {@link PostgreSQLContainer}.
|
||||
*
|
||||
* <p>This rule also replaces the {@link JpaTransactionManagerImpl} provided by {@link
|
||||
* TransactionManagerFactory} with the {@link JpaTransactionManagerImpl} generated by the rule
|
||||
* itself, so that all SQL queries will be sent to the database instance created by {@link
|
||||
* PostgreSQLContainer} to achieve test purpose.
|
||||
*/
|
||||
public class JpaTransactionManagerRule extends ExternalResource {
|
||||
private static final String SCHEMA_GOLDEN_SQL = "sql/schema/nomulus.golden.sql";
|
||||
private static final String DB_CLEANUP_SQL =
|
||||
"google/registry/model/transaction/cleanup_database.sql";
|
||||
private static final String MANAGEMENT_DB_NAME = "management";
|
||||
private static final String POSTGRES_DB_NAME = "postgres";
|
||||
|
||||
private final DateTime now = DateTime.now(UTC);
|
||||
private final FakeClock clock = new FakeClock(now);
|
||||
private final String initScriptPath;
|
||||
private final ImmutableList<Class> extraEntityClasses;
|
||||
private final ImmutableMap userProperties;
|
||||
|
||||
private static final JdbcDatabaseContainer database = create();
|
||||
private EntityManagerFactory emf;
|
||||
private JpaTransactionManager cachedTm;
|
||||
|
||||
private JpaTransactionManagerRule(
|
||||
String initScriptPath,
|
||||
ImmutableList<Class> extraEntityClasses,
|
||||
ImmutableMap<String, String> userProperties) {
|
||||
this.initScriptPath = initScriptPath;
|
||||
this.extraEntityClasses = extraEntityClasses;
|
||||
this.userProperties = userProperties;
|
||||
}
|
||||
|
||||
private static JdbcDatabaseContainer create() {
|
||||
PostgreSQLContainer container = new PostgreSQLContainer().withDatabaseName(MANAGEMENT_DB_NAME);
|
||||
container.start();
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> container.close()));
|
||||
return container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before() throws Exception {
|
||||
executeSql(MANAGEMENT_DB_NAME, DB_CLEANUP_SQL);
|
||||
executeSql(POSTGRES_DB_NAME, initScriptPath);
|
||||
|
||||
ImmutableMap properties = PersistenceModule.providesDefaultDatabaseConfigs();
|
||||
if (!userProperties.isEmpty()) {
|
||||
// If there are user properties, create a new properties object with these added.
|
||||
ImmutableMap.Builder builder = properties.builder();
|
||||
builder.putAll(userProperties);
|
||||
properties = builder.build();
|
||||
}
|
||||
|
||||
emf =
|
||||
createEntityManagerFactory(
|
||||
getJdbcUrlFor(POSTGRES_DB_NAME),
|
||||
database.getUsername(),
|
||||
database.getPassword(),
|
||||
properties,
|
||||
extraEntityClasses);
|
||||
JpaTransactionManagerImpl txnManager = new JpaTransactionManagerImpl(emf, clock);
|
||||
cachedTm = TransactionManagerFactory.jpaTm;
|
||||
TransactionManagerFactory.jpaTm = txnManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void after() {
|
||||
TransactionManagerFactory.jpaTm = cachedTm;
|
||||
if (emf != null) {
|
||||
emf.close();
|
||||
}
|
||||
cachedTm = null;
|
||||
}
|
||||
|
||||
private void executeSql(String dbName, String sqlScriptPath) {
|
||||
try (Connection conn = createConnection(dbName)) {
|
||||
String sqlScript = Resources.toString(Resources.getResource(sqlScriptPath), Charsets.UTF_8);
|
||||
conn.createStatement().execute(sqlScript);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getJdbcUrlFor(String dbName) {
|
||||
// Disable Postgres driver use of java.util.logging to reduce noise at startup time
|
||||
return "jdbc:postgresql://"
|
||||
+ database.getContainerIpAddress()
|
||||
+ ":"
|
||||
+ database.getMappedPort(POSTGRESQL_PORT)
|
||||
+ "/"
|
||||
+ dbName
|
||||
+ "?loggerLevel=OFF";
|
||||
}
|
||||
|
||||
private Connection createConnection(String dbName) {
|
||||
final Properties info = new Properties();
|
||||
info.put("user", database.getUsername());
|
||||
info.put("password", database.getPassword());
|
||||
final Driver jdbcDriverInstance = database.getJdbcDriverInstance();
|
||||
try {
|
||||
return jdbcDriverInstance.connect(getJdbcUrlFor(dbName), info);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Constructs the {@link EntityManagerFactory} instance. */
|
||||
private static EntityManagerFactory createEntityManagerFactory(
|
||||
String jdbcUrl,
|
||||
String username,
|
||||
String password,
|
||||
ImmutableMap<String, String> configs,
|
||||
ImmutableList<Class> extraEntityClasses) {
|
||||
HashMap<String, String> properties = Maps.newHashMap(configs);
|
||||
properties.put(Environment.URL, jdbcUrl);
|
||||
properties.put(Environment.USER, username);
|
||||
properties.put(Environment.PASS, password);
|
||||
|
||||
ParsedPersistenceXmlDescriptor descriptor =
|
||||
PersistenceXmlParser.locatePersistenceUnits(properties).stream()
|
||||
.filter(unit -> PersistenceModule.PERSISTENCE_UNIT_NAME.equals(unit.getName()))
|
||||
.findFirst()
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new IllegalArgumentException(
|
||||
String.format(
|
||||
"Could not find persistence unit with name %s",
|
||||
PersistenceModule.PERSISTENCE_UNIT_NAME)));
|
||||
|
||||
extraEntityClasses.stream().map(Class::getName).forEach(descriptor::addClasses);
|
||||
return Bootstrap.getEntityManagerFactoryBuilder(descriptor, properties).build();
|
||||
}
|
||||
|
||||
/** Returns the {@link FakeClock} used by the underlying {@link JpaTransactionManagerImpl}. */
|
||||
public FakeClock getTxnClock() {
|
||||
return clock;
|
||||
}
|
||||
|
||||
/** Builder for {@link JpaTransactionManagerRule}. */
|
||||
public static class Builder {
|
||||
private String initScript;
|
||||
private List<Class> extraEntityClasses = new ArrayList<Class>();
|
||||
private Map<String, String> userProperties = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Sets the SQL script to be used to initialize the database. If not set,
|
||||
* sql/schema/nomulus.golden.sql will be used.
|
||||
*/
|
||||
public Builder withInitScript(String initScript) {
|
||||
this.initScript = initScript;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Adds annotated class(es) to the known entities for the database. */
|
||||
public Builder withEntityClass(Class... classes) {
|
||||
this.extraEntityClasses.addAll(ImmutableSet.copyOf(classes));
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Adds the specified property to those used to initialize the transaction manager. */
|
||||
public Builder withProperty(String name, String value) {
|
||||
this.userProperties.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds a {@link JpaTransactionManagerRule} instance. */
|
||||
public JpaTransactionManagerRule build() {
|
||||
if (initScript == null) {
|
||||
initScript = SCHEMA_GOLDEN_SQL;
|
||||
}
|
||||
return new JpaTransactionManagerRule(
|
||||
initScript,
|
||||
ImmutableList.copyOf(extraEntityClasses),
|
||||
ImmutableMap.copyOf(userProperties));
|
||||
}
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.transaction;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import java.util.List;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.PersistenceException;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** JUnit test for {@link JpaTransactionManagerRule} */
|
||||
@RunWith(JUnit4.class)
|
||||
public class JpaTransactionManagerRuleTest {
|
||||
|
||||
@Rule
|
||||
public final JpaTransactionManagerRule jpaTmRule =
|
||||
new JpaTransactionManagerRule.Builder()
|
||||
.withEntityClass(TestEntity.class)
|
||||
.withProperty(Environment.HBM2DDL_AUTO, "update")
|
||||
.build();
|
||||
|
||||
@Test
|
||||
public void verifiesRuleWorks() {
|
||||
assertThrows(
|
||||
PersistenceException.class,
|
||||
() ->
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery("SELECT * FROM NoneExistentTable")
|
||||
.getResultList()));
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
List results =
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery("SELECT * FROM \"ClaimsList\"")
|
||||
.getResultList();
|
||||
assertThat(results).isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtraParameters() {
|
||||
// This test verifies that 1) withEntityClass() has registered TestEntity and 2) The table
|
||||
// has been created, implying withProperty(HBM2DDL_AUTO, "update") worked.
|
||||
TestEntity original = new TestEntity("key", "value");
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(original));
|
||||
TestEntity retrieved =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "key"));
|
||||
assertThat(retrieved).isEqualTo(original);
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity") // Specify name to avoid nested class naming issues.
|
||||
static class TestEntity extends ImmutableObject {
|
||||
@Id String key;
|
||||
String value;
|
||||
|
||||
TestEntity(String key, String value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
TestEntity() {}
|
||||
}
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.transaction;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||
import static google.registry.testing.TestDataHelper.fileClassPath;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.util.Clock;
|
||||
import java.math.BigInteger;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.PersistenceException;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
import org.testcontainers.containers.JdbcDatabaseContainer;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
|
||||
/** Unit tests for {@link JpaTransactionManager}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class JpaTransactionManagerTest {
|
||||
@Rule
|
||||
public JdbcDatabaseContainer database =
|
||||
new PostgreSQLContainer().withInitScript(fileClassPath(getClass(), "test_schema.sql"));
|
||||
|
||||
private DateTime now = DateTime.now(UTC);
|
||||
private Clock clock = new FakeClock(now);
|
||||
private EntityManagerFactory emf;
|
||||
private JpaTransactionManager txnManager;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
emf =
|
||||
PersistenceModule.create(
|
||||
database.getJdbcUrl(),
|
||||
database.getUsername(),
|
||||
database.getPassword(),
|
||||
PersistenceModule.providesDefaultDatabaseConfigs());
|
||||
txnManager = new JpaTransactionManager(emf, clock);
|
||||
}
|
||||
|
||||
@After
|
||||
public void clear() {
|
||||
if (emf != null) {
|
||||
emf.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inTransaction_returnsCorrespondingResult() {
|
||||
assertThat(txnManager.inTransaction()).isFalse();
|
||||
txnManager.transact(() -> assertThat(txnManager.inTransaction()).isTrue());
|
||||
assertThat(txnManager.inTransaction()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertInTransaction_throwsExceptionWhenNotInTransaction() {
|
||||
assertThrows(PersistenceException.class, () -> txnManager.assertInTransaction());
|
||||
txnManager.transact(() -> txnManager.assertInTransaction());
|
||||
assertThrows(PersistenceException.class, () -> txnManager.assertInTransaction());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTransactionTime_throwsExceptionWhenNotInTransaction() {
|
||||
assertThrows(PersistenceException.class, () -> txnManager.getTransactionTime());
|
||||
txnManager.transact(() -> assertThat(txnManager.getTransactionTime()).isEqualTo(now));
|
||||
assertThrows(PersistenceException.class, () -> txnManager.getTransactionTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transact_succeeds() {
|
||||
assertPersonEmpty();
|
||||
assertCompanyEmpty();
|
||||
txnManager.transact(
|
||||
() -> {
|
||||
insertPerson(10);
|
||||
insertCompany("Foo");
|
||||
insertCompany("Bar");
|
||||
});
|
||||
assertPersonCount(1);
|
||||
assertPersonExist(10);
|
||||
assertCompanyCount(2);
|
||||
assertCompanyExist("Foo");
|
||||
assertCompanyExist("Bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transact_hasNoEffectWithPartialSuccess() {
|
||||
assertPersonEmpty();
|
||||
assertCompanyEmpty();
|
||||
assertThrows(
|
||||
RuntimeException.class,
|
||||
() ->
|
||||
txnManager.transact(
|
||||
() -> {
|
||||
insertPerson(10);
|
||||
insertCompany("Foo");
|
||||
throw new RuntimeException();
|
||||
}));
|
||||
assertPersonEmpty();
|
||||
assertCompanyEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void transact_reusesExistingTransaction() {
|
||||
assertPersonEmpty();
|
||||
assertCompanyEmpty();
|
||||
txnManager.transact(
|
||||
() ->
|
||||
txnManager.transact(
|
||||
() -> {
|
||||
insertPerson(10);
|
||||
insertCompany("Foo");
|
||||
insertCompany("Bar");
|
||||
}));
|
||||
assertPersonCount(1);
|
||||
assertPersonExist(10);
|
||||
assertCompanyCount(2);
|
||||
assertCompanyExist("Foo");
|
||||
assertCompanyExist("Bar");
|
||||
}
|
||||
|
||||
private void insertPerson(int age) {
|
||||
txnManager
|
||||
.getEntityManager()
|
||||
.createNativeQuery(String.format("INSERT INTO Person (age) VALUES (%d)", age))
|
||||
.executeUpdate();
|
||||
}
|
||||
|
||||
private void insertCompany(String name) {
|
||||
txnManager
|
||||
.getEntityManager()
|
||||
.createNativeQuery(String.format("INSERT INTO Company (name) VALUES ('%s')", name))
|
||||
.executeUpdate();
|
||||
}
|
||||
|
||||
private void assertPersonExist(int age) {
|
||||
txnManager.transact(
|
||||
() -> {
|
||||
EntityManager em = txnManager.getEntityManager();
|
||||
Integer maybeAge =
|
||||
(Integer)
|
||||
em.createNativeQuery(String.format("SELECT age FROM Person WHERE age = %d", age))
|
||||
.getSingleResult();
|
||||
assertThat(maybeAge).isEqualTo(age);
|
||||
});
|
||||
}
|
||||
|
||||
private void assertCompanyExist(String name) {
|
||||
txnManager.transact(
|
||||
() -> {
|
||||
String maybeName =
|
||||
(String)
|
||||
txnManager
|
||||
.getEntityManager()
|
||||
.createNativeQuery(
|
||||
String.format("SELECT name FROM Company WHERE name = '%s'", name))
|
||||
.getSingleResult();
|
||||
assertThat(maybeName).isEqualTo(name);
|
||||
});
|
||||
}
|
||||
|
||||
private void assertPersonCount(int count) {
|
||||
assertThat(countTable("Person")).isEqualTo(count);
|
||||
}
|
||||
|
||||
private void assertCompanyCount(int count) {
|
||||
assertThat(countTable("Company")).isEqualTo(count);
|
||||
}
|
||||
|
||||
private void assertPersonEmpty() {
|
||||
assertPersonCount(0);
|
||||
}
|
||||
|
||||
private void assertCompanyEmpty() {
|
||||
assertCompanyCount(0);
|
||||
}
|
||||
|
||||
private int countTable(String tableName) {
|
||||
return txnManager.transact(
|
||||
() -> {
|
||||
BigInteger colCount =
|
||||
(BigInteger)
|
||||
txnManager
|
||||
.getEntityManager()
|
||||
.createNativeQuery(String.format("SELECT COUNT(*) FROM %s", tableName))
|
||||
.getSingleResult();
|
||||
return colCount.intValue();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.base.Charsets.US_ASCII;
|
||||
import static com.google.common.hash.Funnels.stringFunnel;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.hash.BloomFilter;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.transaction.JpaTransactionManagerRule;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class BloomFilterConverterTest {
|
||||
|
||||
@Rule
|
||||
public final JpaTransactionManagerRule jpaTmRule =
|
||||
new JpaTransactionManagerRule.Builder()
|
||||
.withEntityClass(TestEntity.class)
|
||||
.withProperty(Environment.HBM2DDL_AUTO, "update")
|
||||
.build();
|
||||
|
||||
@Test
|
||||
public void roundTripConversion_returnsSameBloomFilter() {
|
||||
BloomFilter<String> bloomFilter = BloomFilter.create(stringFunnel(US_ASCII), 3);
|
||||
ImmutableSet.of("foo", "bar", "baz").forEach(bloomFilter::put);
|
||||
TestEntity entity = new TestEntity(bloomFilter);
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
|
||||
TestEntity persisted =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "id"));
|
||||
assertThat(persisted.bloomFilter).isEqualTo(bloomFilter);
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
|
||||
public static class TestEntity extends ImmutableObject {
|
||||
|
||||
@Id String name = "id";
|
||||
|
||||
BloomFilter<String> bloomFilter;
|
||||
|
||||
public TestEntity() {}
|
||||
|
||||
public TestEntity(BloomFilter<String> bloomFilter) {
|
||||
this.bloomFilter = bloomFilter;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import google.registry.model.CreateAutoTimestamp;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.transaction.JpaTransactionManagerRule;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class CreateAutoTimestampConverterTest {
|
||||
|
||||
@Rule
|
||||
public final JpaTransactionManagerRule jpaTmRule =
|
||||
new JpaTransactionManagerRule.Builder()
|
||||
.withEntityClass(TestEntity.class)
|
||||
.withProperty(Environment.HBM2DDL_AUTO, "update")
|
||||
.build();
|
||||
|
||||
@Test
|
||||
public void testTypeConversion() {
|
||||
CreateAutoTimestamp ts = CreateAutoTimestamp.create(DateTime.parse("2019-09-9T11:39:00Z"));
|
||||
TestEntity ent = new TestEntity("myinst", ts);
|
||||
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(ent));
|
||||
TestEntity result =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "myinst"));
|
||||
assertThat(result).isEqualTo(new TestEntity("myinst", ts));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutoInitialization() {
|
||||
CreateAutoTimestamp ts = CreateAutoTimestamp.create(null);
|
||||
TestEntity ent = new TestEntity("autoinit", ts);
|
||||
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(ent));
|
||||
|
||||
TestEntity result =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "autoinit"));
|
||||
assertThat(result.cat.getTimestamp()).isEqualTo(jpaTmRule.getTxnClock().nowUtc());
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
|
||||
public static class TestEntity extends ImmutableObject {
|
||||
|
||||
@Id String name;
|
||||
|
||||
CreateAutoTimestamp cat;
|
||||
|
||||
public TestEntity() {}
|
||||
|
||||
public TestEntity(String name, CreateAutoTimestamp cat) {
|
||||
this.name = name;
|
||||
this.cat = cat;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.UpdateAutoTimestamp;
|
||||
import google.registry.model.transaction.JpaTransactionManagerRule;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class UpdateAutoTimestampConverterTest {
|
||||
|
||||
@Rule
|
||||
public final JpaTransactionManagerRule jpaTmRule =
|
||||
new JpaTransactionManagerRule.Builder()
|
||||
.withEntityClass(TestEntity.class)
|
||||
.withProperty(Environment.HBM2DDL_AUTO, "update")
|
||||
.build();
|
||||
|
||||
@Test
|
||||
public void testTypeConversion() {
|
||||
TestEntity ent = new TestEntity("myinst", null);
|
||||
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(ent));
|
||||
|
||||
TestEntity result =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "myinst"));
|
||||
|
||||
assertThat(result.name).isEqualTo("myinst");
|
||||
assertThat(result.uat.getTimestamp()).isEqualTo(jpaTmRule.getTxnClock().nowUtc());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeChangesOnSubsequentTransactions() {
|
||||
TestEntity ent1 = new TestEntity("myinst1", null);
|
||||
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(ent1));
|
||||
|
||||
TestEntity result1 =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "myinst1"));
|
||||
|
||||
jpaTmRule.getTxnClock().advanceOneMilli();
|
||||
|
||||
TestEntity ent2 = new TestEntity("myinst2", result1.uat);
|
||||
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(ent2));
|
||||
|
||||
TestEntity result2 =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "myinst2"));
|
||||
|
||||
assertThat(result1.uat.getTimestamp()).isNotEqualTo(result2.uat.getTimestamp());
|
||||
assertThat(result2.uat.getTimestamp()).isEqualTo(jpaTmRule.getTxnClock().nowUtc());
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
|
||||
public static class TestEntity extends ImmutableObject {
|
||||
|
||||
@Id String name;
|
||||
|
||||
UpdateAutoTimestamp uat;
|
||||
|
||||
public TestEntity() {}
|
||||
|
||||
public TestEntity(String name, UpdateAutoTimestamp uat) {
|
||||
this.name = name;
|
||||
this.uat = uat;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.transaction.JpaTransactionManagerRule;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import java.time.ZonedDateTime;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link ZonedDateTimeConverter}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class ZonedDateTimeConverterTest {
|
||||
|
||||
@Rule
|
||||
public final JpaTransactionManagerRule jpaTmRule =
|
||||
new JpaTransactionManagerRule.Builder()
|
||||
.withEntityClass(TestEntity.class)
|
||||
.withProperty(Environment.HBM2DDL_AUTO, "update")
|
||||
.build();
|
||||
|
||||
private final ZonedDateTimeConverter converter = new ZonedDateTimeConverter();
|
||||
|
||||
@Test
|
||||
public void convertToDatabaseColumn_returnsNullIfInputIsNull() {
|
||||
assertThat(converter.convertToDatabaseColumn(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertToDatabaseColumn_convertsCorrectly() {
|
||||
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2019-09-01T01:01:01Z");
|
||||
assertThat(converter.convertToDatabaseColumn(zonedDateTime).toInstant())
|
||||
.isEqualTo(zonedDateTime.toInstant());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertToEntityAttribute_returnsNullIfInputIsNull() {
|
||||
assertThat(converter.convertToEntityAttribute(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertToEntityAttribute_convertsCorrectly() {
|
||||
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2019-09-01T01:01:01Z");
|
||||
Instant instant = zonedDateTime.toInstant();
|
||||
assertThat(converter.convertToEntityAttribute(Timestamp.from(instant)))
|
||||
.isEqualTo(zonedDateTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void converter_generatesTimestampWithNormalizedZone() {
|
||||
ZonedDateTime zdt = ZonedDateTime.parse("2019-09-01T01:01:01Z");
|
||||
TestEntity entity = new TestEntity("normalized_utc_time", zdt);
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
|
||||
TestEntity retrievedEntity =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> jpaTm().getEntityManager().find(TestEntity.class, "normalized_utc_time"));
|
||||
assertThat(retrievedEntity.zdt.toString()).isEqualTo("2019-09-01T01:01:01Z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void converter_convertsNonNormalizedZoneCorrectly() {
|
||||
ZonedDateTime zdt = ZonedDateTime.parse("2019-09-01T01:01:01Z[UTC]");
|
||||
TestEntity entity = new TestEntity("non_normalized_utc_time", zdt);
|
||||
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
|
||||
TestEntity retrievedEntity =
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> jpaTm().getEntityManager().find(TestEntity.class, "non_normalized_utc_time"));
|
||||
assertThat(retrievedEntity.zdt.toString()).isEqualTo("2019-09-01T01:01:01Z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void converter_convertsNonUtcZoneCorrectly() {
|
||||
ZonedDateTime zdt = ZonedDateTime.parse("2019-09-01T01:01:01+05:00");
|
||||
TestEntity entity = new TestEntity("new_york_time", zdt);
|
||||
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
|
||||
TestEntity retrievedEntity =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "new_york_time"));
|
||||
assertThat(retrievedEntity.zdt.toString()).isEqualTo("2019-08-31T20:01:01Z");
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
|
||||
private static class TestEntity extends ImmutableObject {
|
||||
|
||||
@Id String name;
|
||||
|
||||
ZonedDateTime zdt;
|
||||
|
||||
public TestEntity() {}
|
||||
|
||||
public TestEntity(String name, ZonedDateTime zdt) {
|
||||
this.name = name;
|
||||
this.zdt = zdt;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeLockHandler;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -54,9 +55,11 @@ public class EscrowTaskRunnerTest {
|
||||
private final EscrowTask task = mock(EscrowTask.class);
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
||||
|
||||
private DateTimeZone previousDateTimeZone;
|
||||
private EscrowTaskRunner runner;
|
||||
private Registry registry;
|
||||
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
createTld("lol");
|
||||
@@ -64,9 +67,15 @@ public class EscrowTaskRunnerTest {
|
||||
runner = new EscrowTaskRunner();
|
||||
runner.clock = clock;
|
||||
runner.lockHandler = new FakeLockHandler(true);
|
||||
previousDateTimeZone = DateTimeZone.getDefault();
|
||||
DateTimeZone.setDefault(DateTimeZone.forID("America/New_York")); // Make sure UTC stuff works.
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
DateTimeZone.setDefault(previousDateTimeZone);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_cursorIsToday_advancesCursorToTomorrow() throws Exception {
|
||||
clock.setTo(DateTime.parse("2006-06-06T00:30:00Z"));
|
||||
|
||||
@@ -61,63 +61,40 @@ public class Spec11EmailUtilsTest {
|
||||
|
||||
private static final ImmutableList<String> FAKE_RESOURCES = ImmutableList.of("foo");
|
||||
private static final String DAILY_EMAIL_FORMAT =
|
||||
"Dear registrar partner,"
|
||||
+ ""
|
||||
+ "<p>Super Cool Registry conducts a daily analysis of all domains registered in its "
|
||||
+ "TLDs to identify potential security concerns. On 2018-07-15, the following domains "
|
||||
+ "that your registrar manages were flagged for potential security concerns:</p>"
|
||||
+ ""
|
||||
+ "<table>"
|
||||
+ "<tr><th>Domain Name</th><th>Threat Type</th></tr>"
|
||||
+ "%s"
|
||||
+ "</table>"
|
||||
+ "<p><b>Please communicate these findings to the registrant and work with the "
|
||||
+ "registrant to mitigate any security issues and have the domains delisted.</b></p>"
|
||||
+ ""
|
||||
"Dear registrar partner,<p>Super Cool Registry conducts a daily analysis of all domains"
|
||||
+ " registered in its TLDs to identify potential security concerns. On 2018-07-15, the"
|
||||
+ " following domains that your registrar manages were flagged for potential security"
|
||||
+ " concerns:</p><table><tr><th>Domain Name</th><th>Threat Type</th></tr>%s"
|
||||
+ "</table><p><b>Please communicate these findings to the registrant and work with the"
|
||||
+ " registrant to mitigate any security issues and have the domains delisted.</b></p>"
|
||||
+ "Some helpful resources for getting off a blocked list include:"
|
||||
+ "<ul><li>foo</li></ul><p>"
|
||||
+ ""
|
||||
+ "You will continue to receive daily notices when new domains managed by your registrar "
|
||||
+ "are flagged for abuse, as well as a monthly summary of all of your domains under "
|
||||
+ "management that remain flagged for abuse. Once the registrant has resolved the "
|
||||
+ "security issues and followed the steps to have his or her domain reviewed and "
|
||||
+ "delisted it will automatically be removed from our reporting.</p>"
|
||||
+ ""
|
||||
+ "<p>If you would like to change the email to which these notices are sent please "
|
||||
+ "update your abuse contact using your registrar portal account.</p>"
|
||||
+ ""
|
||||
+ "<p>If you have any questions regarding this notice, please contact "
|
||||
+ "abuse@test.com.</p>";
|
||||
+ "<ul><li>foo</li></ul><p>If you believe that any of the domains were reported in"
|
||||
+ " error, or are still receiving reports for issues that have been remediated, please"
|
||||
+ " <a href=\"https://safebrowsing.google.com/safebrowsing/report_error/?hl=en\">submit"
|
||||
+ " a request</a> to have the site reviewed.</p><p>You will continue to receive daily"
|
||||
+ " notices when new domains managed by your registrar are flagged for abuse, as well as"
|
||||
+ " a monthly summary of all of your domains under management that remain flagged for"
|
||||
+ " abuse.</p><p>If you would like to change the email to which these notices are sent"
|
||||
+ " please update your abuse contact using your registrar portal account.</p><p>If you"
|
||||
+ " have any questions regarding this notice, please contact abuse@test.com.</p>";
|
||||
private static final String MONTHLY_EMAIL_FORMAT =
|
||||
"Dear registrar partner,"
|
||||
+ ""
|
||||
+ "<p>Super Cool Registry previously notified you when the following "
|
||||
+ "domains managed by your registrar were flagged for potential security concerns.</p>"
|
||||
+ "<p>The following domains that you manage continue to be flagged by our analysis "
|
||||
+ "for potential security concerns. This may be because the registrants have not "
|
||||
+ "completed the requisite steps to mitigate the potential security abuse and/or have "
|
||||
+ "it reviewed and delisted.</p>"
|
||||
+ ""
|
||||
+ "<table>"
|
||||
+ "<tr><th>Domain Name</th><th>Threat Type</th></tr>"
|
||||
+ "%s"
|
||||
+ "</table>"
|
||||
+ ""
|
||||
+ "<p>Please work with the registrant to mitigate any security issues "
|
||||
+ "and have the domains delisted.</p>"
|
||||
+ ""
|
||||
+ "Some helpful resources for getting off a blocked list include:"
|
||||
+ "<ul><li>foo</li></ul><p>"
|
||||
+ ""
|
||||
+ "You will continue to receive a monthly summary of all domains managed by your "
|
||||
+ "registrar that remain on our lists of potential security threats. You will "
|
||||
+ "additionally receive a daily notice when any new domains that are added to these "
|
||||
+ "lists. Once the registrant has resolved the security issues and followed the steps to "
|
||||
+ "have his or her domain reviewed and delisted it will automatically be removed from "
|
||||
+ "our monthly reporting.</p>"
|
||||
+ ""
|
||||
+ "<p>If you have any questions regarding this notice, please contact "
|
||||
+ "abuse@test.com.</p>";
|
||||
"Dear registrar partner,<p>Super Cool Registry previously notified you when the following"
|
||||
+ " domains managed by your registrar were flagged for potential security"
|
||||
+ " concerns.</p><p>The following domains that you manage continue to be flagged by our"
|
||||
+ " analysis for potential security concerns. This may be because the registrants have"
|
||||
+ " not completed the requisite steps to mitigate the potential security abuse and/or"
|
||||
+ " have it reviewed and delisted.</p><table><tr><th>Domain Name</th><th>Threat"
|
||||
+ " Type</th></tr>%s</table><p>Please work with the registrant to mitigate any security"
|
||||
+ " issues and have the domains delisted. If you believe that any of the domains were"
|
||||
+ " reported in error, or are still receiving reports for issues that have been"
|
||||
+ " remediated, please <a"
|
||||
+ " href=\"https://safebrowsing.google.com/safebrowsing/report_error/?hl=en\">submit a"
|
||||
+ " request</a> to have the site reviewed.</p>Some helpful resources for getting off a"
|
||||
+ " blocked list include:<ul><li>foo</li></ul><p>You will continue to receive a monthly"
|
||||
+ " summary of all domains managed by your registrar that remain on our lists of"
|
||||
+ " potential security threats. You will also receive a daily notice when any new"
|
||||
+ " domains are added to these lists.</p><p>If you have any questions regarding this"
|
||||
+ " notice, please contact abuse@test.com.</p>";
|
||||
|
||||
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.schema.tld;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.transaction.JpaTransactionManagerRule;
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.PersistenceException;
|
||||
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 PremiumListDao}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class PremiumListDaoTest {
|
||||
|
||||
@Rule
|
||||
public final JpaTransactionManagerRule jpaTmRule =
|
||||
new JpaTransactionManagerRule.Builder().build();
|
||||
|
||||
private static final ImmutableMap<String, BigDecimal> TEST_PRICES =
|
||||
ImmutableMap.of(
|
||||
"silver",
|
||||
BigDecimal.valueOf(10.23),
|
||||
"gold",
|
||||
BigDecimal.valueOf(1305.47),
|
||||
"palladium",
|
||||
BigDecimal.valueOf(1552.78));
|
||||
|
||||
@Test
|
||||
public void saveNew_worksSuccessfully() {
|
||||
PremiumList premiumList = PremiumList.create("testname", CurrencyUnit.USD, TEST_PRICES);
|
||||
PremiumListDao.saveNew(premiumList);
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
PremiumList persistedList =
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery(
|
||||
"SELECT pl FROM PremiumList pl WHERE pl.name = :name", PremiumList.class)
|
||||
.setParameter("name", "testname")
|
||||
.getSingleResult();
|
||||
assertThat(persistedList.getLabelsToPrices()).containsExactlyEntriesIn(TEST_PRICES);
|
||||
assertThat(persistedList.getCreationTimestamp())
|
||||
.isEqualTo(jpaTmRule.getTxnClock().nowUtc());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveNew_throwsWhenPremiumListAlreadyExists() {
|
||||
PremiumListDao.saveNew(PremiumList.create("testlist", CurrencyUnit.USD, TEST_PRICES));
|
||||
PersistenceException thrown =
|
||||
assertThrows(
|
||||
PersistenceException.class,
|
||||
() ->
|
||||
PremiumListDao.saveNew(
|
||||
PremiumList.create("testlist", CurrencyUnit.USD, TEST_PRICES)));
|
||||
assertThat(thrown)
|
||||
.hasCauseThat()
|
||||
.hasMessageThat()
|
||||
.contains("A premium list of this name already exists");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkExists_worksSuccessfully() {
|
||||
assertThat(PremiumListDao.checkExists("testlist")).isFalse();
|
||||
PremiumListDao.saveNew(PremiumList.create("testlist", CurrencyUnit.USD, TEST_PRICES));
|
||||
assertThat(PremiumListDao.checkExists("testlist")).isTrue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.schema.tld;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.hash.BloomFilter;
|
||||
import java.math.BigDecimal;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link PremiumList}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class PremiumListTest {
|
||||
|
||||
private static final ImmutableMap<String, BigDecimal> TEST_PRICES =
|
||||
ImmutableMap.of(
|
||||
"silver",
|
||||
BigDecimal.valueOf(10.23),
|
||||
"gold",
|
||||
BigDecimal.valueOf(1305.47),
|
||||
"palladium",
|
||||
BigDecimal.valueOf(1552.78));
|
||||
|
||||
@Test
|
||||
public void bloomFilter_worksCorrectly() {
|
||||
BloomFilter<String> bloomFilter =
|
||||
PremiumList.create("testname", CurrencyUnit.USD, TEST_PRICES).getBloomFilter();
|
||||
ImmutableSet.of("silver", "gold", "palladium")
|
||||
.forEach(l -> assertThat(bloomFilter.mightContain(l)).isTrue());
|
||||
ImmutableSet.of("dirt", "pyrite", "zirconia")
|
||||
.forEach(l -> assertThat(bloomFilter.mightContain(l)).isFalse());
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ package google.registry.security;
|
||||
|
||||
import static com.google.common.base.Suppliers.memoize;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.security.JsonHttp.JSON_SAFETY_PREFIX;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
@@ -62,7 +62,7 @@ public final class JsonHttpTestUtils {
|
||||
Map<String, Object> json = (Map<String, Object>) JSONValue.parseWithException(jsonText);
|
||||
return json;
|
||||
} catch (ClassCastException | ParseException e) {
|
||||
assert_().fail("Bad JSON: %s\n%s", e.getMessage(), jsonText);
|
||||
assertWithMessage("Bad JSON: %s\n%s", e.getMessage(), jsonText).fail();
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
package google.registry.testing;
|
||||
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.testing.DatastoreHelper.persistSimpleResources;
|
||||
import static google.registry.util.ResourceUtils.readResourceUtf8;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
@@ -338,7 +338,7 @@ public final class AppEngineRule extends ExternalResource {
|
||||
Set<String> autoIndexes = getIndexXmlStrings(indexFileContent);
|
||||
Set<String> missingIndexes = Sets.difference(autoIndexes, MANUAL_INDEXES);
|
||||
if (!missingIndexes.isEmpty()) {
|
||||
assert_().fail("Missing indexes:\n%s", Joiner.on('\n').join(missingIndexes));
|
||||
assertWithMessage("Missing indexes:\n%s", Joiner.on('\n').join(missingIndexes)).fail();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
|
||||
@@ -57,6 +57,7 @@ public final class FakeKeyringModule {
|
||||
private static final String MARKSDB_SMDRL_LOGIN_AND_PASSWORD = "smdrl:yolo";
|
||||
private static final String JSON_CREDENTIAL = "json123";
|
||||
private static final String CLOUD_SQL_PASSWORD = "cloudsqlpw";
|
||||
private static final String TOOLS_CLOUD_SQL_PASSWORD = "toolscloudsqlpw";
|
||||
|
||||
@Provides
|
||||
public Keyring get() {
|
||||
@@ -86,6 +87,11 @@ public final class FakeKeyringModule {
|
||||
return CLOUD_SQL_PASSWORD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolsCloudSqlPassword() {
|
||||
return TOOLS_CLOUD_SQL_PASSWORD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PGPPublicKey getRdeStagingEncryptionKey() {
|
||||
return rdeStagingKey.getPublicKey();
|
||||
|
||||
@@ -16,7 +16,7 @@ package google.registry.testing;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.testing.TestDataHelper.filePath;
|
||||
import static google.registry.testing.TestDataHelper.loadFile;
|
||||
|
||||
@@ -80,13 +80,12 @@ public class GoldenFileTestHelper {
|
||||
logger.atWarning().log(
|
||||
"Actual routing map was:\n%s\n\nExpected routing map was:\n%s\n",
|
||||
actualValue, expectedValue);
|
||||
assert_()
|
||||
.fail(
|
||||
String.format(
|
||||
UPDATE_INSTRUCTIONS,
|
||||
nomulusCommand,
|
||||
filePath(context, filename),
|
||||
goldenFileDescription));
|
||||
assertWithMessage(
|
||||
UPDATE_INSTRUCTIONS,
|
||||
nomulusCommand,
|
||||
filePath(context, filename),
|
||||
goldenFileDescription)
|
||||
.fail();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.Iterables.getFirst;
|
||||
import static com.google.common.collect.Multisets.containsOccurrences;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static com.google.common.truth.Truth8.assertThat;
|
||||
import static google.registry.util.DiffUtils.prettyPrintEntityDeepDiff;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
@@ -236,13 +236,11 @@ public class TaskQueueHelper {
|
||||
taskInfos.remove(taskInfos.stream().filter(taskMatcher).findFirst().get());
|
||||
} catch (NoSuchElementException e) {
|
||||
final Map<String, Object> taskMatcherMap = taskMatcher.expected.toMap();
|
||||
assert_()
|
||||
.fail(
|
||||
assertWithMessage(
|
||||
"Task not found in queue %s:\n\n%s\n\nPotential candidate match diffs:\n\n%s",
|
||||
queueName,
|
||||
taskMatcher,
|
||||
taskInfos
|
||||
.stream()
|
||||
taskInfos.stream()
|
||||
.map(
|
||||
input ->
|
||||
prettyPrintEntityDeepDiff(
|
||||
@@ -250,7 +248,8 @@ public class TaskQueueHelper {
|
||||
Maps.filterKeys(
|
||||
new MatchableTaskInfo(input).toMap(),
|
||||
in(taskMatcherMap.keySet()))))
|
||||
.collect(joining("\n")));
|
||||
.collect(joining("\n")))
|
||||
.fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
package google.registry.testing;
|
||||
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.testing.TestLogHandler;
|
||||
@@ -49,6 +49,6 @@ public final class TestLogHandlerUtils {
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert_().fail(String.format("Log message \"%s\" not found", message));
|
||||
assertWithMessage("Log message \"%s\" not found", message).fail();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,13 @@ public class CreatePremiumListCommandTest<C extends CreatePremiumListCommand>
|
||||
verifySentParams(
|
||||
connection,
|
||||
servletPath,
|
||||
ImmutableMap.of("name", "foo", "inputData", generateInputData(premiumTermsPath)));
|
||||
ImmutableMap.of(
|
||||
"name",
|
||||
"foo",
|
||||
"inputData",
|
||||
generateInputData(premiumTermsPath),
|
||||
"alsoCloudSql",
|
||||
"false"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -78,7 +84,28 @@ public class CreatePremiumListCommandTest<C extends CreatePremiumListCommand>
|
||||
connection,
|
||||
servletPath,
|
||||
ImmutableMap.of(
|
||||
"name", "example_premium_terms", "inputData", generateInputData(premiumTermsPath)));
|
||||
"name",
|
||||
"example_premium_terms",
|
||||
"inputData",
|
||||
generateInputData(premiumTermsPath),
|
||||
"alsoCloudSql",
|
||||
"false"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_alsoCloudSql() throws Exception {
|
||||
runCommandForced("-i=" + premiumTermsPath, "-n=foo", "--also_cloud_sql");
|
||||
assertInStdout("Successfully");
|
||||
verifySentParams(
|
||||
connection,
|
||||
servletPath,
|
||||
ImmutableMap.of(
|
||||
"name",
|
||||
"foo",
|
||||
"inputData",
|
||||
generateInputData(premiumTermsPath),
|
||||
"alsoCloudSql",
|
||||
"true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -57,7 +57,13 @@ public class UpdatePremiumListCommandTest<C extends UpdatePremiumListCommand>
|
||||
verifySentParams(
|
||||
connection,
|
||||
servletPath,
|
||||
ImmutableMap.of("name", "foo", "inputData", generateInputData(premiumTermsPath)));
|
||||
ImmutableMap.of(
|
||||
"name",
|
||||
"foo",
|
||||
"inputData",
|
||||
generateInputData(premiumTermsPath),
|
||||
"alsoCloudSql",
|
||||
"false"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -68,6 +74,11 @@ public class UpdatePremiumListCommandTest<C extends UpdatePremiumListCommand>
|
||||
connection,
|
||||
servletPath,
|
||||
ImmutableMap.of(
|
||||
"name", "example_premium_terms", "inputData", generateInputData(premiumTermsPath)));
|
||||
"name",
|
||||
"example_premium_terms",
|
||||
"inputData",
|
||||
generateInputData(premiumTermsPath),
|
||||
"alsoCloudSql",
|
||||
"false"));
|
||||
}
|
||||
}
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
// Copyright 2017 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.tools.server;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth8.assertThat;
|
||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||
|
||||
import google.registry.schema.tld.PremiumList;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeJsonResponse;
|
||||
import java.math.BigDecimal;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link CreateOrUpdatePremiumListAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class CreateOrUpdatePremiumListActionTest {
|
||||
|
||||
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||
|
||||
private CreatePremiumListAction action;
|
||||
private FakeJsonResponse response;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
action = new CreatePremiumListAction();
|
||||
response = new FakeJsonResponse();
|
||||
action.response = response;
|
||||
action.name = "testlist";
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseInputToPremiumList_works() {
|
||||
action.inputData = "foo,USD 99.50\n" + "bar,USD 30\n" + "baz,USD 10\n";
|
||||
PremiumList premiumList = action.parseInputToPremiumList();
|
||||
assertThat(premiumList.getName()).isEqualTo("testlist");
|
||||
assertThat(premiumList.getLabelsToPrices())
|
||||
.containsExactly("foo", twoDigits(99.50), "bar", twoDigits(30), "baz", twoDigits(10));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseInputToPremiumList_throwsOnInconsistentCurrencies() {
|
||||
action.inputData = "foo,USD 99.50\n" + "bar,USD 30\n" + "baz,JPY 990\n";
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(IllegalArgumentException.class, () -> action.parseInputToPremiumList());
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo("The Cloud SQL schema requires exactly one currency, but got: [JPY, USD]");
|
||||
}
|
||||
|
||||
private static BigDecimal twoDigits(double num) {
|
||||
return BigDecimal.valueOf((long) (num * 100.0), 2);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
package google.registry.xml;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.util.DiffUtils.prettyPrintXmlDeepDiff;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
@@ -49,17 +49,15 @@ public class XmlTestUtils {
|
||||
public static void assertXmlEqualsWithMessage(
|
||||
String expected, String actual, String message, String... ignoredPaths) throws Exception {
|
||||
if (!actual.startsWith("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")) {
|
||||
assert_().fail("XML declaration not found at beginning:\n%s", actual);
|
||||
assertWithMessage("XML declaration not found at beginning:\n%s", actual).fail();
|
||||
}
|
||||
Map<String, Object> expectedMap = toComparableJson(expected, ignoredPaths);
|
||||
Map<String, Object> actualMap = toComparableJson(actual, ignoredPaths);
|
||||
if (!expectedMap.equals(actualMap)) {
|
||||
assert_().fail(String.format(
|
||||
"%s: Expected:\n%s\n\nActual:\n%s\n\nDiff:\n%s\n\n",
|
||||
message,
|
||||
expected,
|
||||
actual,
|
||||
prettyPrintXmlDeepDiff(expectedMap, actualMap, null)));
|
||||
assertWithMessage(
|
||||
"%s: Expected:\n%s\n\nActual:\n%s\n\nDiff:\n%s\n\n",
|
||||
message, expected, actual, prettyPrintXmlDeepDiff(expectedMap, actualMap, null))
|
||||
.fail();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user