1
0
mirror of https://github.com/google/nomulus synced 2026-01-28 16:42:18 +00:00

Compare commits

...

52 Commits

Author SHA1 Message Date
Ben McIlwain
8a06ef09c0 Add a new method to load all Registry entities of a given type (#373)
* Add a new method to load all Registry entities of a given type

This is useful for things that need to know more than just the TLD strings
themselves, which is all Registries currently provides.
2019-11-18 17:40:42 -05:00
Shicong Huang
9e0368b77c Enable JpaTransactionManager in all environment (#352)
* Enable JpaTransactionManager in all environment

* Refactor to have a single place to create JpaTm
2019-11-18 14:53:49 -05:00
Weimin Yu
05c45da07a Use psql 11 docker image in all tests (#372)
* Use psql 11 docker image in all tests
2019-11-18 14:08:58 -05:00
Weimin Yu
365c5da942 Require explict tag when starting psql docker (#368)
* Require explict tag when starting psql docker

Defined a util class to return docker tag of desired PSQL version.
Class is defined in ':db' and shared by ':db' and ':core'. Used
an artifact declaration to exclude unnecesary compile dependencies.

Added a presubmit check for instantiations without explicit tag.
2019-11-18 11:33:26 -05:00
Weimin Yu
2cc2571375 Update schema deployment doc and flyway tool (#363)
* Update schema deployment doc and flyway tool

Disabled Flyway Gradle tasks with side effects on Cloud SQL
instances. They can still be used on local databases.

Also switched Flyway Gradle tasks to get credentials from
new locations (in domain-registry-dev).

Updated README file on schema push process. Also reformatted
the entire file.
2019-11-15 11:44:21 -05:00
Lai Jiang
d55230933b Upgrade to Gradle 6.0 (#364) 2019-11-13 13:17:29 -05:00
Shicong Huang
09aef04117 Add PersistenceXmlUtility and refactor related code (#357)
* Refactor GenerateSqlSchemaCommand

* Add and throw UncheckedClassNotFoundException
2019-11-12 15:08:54 -05:00
gbrodman
a392100852 Add by-repo-id method to RegistryLockDao (#344)
* Add by-repo-id method to RegistryLockDao

When we create new registry lock objects on user request, we will want
to make sure that there are no pending lock/unlock actions on this
domain. In order to do that, we will need to know what lock actions
there have been for this domain.

* Inline the query into a single statement

* whoops

* comments
2019-11-12 11:47:59 -05:00
Weimin Yu
b005e3aeb0 Fix a few lint errors (#361)
Replace deprecated bouncycastle class in SslInitializerTestUils.

Generic array as vargs: worked around it in ProbingAction and
removed unused method in CircularList.
2019-11-12 11:14:51 -05:00
Weimin Yu
bce09a3aa3 Deploy SQL schema from Cloud Build (#350)
Defined Docker image for schema deployment.

Included schema deploymer docker in the Cloud Build release process.

Defined Cloud Build config for schema deployment.

TESTED=Used cloud-build-local to test deployment flow
TESTED=Used docker to test schema deployer image in more ways
2019-11-12 11:06:16 -05:00
Weimin Yu
cb87658827 Remove unnecessary usage of CircularList (#358)
Implementation of CircularList is an overkill for its stated
purpose. Remove an unnecessary usage so that the remaining
use case may be refactored in isolation.
2019-11-11 18:04:46 -05:00
Michael Muller
455daae25c Add converter for DateTime (#346)
* Add converter for DateTime

* Added to sql integration test suite

* Removed obsolete "auto update schema" property
2019-11-11 17:24:20 -05:00
gbrodman
dea7dfcf28 Refactor UI actions to be more reliable (#348)
* Refactor UI actions to be more reliable

- Created HtmlAction to handle the nitty-gritty of login and setting up
HTML pages
- Created a test to verify that all UI actions implement JSON GET, JSON
POST, or HTML classes
- Move CSS renaming into a utility class

* Move logging of request into HtmlAction

* Comment and wording in exception

* mention JsonGetAction in the comment

* JsonGetAction extends Runnable
2019-11-11 16:18:48 -05:00
Shicong Huang
3a47fa2fe9 Fix beam pipeline deployment issue (#360) 2019-11-11 15:57:33 -05:00
gbrodman
0b7a0ba99d Update puppeteer (#359)
* Update puppeteer

They released 2.0.0 which fixes the security vuln in https-proxy-agent
2019-11-11 15:38:44 -05:00
gbrodman
ae89a8b76f Run both the AppEngineRule and JpaTransactionManagerRule in tests (#356)
* Run both the AppEngineRule and JpaTransactionManagerRule in tests

As previously written, the AppEngineRule wraps the infinite loop of the
server handling requests. This changes the code so that we'll have a
chain that does both the AppEngine management and the JPA transaction
manager management so we can actually use SQL in tests and in the test
server.

* remove log line
2019-11-11 11:26:20 -05:00
Shicong Huang
f0345ddf89 Resolve test flakiness caused by connection leak (#355) 2019-11-08 15:40:27 -05:00
Weimin Yu
e9f20b3401 Delete obsolet gradle config in root project (#354)
* Delete obsolet gradle config in root project
2019-11-08 14:32:08 -05:00
Lai Jiang
64e7a593ef Make Joda Money embeddable in entities (#340) 2019-11-07 17:03:00 -05:00
gbrodman
135ab66e55 Throw an EPP exception when using discount on premium domains (#351)
We should communicate to the users why this command failed, that they
are not allowed to use discounted allocation tokens on premium domains.
Currently it still fails, but we don't yet tell them why.
2019-11-07 15:30:23 -05:00
sarahcaseybot
69acb9f6de Add cursors for tracking ICANN report uploads to Cursor.java (#349) 2019-11-07 10:49:21 -05:00
gbrodman
5359f4640a Clean up Karma config file (#345)
Because we moved it into the source dirs, we don't need to reference
soyutils_usegoog.js separately
2019-11-06 10:33:58 -05:00
gbrodman
5c2856e3e2 Add RegistryLockGetActionTest to SQL testclasses (#347) 2019-11-05 15:10:13 -05:00
gbrodman
86e1fb85b6 Add a GET action and tests for registry lock retrieval (#326)
* Add a GET action and tests for registry lock retrieval

* Create isVerified method

* Allow lock access for admins even if they're not enabled on the registrar

* Simple CR responses

* Move locks retrieval to the GET action

* add newline at eof

* Switch to using ID
2019-11-05 13:19:32 -05:00
Michael Muller
301ab54fb4 Improve FilteringTest so it works in all cases (#339)
* Improve FilteringTest so it works in all cases

- Disable failOnMatchingTests so we don't fail if we filter out all of the
  tests for any given task.
- Add excludeTestCases flag so that we can turn this behavior off for test
  tasks that need to run TestCas/TestSuite classes.
- Add includeAllTests() function for test tasks where we don't explicitly
  include our required tests.

This makes all test tasks in core FilteringTest, with the exception of the
default test task which now does nothing (it just depends on the other test
tasks).

* Improve wording of excludeTestCases comment
2019-11-05 12:04:56 -05:00
Shicong Huang
2c6d71f04c Prevent test from changing golden schema (#337)
When we add the extra test entity to the current JpaTransactionManagerRule by calling jpaRule.withEntityClass(TestEntity.class) and jpaRule.withProperty(Environment.HBM2DDL_AUTO, "update"), the rule would override the golden database scheme with the schema derived from the current entity class(This is an expected behavior by enabling HBM2DDL_AUTO). This behavior prevents us from detecting breaking changes in ORM classes.

This PR fixed the issue by adding HibernateSchemaExporter to export the DDL script for given extra entity class, and make JpaTransactionManagerRule execute the DDL script to create the corresponding table for the extra entity when initializing the database. This PR also simplified the code when adding extra entity class for testing. For now, you don't need to(and shouldn't) call jpaRule.withProperty(Environment.HBM2DDL_AUTO, "update").
2019-11-05 11:36:03 -05:00
Shicong Huang
ee4e6ace2a Remove jdbcUrl config for nomulus tool (#330) 2019-11-05 10:33:53 -05:00
Lai Jiang
c4721121eb Move soyutils_usegoog.js out of node_modules (#342)
* Move soyutils_usegoog.js out of node_modules

Everytime the npmInstall runs, it removes this file from node_modules.
Move it outside the folder to prevent this from happening.

* Move karma.conf.js and soyutils_usegooge.js

* Move karma.conf.js to be under core
2019-11-04 15:22:32 -05:00
Weimin Yu
37b9999cfc Release SQL schema in Cloud Build (#341)
* Release SQL schema in Cloud Build

Tentatively release SQL schema at the same time as the server release.
Publish schema jar to gs://domain-registry-maven-repository/nomulus
and also upload it with server artifacts.

Also removed the Gradle 'version' variable which is not used.

Tested=On cloud-build with a simplified version of
cloudbuild-nomulus.yaml.
2019-11-04 10:22:05 -05:00
Ben McIlwain
5f62f91cd5 Don't wrap exceptions thrown inside Cloud SQL transactions (#338)
* Don't wrap exceptions thrown inside Cloud SQL transactions

There's no reason to wrap them in PersistenceException, and it makes dealing
with thrown exceptions harder as seen in the diffs on test classes in this
commit.
2019-11-03 14:08:31 -05:00
sarahcaseybot
6f87fc115f Don't allow generation of allocation tokens for invalid domain names (#327)
* Address comments

* Delete client name change

* Delete skaffold.yaml
2019-11-01 12:19:10 -04:00
Lai Jiang
aaca6651c8 Make compilation work on Windows (#331)
* Make the Gradle upload plugin work on Windows

* Remove the bash script to generate package-info.java file

* Minor changes to the format
2019-10-31 17:04:35 -04:00
Ben McIlwain
03bbb2c057 Add a converter for CurrencyUnits stored in the database (#334)
* Add a converter for CurrencyUnits stored in the database

This uses the well-known String representation for currency units. It also
provides a base class for other converters that will be persisting the
toString() representation.

* Add DB and formatting changes

* Add tests, make minor fixes
2019-10-31 15:26:40 -04:00
Shicong Huang
d00ade8ae0 Enable JpaTransactionManager in sandbox (#323)
* Enable JpaTransactionManager in sandbox
2019-10-31 14:23:38 -04:00
Ben McIlwain
5e61adb396 Make the DB update instructions more comprehensive (#335)
* Make the DB update instructions more comprehensive

They were missing some initial steps.
2019-10-31 14:07:57 -04:00
Weimin Yu
6fe9cced3e Save current deployment tag for every environment (#332)
* Save release tag during deployment

* Save current tag for every environment

Store tag of the current deployment in each environment.
This is used by the server-sql compatibility test.

* Save current tag for every environment

Store tag of the current deployment in each environment.
This is used by the server-sql compatibility test.
2019-10-30 13:58:56 -04:00
Shicong Huang
6a3bd9418f Upgrade org.apache.beam related packages to latest version (#333) 2019-10-30 11:44:26 -04:00
Lai Jiang
3106958f18 Instrument proxy frontend latency metric (#320)
* Instrument proxy frontend latency metric

Backend latency only captures the time spent waiting for the GAE backend
to respond to a request, which is not representitive of what clients
experience. For instance it does not take into account the time the
proxy spends on processing the requests and the time it takes to send a
response to the client.

This PR adds a metric for frontend latency, which is the time spent on
answering a client request. This should serve as a better proxy for the
latency clients observe.

* Rename AbstractMetrics to BaseMetrics
2019-10-29 16:02:47 -04:00
Weimin Yu
7da94c90dc Restrict "Public Domain" license acceptance (#329)
"Public Domain" license must be reviewed case by case.
Removed blanket acceptance and named accepted dependencies
individually.

Also added a README file to warn about this license and WTFPL.
2019-10-28 13:32:42 -04:00
Ben McIlwain
dbb4092680 Don't retry permanent failures when uploading ICANN monthly reports (#328)
* Don't retry permanent failures when uploading ICANN monthly reports

There are two kinds of permanent failures that this checks for that we know will
never succeed, so it makes no sense to continue retrying 11 more times before
moving onto the next file to upload. These errors are:

1.
com.google.api.client.http.HttpResponseException: 403
Your IP address xx.xx.xx.xx is not allowed to connect

2.
com.google.api.client.http.HttpResponseException: 400
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><response xmlns="urn:ietf:params:xml:ns:iirdea-1.0"><result code="2002"><msg>A report for that month already exists, the cut-off date already passed.</msg><description>Date: 2019-09</description></result></response>

In order to implement this new functionality, this commit also adds a new way to
call Retriable that allows specifying the isRetryable Predicate (which is quite
useful).
2019-10-25 13:54:47 -04:00
Weimin Yu
af3223d086 Add a test task for all schema-dependent tests (#325)
Such tests are used in server-schema compatibility tests.

Also added a test that verifies that all eligible tests
are included.
2019-10-25 13:25:01 -04:00
Shicong Huang
2d7f80baaf Fix issues related to Cloud SQL connection (#321)
* Reenable JpaTransactionManager for Alpha and Crash

* Make UploadClaimsListCommand implement CommandWithCloudSql

* Fix wrong call to get password

* Use Cloud SQL Socket library to provision TransactionManager

* Change to use dataSource configs
2019-10-25 12:40:43 -04:00
gbrodman
d4d5d6a570 Add another test contact for Registry Lock testing (#324)
* Add another test contact for Registry Lock testing

Previously, we only had two contacts -- one per registrar. This PR adds
a second, registry-lock-enabled, contact to one registrar for two
reasons:

1. For registry-lock-related testing, we'd like to be able to test both
positively and negatively, making sure that the permissions work the way
they should
2. In general, the UI tests should include the case where we have
multiple contacts in the same registrar. Previously, this was never the
case in tests.

* Merge remote-tracking branch 'origin/master' into addTestContact
2019-10-25 10:24:59 -04:00
gbrodman
53c0be6537 Don't destroy existing registry lock passwords in contacts (#317)
* Don't destroy existing registry lock passwords in contacts

The existing code assumes that the "contacts" segment of the form
contains an exact representation of the registrar contacts. This breaks
when we have a contact with an existing registry lock password because
we don't want to keep passing around that password in plain text (we
never store it in plain text)

This PR changes the code so that instead of assuming the contact is
provided in its entirety, we load the contact from storage first
(matching by email address) if it exists. We then set the required
fields from the JSON object, and set the password optionally if it was
provided.

Alternatives:
- Create a separate RegistrarContactPassword object with a
RegistrarContact parent. This increases complexity significantly since
we'd be adding a parent-child relationship and adding more objects to
Datastore during the transition to SQL. It also doesn't completely solve
the problem of "When should we set the password?" because the password
field still must be part of the same form.
- Rearrange the UI so that the password is set as part of a completely
separate form with a separate submit action. This would be possible but
is sub-optimal for two reasons. First, we are trying to not re-engineer
the web console as much as possible since we're likely starting it from
scratch before too long anyway. Second, we want the
lock-password-setting to be part of the standard contact modification
workflow.

* Responses to CR

* Actually we need to allow "removal" of fields

* Remove optional

* one-statement building the contacts
2019-10-24 20:18:37 -04:00
gbrodman
63bb2dd79b Don't include password hash + salt in visible diffs (#322)
We don't want to override toDiffableFieldMap because (per the javadoc)
that is supposed to contain sensitive information. So, we should just
remove it before sending it out.
2019-10-23 10:57:46 -07:00
gbrodman
8278b5409e Add a registrarId index to RegistryLock (#312)
* Add a registrarId index to RegistryLock

* Merge remote-tracking branch 'origin/master' into getByRegistrar

* Responses to CR
2019-10-23 06:51:20 -07:00
gbrodman
f98b0f8739 Use merge instead of persist for RegistryLockDao (#310)
* Use merge instead of persist for RegistryLockDao

* CR responses
2019-10-22 12:21:32 -07:00
gbrodman
128fde16c3 Fix security alerts by upgrading (#318)
Note: this will be incomplete until Puppeteer releases a new version as
we await their https-proxy-agent version bump
2019-10-21 14:17:03 -07:00
Lai Jiang
45f7c89efd Upgrade to Gradle 5.6.3 (#315) 2019-10-18 15:13:46 -07:00
Weimin Yu
13dc758747 Use base64-encoded SQL credentials (#314)
* Use base64-encoded SQL credentials

Encode Cloud SQL credential files on gcs with base64,
to be consistent with our Cloud Build practices.

Also renamed a property that specifies where to publish
the schema jar. New name is schema_publish_repo.
2019-10-18 11:48:40 -04:00
Shicong Huang
85c11ca889 Use a single database container for all tests (#313) 2019-10-15 15:09:03 -04:00
sarahcaseybot
340bf40642 Update Spec11 email template (#308)
* Changes to Spec11 notice email.

* Fix lines that were too long
2019-10-14 12:23:28 -04:00
237 changed files with 5469 additions and 4252 deletions

1
.gitignore vendored
View File

@@ -98,7 +98,6 @@ nomulus.iws
.gradle/
**/build
node_modules/**
!node_modules/soyutils_usegoog.js
/repos/
# Compiled JS/CSS code

View File

@@ -34,7 +34,7 @@ buildscript {
plugins {
// Java static analysis plugins. Keep versions consistent with
// ./buildSrc/build.gradle
id 'nebula.lint' version '10.4.2'
id 'nebula.lint' version '16.0.2'
// TODO(weiminyu): consider remove net.ltgt.apt. Gradle 5.2+
// has similar functionalities.
id 'net.ltgt.apt' version '0.19' apply false
@@ -46,7 +46,7 @@ plugins {
id "com.moowork.node" version "1.2.0"
id 'idea'
id 'com.diffplug.gradle.spotless' version '3.18.0'
id 'com.diffplug.gradle.spotless' version '3.25.0'
id 'jacoco'
}
@@ -288,20 +288,6 @@ subprojects {
}
}
}
if (['util', 'proxy', 'core', 'prober', 'db'].contains(project.name)) return
// TODO(weiminyu): investigate if the block below is still needed
ext.relativePath = "google/registry/${project.name}"
sourceSets.each {
it.java {
include "${project.relativePath}/"
}
it.resources {
include "${project.relativePath}/"
}
}
}
// If "-P verboseTestOutput=true" is passed in, configure all subprojects to dump all of their

View File

@@ -23,13 +23,13 @@ buildscript {
plugins {
// Java static analysis plugins. Keep versions consistent with ../build.gradle
id 'nebula.lint' version '10.4.2'
id 'nebula.lint' version '16.0.2'
// Config helper for annotation processors such as AutoValue and Dagger.
// Ensures that source code is generated at an appropriate location.
id 'net.ltgt.apt' version '0.19' apply false
id 'net.ltgt.errorprone' version '0.6.1'
id 'checkstyle'
id 'com.diffplug.gradle.spotless' version '3.18.0'
id 'com.diffplug.gradle.spotless' version '3.25.0'
}
if (rootProject.enableDependencyLocking.toBoolean()) {

View File

@@ -1,60 +1,44 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
cglib:cglib-nodep:3.2.2
com.diffplug.durian:durian-collect:1.2.0
com.diffplug.durian:durian-core:1.2.0
com.diffplug.durian:durian-io:1.2.0
com.diffplug.gradle.spotless:com.diffplug.gradle.spotless.gradle.plugin:3.18.0
com.diffplug.spotless:spotless-lib-extra:1.18.0
com.diffplug.spotless:spotless-lib:1.18.0
com.diffplug.spotless:spotless-plugin-gradle:3.18.0
com.diffplug.gradle.spotless:com.diffplug.gradle.spotless.gradle.plugin:3.25.0
com.diffplug.spotless:spotless-lib-extra:1.25.0
com.diffplug.spotless:spotless-lib:1.25.0
com.diffplug.spotless:spotless-plugin-gradle:3.25.0
com.google.guava:guava:19.0
com.googlecode.concurrent-trees:concurrent-trees:2.6.1
com.googlecode.javaewah:JavaEWAH:1.1.6
com.jcraft:jsch:0.1.54
com.jcraft:jsch:0.1.55
com.jcraft:jzlib:1.1.1
com.netflix.nebula:gradle-lint-plugin:10.4.2
com.netflix.nebula:gradle-lint-plugin:16.0.2
com.netflix.nebula:nebula-gradle-interop:1.0.11
com.netflix.nebula:nebula-test:7.3.0
commons-codec:commons-codec:1.9
commons-io:commons-io:2.5
commons-lang:commons-lang:2.6
commons-logging:commons-logging:1.2
javax.inject:javax.inject:1
junit:junit:4.12
log4j:log4j:1.2.14
nebula.lint:nebula.lint.gradle.plugin:10.4.2
nebula.lint:nebula.lint.gradle.plugin:16.0.2
net.ltgt.apt:net.ltgt.apt.gradle.plugin:0.19
net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:0.6.1
net.ltgt.gradle:gradle-apt-plugin:0.19
net.ltgt.gradle:gradle-errorprone-plugin:0.6.1
org.apache.ant:ant-antlr:1.8.4
org.apache.ant:ant-junit:1.8.4
org.apache.ant:ant-launcher:1.8.4
org.apache.ant:ant:1.8.4
org.apache.commons:commons-lang3:3.8.1
org.apache.httpcomponents:httpclient:4.5.2
org.apache.httpcomponents:httpcore:4.4.4
org.apache.maven:maven-artifact:3.6.2
org.apache.maven:maven-builder-support:3.6.2
org.apache.maven:maven-model-builder:3.6.2
org.apache.maven:maven-model:3.6.2
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcpkix-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.codehaus.gpars:gpars:1.2.1
org.codehaus.groovy:groovy-all:2.4.9
org.codehaus.groovy:groovy-ant:2.1.8
org.codehaus.groovy:groovy-groovydoc:2.1.8
org.codehaus.groovy:groovy-templates:2.1.8
org.codehaus.groovy:groovy-xml:2.4.7
org.codehaus.groovy:groovy:2.4.7
org.codehaus.jsr166-mirror:jsr166y:1.7.0
org.codehaus.plexus:plexus-interpolation:1.25
org.codehaus.plexus:plexus-utils:3.2.1
org.codenarc:CodeNarc:0.25.2
org.eclipse.jdt:core:3.1.1
org.eclipse.jgit:org.eclipse.jgit:5.0.1.201806211838-r
org.eclipse.jgit:org.eclipse.jgit:5.5.0.201909110433-r
org.eclipse.sisu:org.eclipse.sisu.inject:0.3.3
org.gmetrics:GMetrics:0.7
org.hamcrest:hamcrest-core:1.3
org.jetbrains.kotlin:kotlin-stdlib-common:1.3.50
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50
@@ -62,7 +46,8 @@ org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.50
org.jetbrains.kotlin:kotlin-stdlib:1.3.50
org.jetbrains:annotations:13.0
org.multiverse:multiverse-core:0.7.0
org.objenesis:objenesis:2.4
org.ow2.asm:asm:7.0
org.ow2.asm:asm-analysis:7.1
org.ow2.asm:asm-commons:7.1
org.ow2.asm:asm-tree:7.1
org.ow2.asm:asm:7.1
org.slf4j:slf4j-api:1.7.2
org.spockframework:spock-core:1.1-groovy-2.4-rc-4

View File

@@ -3,16 +3,16 @@
# This file is expected to be part of source control.
antlr:antlr:2.7.7
com.google.code.findbugs:jsr305:3.0.2
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.0.1-jre
com.google.guava:guava:28.0-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.puppycrawl.tools:checkstyle:8.17
commons-beanutils:commons-beanutils:1.9.3
com.google.j2objc:j2objc-annotations:1.3
com.puppycrawl.tools:checkstyle:8.24
commons-beanutils:commons-beanutils:1.9.4
commons-collections:commons-collections:3.2.2
info.picocli:picocli:3.9.0
net.sf.saxon:Saxon-HE:9.9.0-2
info.picocli:picocli:4.0.3
net.sf.saxon:Saxon-HE:9.9.1-4
org.antlr:antlr4-runtime:4.7.2
org.checkerframework:checker-qual:2.5.2
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.17

View File

@@ -1,4 +1,4 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.4
org.jacoco:org.jacoco.agent:0.8.5

View File

@@ -1,11 +1,11 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.4
org.jacoco:org.jacoco.ant:0.8.4
org.jacoco:org.jacoco.core:0.8.4
org.jacoco:org.jacoco.report:0.8.4
org.ow2.asm:asm-analysis:7.1
org.ow2.asm:asm-commons:7.1
org.ow2.asm:asm-tree:7.1
org.ow2.asm:asm:7.1
org.jacoco:org.jacoco.agent:0.8.5
org.jacoco:org.jacoco.ant:0.8.5
org.jacoco:org.jacoco.core:0.8.5
org.jacoco:org.jacoco.report:0.8.5
org.ow2.asm:asm-analysis:7.2
org.ow2.asm:asm-commons:7.2
org.ow2.asm:asm-tree:7.2
org.ow2.asm:asm:7.2

View File

@@ -0,0 +1,61 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
aopalliance:aopalliance:1.0
args4j:args4j:2.0.23
com.fasterxml.jackson.core:jackson-core:2.9.9
com.google.api-client:google-api-client:1.27.0
com.google.api.grpc:proto-google-common-protos:1.12.0
com.google.api.grpc:proto-google-iam-v1:0.12.0
com.google.api:api-common:1.7.0
com.google.api:gax-httpjson:0.52.1
com.google.api:gax:1.35.1
com.google.apis:google-api-services-storage:v1-rev20181013-1.27.0
com.google.auth:google-auth-library-credentials:0.16.1
com.google.auth:google-auth-library-oauth2-http:0.16.1
com.google.auto.value:auto-value-annotations:1.6.3
com.google.cloud:google-cloud-core-http:1.59.0
com.google.cloud:google-cloud-core:1.59.0
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.2
com.google.guava:failureaccess:1.0.1
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
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client:1.30.1
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.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.ibm.icu:icu4j:57.1
commons-codec:commons-codec:1.11
commons-logging:commons-logging:1.2
io.grpc:grpc-context:1.19.0
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-contrib-http-util:0.21.0
javax.annotation:javax.annotation-api:1.2
javax.annotation:jsr250-api:1.0
javax.inject:javax.inject:1
javax.validation:validation-api:1.0.0.GA
joda-time:joda-time:2.9.2
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.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
org.ow2.asm:asm-tree:6.0
org.ow2.asm:asm-util:6.0
org.ow2.asm:asm:6.0
org.threeten:threetenbp:1.3.3

View File

@@ -0,0 +1,71 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
aopalliance:aopalliance:1.0
args4j:args4j:2.0.23
com.fasterxml.jackson.core:jackson-core:2.9.9
com.google.api-client:google-api-client:1.27.0
com.google.api.grpc:proto-google-common-protos:1.12.0
com.google.api.grpc:proto-google-iam-v1:0.12.0
com.google.api:api-common:1.7.0
com.google.api:gax-httpjson:0.52.1
com.google.api:gax:1.35.1
com.google.apis:google-api-services-storage:v1-rev20181013-1.27.0
com.google.auth:google-auth-library-credentials:0.16.1
com.google.auth:google-auth-library-oauth2-http:0.16.1
com.google.auto.value:auto-value-annotations:1.6.3
com.google.cloud:google-cloud-core-http:1.59.0
com.google.cloud:google-cloud-core:1.59.0
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.2
com.google.guava:failureaccess:1.0.1
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
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client:1.30.1
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.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: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
commons-logging:commons-logging:1.2
io.grpc:grpc-context:1.19.0
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-contrib-http-util:0.21.0
javax.annotation:javax.annotation-api:1.2
javax.annotation:jsr250-api:1.0
javax.inject:javax.inject:1
javax.validation:validation-api:1.0.0.GA
joda-time:joda-time:2.9.2
junit:junit:4.12
net.bytebuddy:byte-buddy-agent:1.9.7
net.bytebuddy:byte-buddy:1.9.7
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-compat-qual:2.5.5
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
org.objenesis:objenesis:2.6
org.ow2.asm:asm-analysis:6.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.threeten:threetenbp:1.3.3

View File

@@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableSetMultimap;
import com.google.template.soy.SoyFileSet;
import com.google.template.soy.tofu.SoyTofu;
import google.registry.gradle.plugin.ProjectData.TaskData;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.Supplier;
@@ -148,10 +149,14 @@ final class CoverPageGenerator {
/** returns a soy-friendly version of the given task data. */
static ImmutableMap<String, Object> taskDataToSoy(TaskData task) {
// Note that all instances of File.separator are replaced with forward slashes so that we can
// generate a valid href on Windows.
return new ImmutableMap.Builder<String, Object>()
.put("uniqueName", task.uniqueName())
.put("description", task.description())
.put("log", task.log().isPresent() ? getLogPath(task).toString() : "")
.put(
"log",
task.log().isPresent() ? getLogPath(task).toString().replace(File.separator, "/") : "")
.put(
"reports",
task.reports().entrySet().stream()
@@ -161,7 +166,11 @@ final class CoverPageGenerator {
entry ->
entry.getValue().files().isEmpty()
? ""
: entry.getValue().entryPoint().toString())))
: entry
.getValue()
.entryPoint()
.toString()
.replace(File.separator, "/"))))
.build();
}
@@ -188,8 +197,10 @@ final class CoverPageGenerator {
}
private static Path getLogPath(TaskData task) {
// TODO(guyben):escape uniqueName to guarantee legal file name.
return Paths.get("logs", task.uniqueName() + ".log");
// We replace colons with dashes so that the resulting filename is always valid, even in
// Windows. As a dash is not a valid character in Java identifies, a task name cannot include
// it, so the uniqueness of the name is perserved.
return Paths.get("logs", task.uniqueName().replace(":", "-") + ".log");
}
private static Supplier<byte[]> resourceLoader(Path path) {

View File

@@ -64,7 +64,8 @@ final class GcsPluginUtils {
static void uploadFileToGcs(
Storage storage, String bucket, Path path, Supplier<byte[]> dataSupplier) {
String filename = path.toString();
// Replace Windows file separators with forward slashes.
String filename = path.toString().replace(File.separator, "/");
storage.create(
BlobInfo.newBuilder(bucket, filename).setContentType(getContentType(filename)).build(),
dataSupplier.get());

View File

@@ -20,9 +20,11 @@ import static com.google.common.truth.Truth8.assertThat;
import static google.registry.gradle.plugin.GcsPluginUtils.toByteArraySupplier;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import google.registry.gradle.plugin.ProjectData.TaskData;
import java.io.File;
import java.nio.file.Paths;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -63,6 +65,8 @@ public final class CoverPageGeneratorTest {
.setState(TaskData.State.UP_TO_DATE)
.build();
private static final Joiner filenameJoiner = Joiner.on(File.separator);
private ImmutableMap<String, String> getGeneratedFiles(ProjectData project) {
CoverPageGenerator coverPageGenerator = new CoverPageGenerator(project);
FilesWithEntryPoint files = coverPageGenerator.getFilesToUpload();
@@ -172,8 +176,8 @@ public final class CoverPageGeneratorTest {
@Test
public void testGetFilesToUpload_containsCssFile() {
ImmutableMap<String, String> files = getGeneratedFiles(EMPTY_PROJECT);
assertThat(files).containsKey("css/style.css");
assertThat(files.get("css/style.css")).contains("body {");
assertThat(files).containsKey(filenameJoiner.join("css", "style.css"));
assertThat(files.get(filenameJoiner.join("css", "style.css"))).contains("body {");
assertThat(files.get("index.html"))
.contains("<link rel=\"stylesheet\" type=\"text/css\" href=\"css/style.css\">");
}
@@ -191,8 +195,8 @@ public final class CoverPageGeneratorTest {
.setLog(toByteArraySupplier("my log data"))
.build())
.build());
assertThat(files).containsEntry("logs/my:name.log", "my log data");
assertThat(files.get("index.html")).contains("<a href=\"logs/my:name.log\">[log]</a>");
assertThat(files).containsEntry(filenameJoiner.join("logs", "my-name.log"), "my log data");
assertThat(files.get("index.html")).contains("<a href=\"logs/my-name.log\">[log]</a>");
}
@Test
@@ -203,7 +207,7 @@ public final class CoverPageGeneratorTest {
.toBuilder()
.addTask(EMPTY_TASK_SUCCESS.toBuilder().setUniqueName("my:name").build())
.build());
assertThat(files).doesNotContainKey("logs/my:name.log");
assertThat(files).doesNotContainKey("logs/my-name.log");
assertThat(files.get("index.html")).contains("<span class=\"report_link_broken\">[log]</span>");
}
@@ -225,7 +229,7 @@ public final class CoverPageGeneratorTest {
Paths.get("path", "report.txt")))
.build())
.build());
assertThat(files).containsEntry("path/report.txt", "report content");
assertThat(files).containsEntry(filenameJoiner.join("path", "report.txt"), "report content");
assertThat(files.get("index.html")).contains("<a href=\"path/report.txt\">[someReport]</a>");
}
@@ -244,7 +248,7 @@ public final class CoverPageGeneratorTest {
ImmutableMap.of(), Paths.get("path", "report.txt")))
.build())
.build());
assertThat(files).doesNotContainKey("path/report.txt");
assertThat(files).doesNotContainKey(filenameJoiner.join("path", "report.txt"));
assertThat(files.get("index.html"))
.contains("<span class=\"report_link_broken\">[someReport]</span>");
}
@@ -275,12 +279,15 @@ public final class CoverPageGeneratorTest {
ImmutableMap.of(), Paths.get("path-empty", "report.txt")))
.build())
.build());
assertThat(files).containsEntry("path-filled/report.txt", "report content");
assertThat(files).containsEntry("path-filled/other/file.txt", "some other content");
assertThat(files).containsEntry("logs/my:name.log", "log data");
assertThat(files)
.containsEntry(filenameJoiner.join("path-filled", "report.txt"), "report content");
assertThat(files)
.containsEntry(
filenameJoiner.join("path-filled", "other", "file.txt"), "some other content");
assertThat(files).containsEntry(filenameJoiner.join("logs", "my-name.log"), "log data");
assertThat(files.get("index.html"))
.contains("<a href=\"path-filled/report.txt\">[filledReport]</a>");
assertThat(files.get("index.html")).contains("<a href=\"logs/my:name.log\">[log]</a>");
assertThat(files.get("index.html")).contains("<a href=\"logs/my-name.log\">[log]</a>");
assertThat(files.get("index.html"))
.contains("<span class=\"report_link_broken\">[emptyReport]</span>");
}

View File

@@ -29,6 +29,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import java.io.File;
import java.nio.file.Files;
@@ -45,6 +46,8 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public final class GcsPluginUtilsTest {
private static final Joiner filenameJoiner = Joiner.on(File.separator);
@Rule public final TemporaryFolder folder = new TemporaryFolder();
@Test
@@ -155,8 +158,10 @@ public final class GcsPluginUtilsTest {
FilesWithEntryPoint files =
readFilesWithEntryPoint(destination, Optional.of(ignoredHint), root);
assertThat(files.entryPoint().toString()).isEqualTo("some/path/file.txt");
assertThat(readAllFiles(files)).containsExactly("some/path/file.txt", "some data");
assertThat(files.entryPoint().toString())
.isEqualTo(filenameJoiner.join("some", "path", "file.txt"));
assertThat(readAllFiles(files))
.containsExactly(filenameJoiner.join("some", "path", "file.txt"), "some data");
}
@Test
@@ -171,7 +176,7 @@ public final class GcsPluginUtilsTest {
FilesWithEntryPoint files =
readFilesWithEntryPoint(destination, Optional.of(ignoredHint), root);
assertThat(files.entryPoint().toString()).isEqualTo("non/existing.txt");
assertThat(files.entryPoint().toString()).isEqualTo(filenameJoiner.join("non", "existing.txt"));
assertThat(files.files()).isEmpty();
}
@@ -187,7 +192,7 @@ public final class GcsPluginUtilsTest {
FilesWithEntryPoint files =
readFilesWithEntryPoint(destination, Optional.of(ignoredHint), root);
assertThat(files.entryPoint().toString()).isEqualTo("some/path");
assertThat(files.entryPoint().toString()).isEqualTo(filenameJoiner.join("some", "path"));
assertThat(files.files()).isEmpty();
}
@@ -205,8 +210,10 @@ public final class GcsPluginUtilsTest {
FilesWithEntryPoint files =
readFilesWithEntryPoint(destination, Optional.of(ignoredHint), root);
assertThat(files.entryPoint().toString()).isEqualTo("some/path/a/file.txt");
assertThat(readAllFiles(files)).containsExactly("some/path/a/file.txt", "some data");
assertThat(files.entryPoint().toString())
.isEqualTo(filenameJoiner.join("some", "path", "a", "file.txt"));
assertThat(readAllFiles(files))
.containsExactly(filenameJoiner.join("some", "path", "a", "file.txt"), "some data");
}
/**
@@ -232,8 +239,10 @@ public final class GcsPluginUtilsTest {
FilesWithEntryPoint files = readFilesWithEntryPoint(destination, Optional.empty(), root);
assertThat(files.entryPoint().toString()).isEqualTo("some/path/path.zip");
assertThat(readAllFiles(files).keySet()).containsExactly("some/path/path.zip");
assertThat(files.entryPoint().toString())
.isEqualTo(filenameJoiner.join("some", "path", "path.zip"));
assertThat(readAllFiles(files).keySet())
.containsExactly(filenameJoiner.join("some", "path", "path.zip"));
}
/**
@@ -261,8 +270,10 @@ public final class GcsPluginUtilsTest {
FilesWithEntryPoint files =
readFilesWithEntryPoint(destination, Optional.of(badEntryPoint), root);
assertThat(files.entryPoint().toString()).isEqualTo("some/path/path.zip");
assertThat(readAllFiles(files).keySet()).containsExactly("some/path/path.zip");
assertThat(files.entryPoint().toString())
.isEqualTo(filenameJoiner.join("some", "path", "path.zip"));
assertThat(readAllFiles(files).keySet())
.containsExactly(filenameJoiner.join("some", "path", "path.zip"));
}
@Test
@@ -285,12 +296,13 @@ public final class GcsPluginUtilsTest {
FilesWithEntryPoint files =
readFilesWithEntryPoint(destination, Optional.of(goodEntryPoint), root);
assertThat(files.entryPoint().toString()).isEqualTo("some/path/index.html");
assertThat(files.entryPoint().toString())
.isEqualTo(filenameJoiner.join("some", "path", "index.html"));
assertThat(readAllFiles(files))
.containsExactly(
"some/path/index.html", "some data",
"some/path/a/index.html", "wrong index",
"some/path/c/style.css", "css file",
"some/path/my_image.png", "images");
filenameJoiner.join("some", "path", "index.html"), "some data",
filenameJoiner.join("some", "path", "a", "index.html"), "wrong index",
filenameJoiner.join("some", "path", "c", "style.css"), "css file",
filenameJoiner.join("some", "path", "my_image.png"), "images");
}
}

View File

@@ -73,6 +73,19 @@ by Joshua Bloch in his book Effective Java -->
<property name="message" value="MockitoJUnitRunner is deprecated. Use @RunWith(JUnit4.class) and MockitoRule instead."/>
</module>
<module name="LineLength">
<!-- Checks if a line is too long. -->
<property name="max" value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.max}" default="100"/>
<property name="severity" value="error"/>
<!-- Ignore lines that have any series of 80 or more non-whitespace characters.
These lines likely cannot be broken.
-->
<property name="ignorePattern"
value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
default=".*[^ ]{80,}.*"/>
</module>
<!-- All Java AST specific tests live under TreeWalker module. -->
<module name="TreeWalker">
@@ -184,19 +197,6 @@ by Joshua Bloch in his book Effective Java -->
LENGTH and CODING CHECKS
-->
<module name="LineLength">
<!-- Checks if a line is too long. -->
<property name="max" value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.max}" default="100"/>
<property name="severity" value="error"/>
<!-- Ignore lines that have any series of 80 or more non-whitespace characters.
These lines likely cannot be broken.
-->
<property name="ignorePattern"
value="${com.puppycrawl.tools.checkstyle.checks.sizes.LineLength.ignorePattern}"
default=".*[^ ]{80,}.*"/>
</module>
<module name="OperatorWrap">
<property name="option" value="nl"/>
<property name="tokens" value="QUESTION, EQUAL, NOT_EQUAL, DIV, PLUS, MINUS, STAR, MOD, SR, BSR, GE, GT, SL, LE, LT, BXOR, BOR, LOR, BAND, LAND, TYPE_EXTENSION_AND, LITERAL_INSTANCEOF"/>

View File

@@ -0,0 +1,16 @@
## Summary
This folder contains configuration files for the gradle-license-report plugin:
* allowed_licenses.json declares the acceptable licenses. A license may have
multiple entries in this file, since the 'moduleLicense' property value must
match exactly the phrases found in pom or manifest files.
* license_normalizer_bundle.json configures normalization rules for license
reporting.
## Notes About Adding New Licenses
* The WTFPL license is not allowed.
* Each 'Public Domain' license entry must include a specific 'moduleName'. Do
not omit moduleName or use wildcards.

View File

@@ -3,6 +3,9 @@
{
"moduleLicense": "Apache Software License, Version 1.1"
},
{
"moduleLicense": "Apache Software License, version 1.1"
},
{
"moduleLicense": "Apache 2"
},
@@ -90,6 +93,9 @@
{
"moduleLicense": "The BSD License"
},
{
"moduleLicense": "The New BSD License"
},
{
"moduleLicense": "The PostgreSQL License"
},
@@ -135,6 +141,9 @@
{
"moduleLicense": "Eclipse Public License - v 2.0"
},
{
"moduleLicense": "Eclipse Public License 2.0"
},
{
"moduleLicense": "https://www.eclipse.org/legal/epl-2.0/, http://www.gnu.org/copyleft/gpl.html, http://www.gnu.org/licenses/lgpl.html"
},
@@ -198,6 +207,9 @@
{
"moduleLicense": "The MIT license"
},
{
"moduleLicense": "The MIT License (MIT)"
},
{
"moduleLicense": "The PostgreSQL License"
},
@@ -205,10 +217,12 @@
"moduleLicense": "Mozilla Public License Version 2.0"
},
{
"moduleLicense": "Public Domain"
"moduleLicense": "Public Domain",
"moduleName": "aopalliance:aopalliance"
},
{
"moduleLicense": "PUBLIC DOMAIN"
"moduleLicense": "Public Domain",
"moduleName": "org.tukaani:xz"
},
{
"moduleLicense": "The W3C Software License"

View File

@@ -80,7 +80,7 @@ PRESUBMITS = {
".git", "/build/", "/generated/", "node_modules/",
"JUnitBackports.java", "registrar_bin.", "registrar_dbg.",
"google-java-format-diff.py",
"nomulus.golden.sql"
"nomulus.golden.sql", "soyutils_usegoog.js"
}, REQUIRED):
"File did not include the license header.",
@@ -99,6 +99,12 @@ PRESUBMITS = {
"System.(out|err).println is only allowed in tools/ packages. Please "
"use a logger instead.",
# PostgreSQLContainer instantiation must specify docker tag
PresubmitCheck(
r"[\s\S]*new\s+PostgreSQLContainer(<[\s\S]*>)?\(\s*\)[\s\S]*",
"java", {}):
"PostgreSQLContainer instantiation must specify docker tag.",
# Various Soy linting checks
PresubmitCheck(
r".* (/\*)?\* {?@param ",

View File

@@ -76,9 +76,9 @@ sourceSets {
main {
java {
srcDirs += generatedDir
// Javadoc API is deprecated and removed in Java 12.
// Javadoc API is deprecated in Java 11 and removed in Java 12.
// TODO(jianglai): re-enable after migrating to the new Javadoc API
if ((JavaVersion.current().majorVersion as Integer) > 11) {
if ((JavaVersion.current().majorVersion as Integer) >= 11) {
exclude 'google/registry/documentation/**'
}
}
@@ -88,9 +88,9 @@ sourceSets {
}
test {
java {
// Javadoc API is deprecated and removed in Java 12.
// Javadoc API is deprecated in Java 11 and removed in Java 12.
// TODO(jianglai): re-enable after migrating to the new Javadoc API
if ((JavaVersion.current().majorVersion as Integer) > 11) {
if ((JavaVersion.current().majorVersion as Integer) >= 11) {
exclude 'google/registry/documentation/**'
}
}
@@ -160,7 +160,6 @@ dependencies {
compile deps['com.google.apis:google-api-services-groupssettings']
compile deps['com.google.apis:google-api-services-monitoring']
compile deps['com.google.apis:google-api-services-sheets']
testCompileOnly deps['com.google.appengine:appengine-api-1.0-sdk']
testCompile deps['com.google.appengine:appengine-api-stubs']
compile deps['com.google.appengine.tools:appengine-gcs-client']
compile deps['com.google.appengine.tools:appengine-mapreduce']
@@ -192,10 +191,12 @@ dependencies {
compile deps['com.jcraft:jsch']
testCompile deps['com.thoughtworks.qdox:qdox']
compile deps['dnsjava:dnsjava']
runtime deps['org.glassfish.jaxb:jaxb-runtime']
testCompile deps['io.github.classgraph:classgraph']
testCompile deps['javax.annotation:javax.annotation-api']
testCompile deps['javax.annotation:jsr250-api']
compile deps['javax.inject:javax.inject']
compile deps['javax.mail:mail']
compile deps['javax.persistence:javax.persistence-api']
compile deps['javax.servlet:servlet-api']
compile deps['javax.xml.bind:jaxb-api']
compile deps['jline:jline']
@@ -206,6 +207,7 @@ dependencies {
compile deps['org.apache.beam:beam-sdks-java-core']
compile deps['org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core']
compile deps['org.apache.beam:beam-sdks-java-io-google-cloud-platform']
testCompile deps['org.apache.commons:commons-lang3']
testCompile deps['org.apache.commons:commons-text']
testCompile deps['org.apache.ftpserver:ftplet-api']
testCompile deps['org.apache.ftpserver:ftpserver-core']
@@ -218,6 +220,8 @@ dependencies {
compile deps['org.bouncycastle:bcpg-jdk15on']
testCompile deps['org.bouncycastle:bcpkix-jdk15on']
compile deps['org.bouncycastle:bcprov-jdk15on']
runtime deps['org.glassfish.jaxb:jaxb-runtime']
compile deps['org.hibernate:hibernate-core']
compile deps['org.joda:joda-money']
compile deps['org.json:json']
testCompile deps['org.mortbay.jetty:jetty']
@@ -226,14 +230,21 @@ dependencies {
testCompile deps['org.seleniumhq.selenium:selenium-chrome-driver']
testCompile deps['org.seleniumhq.selenium:selenium-java']
testCompile deps['org.seleniumhq.selenium:selenium-remote-driver']
testCompile deps['org.testcontainers:jdbc']
compile deps['org.testcontainers:postgresql']
testCompile deps['org.testcontainers:selenium']
testCompile deps['org.testcontainers:testcontainers']
compile deps['xerces:xmlParserAPIs']
compile deps['xpp3:xpp3']
// This dependency must come after javax.mail:mail as it would otherwise
// shadow classes in package javax.mail with its own implementation.
compile deps['com.google.appengine:appengine-api-1.0-sdk']
// Known issue: nebula-lint misses inherited dependency.
compile project(':third_party')
compile project(':util')
// Import NomulusPostreSql from ':db' for compile but exclude dependencies.
compile project(path: ':db', configuration: 'compileApi')
testRuntime project(':db')
// Include auto-value in compile until nebula-lint understands
@@ -289,12 +300,12 @@ dependencies {
task jaxbToJava {
def xsdFilesDir = "${javaDir}/google/registry/xml/xsd"
def bindingsFile = "${javaDir}/google/registry/xjc/bindings.xjb"
def pkgInfoGenerator = "${javaDir}/google/registry/xjc/make_pkginfo.sh"
def pkgInfoTemplate = "${javaDir}/google/registry/xjc/package-info.java.in"
def pkgInfoMap = "${javaDir}/google/registry/xjc/package-info.map"
def outputDir = "${generatedDir}/google/registry/xjc"
inputs.dir xsdFilesDir
inputs.files bindingsFile, pkgInfoTemplate, pkgInfoGenerator
inputs.files bindingsFile, pkgInfoTemplate, pkgInfoMap
outputs.dir outputDir
doLast {
@@ -332,11 +343,17 @@ task jaxbToJava {
// below.
arg(line: '-npa -quiet -extension')
}
exec {
workingDir "${generatedDir}"
executable pkgInfoGenerator
args pkgInfoTemplate, outputDir
new File(pkgInfoMap).eachLine { line ->
def (packageName, namespace) = line.split()
ant.copy(
tofile: "${outputDir}/${packageName}/package-info.java",
overwrite: true,
file: "${pkgInfoTemplate}") {
filterSet() {
filter(token: 'PACKAGE', value: packageName)
filter(token: 'NAMESPACE', value: namespace)
}
}
}
}
}
@@ -412,8 +429,10 @@ task soyToJS {
"--allowExternalCalls", "false",
"--srcs", "${soyFiles.join(',')}",
"--shouldProvideRequireSoyNamespaces", "true",
"--compileTimeGlobalsFile", "${resourcesSourceDir}/google/registry/ui/globals.txt",
"--deps", "${deps.join(',')}"
"--compileTimeGlobalsFile", "${resourcesSourceDir}/google/registry/ui/globals.txt"
if (deps != "") {
args "--deps", "${deps.join(',')}"
}
}
}
@@ -514,7 +533,7 @@ task compileProdJS(type: JavaExec) {
// manually include all the required js files
closureArgs << "--js=${nodeModulesDir}/google-closure-library/**.js"
closureArgs << "--js=${nodeModulesDir}/soyutils_usegoog.js"
closureArgs << "--js=${jsDir}/soyutils_usegoog.js"
closureArgs << "--js=${cssSourceDir}/registrar_bin.css.js"
closureArgs << "--js=${jsSourceDir}/**.js"
// TODO(shicong) Verify the compiled JS file works in Alpha
@@ -525,7 +544,12 @@ task compileProdJS(type: JavaExec) {
compileJava.dependsOn jaxbToJava
compileJava.dependsOn soyToJava
compileJava.dependsOn compileProdJS
// The Closure JS compiler does not support Windows. It is fine to disable it if
// all we want to do is to complile the Java code on Windows.
if (!System.properties['os.name'].toLowerCase().contains('windows')) {
compileJava.dependsOn compileProdJS
assemble.dependsOn compileProdJS
}
// stylesheetsToJavascript must happen after processResources, which wipes the
// resources folder before copying data into it.
@@ -536,13 +560,12 @@ compileProdJS.dependsOn rootProject.npmInstall
compileProdJS.dependsOn processResources
compileProdJS.dependsOn processTestResources
compileProdJS.dependsOn soyToJS
assemble.dependsOn compileProdJS
task karmaTest(type: Exec) {
dependsOn ':npmInstall'
workingDir rootProject.projectDir
executable 'node_modules/karma/bin/karma'
args('start')
args('start', "${project.projectDir}/karma.conf.js")
}
test.dependsOn karmaTest
@@ -577,14 +600,43 @@ artifacts {
*/
class FilteringTest extends Test {
void setTests(List<String> tests) {
// Common exclude pattern. See README in parent directory for explanation.
exclude "**/*TestCase.*", "**/*TestSuite.*"
include tests
private void applyTestFilter() {
if (project.testFilter) {
testNameIncludePatterns = project.testFilter.split(',')
// By default, gradle test tasks will produce a failure if no tests
// match the include/exclude/filter rules. Since test filtering allows us
// to select a set of tests from a particular task, we don't want this
// behavior.
filter.failOnNoMatchingTests = false
}
}
/**
* Set to false if you also want to include TestCase and TestSuite classes.
*
* <p>Must be defined before "test", if at all.
*/
boolean excludeTestCases = true
void setTests(List<String> tests) {
// Common exclude pattern. See README in parent directory for explanation.
if (excludeTestCases) {
exclude "**/*TestCase.*", "**/*TestSuite.*"
}
include tests
applyTestFilter()
}
/**
* Include all of the tests (except Test{Case,TestSuite}). This actually
* doesn't explicitly "include" anything, in which cast the Test class tries
* to include everything that is not explicitly excluded.
*/
void includeAllTests() {
exclude "**/*TestCase.*", "**/*TestSuite.*"
applyTestFilter()
}
}
task fragileTest(type: FilteringTest) {
@@ -606,6 +658,12 @@ task outcastTest(type: FilteringTest) {
maxParallelForks 5
}
// Dedicated test suite for schema-dependent tests.
task sqlIntegrationTest(type: FilteringTest) {
excludeTestCases = false
tests = ['google/registry/schema/integration/SqlIntegrationTestSuite.*']
}
task findGoldenImages(type: JavaExec) {
classpath = sourceSets.test.runtimeClasspath
main = 'google.registry.webdriver.GoldenImageFinder'
@@ -688,9 +746,8 @@ task flowDocsTool(type: JavaExec) {
args arguments
}
test {
// Common exclude pattern. See README in parent directory for explanation.
exclude "**/*TestCase.*", "**/*TestSuite.*"
task standardTest(type: FilteringTest) {
includeAllTests()
exclude fragileTestPatterns
exclude outcastTestPatterns
@@ -712,7 +769,13 @@ test {
doFirst {
new File(screenshotsDir).deleteDir()
}
}.dependsOn(fragileTest, outcastTest)
}
test {
// Don't run any tests from this task, all testing gets done in the
// FilteringTest tasks.
exclude "**"
}.dependsOn(fragileTest, outcastTest, standardTest)
createUberJar('nomulus', 'nomulus', 'google.registry.tools.RegistryTool')
project.nomulus.dependsOn project(':third_party').jar

View File

@@ -3,16 +3,16 @@
# This file is expected to be part of source control.
antlr:antlr:2.7.7
com.google.code.findbugs:jsr305:3.0.2
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.0.1-jre
com.google.guava:guava:28.0-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.j2objc:j2objc-annotations:1.1
com.puppycrawl.tools:checkstyle:8.17
commons-beanutils:commons-beanutils:1.9.3
com.google.j2objc:j2objc-annotations:1.3
com.puppycrawl.tools:checkstyle:8.24
commons-beanutils:commons-beanutils:1.9.4
commons-collections:commons-collections:3.2.2
info.picocli:picocli:3.9.0
net.sf.saxon:Saxon-HE:9.9.0-2
info.picocli:picocli:4.0.3
net.sf.saxon:Saxon-HE:9.9.1-4
org.antlr:antlr4-runtime:4.7.2
org.checkerframework:checker-qual:2.5.2
org.checkerframework:checker-qual:2.8.1
org.codehaus.mojo:animal-sniffer-annotations:1.17

View File

@@ -6,11 +6,10 @@ aopalliance:aopalliance:1.0
args4j:args4j:2.0.23
cglib:cglib-nodep:2.2
com.beust:jcommander:1.60
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.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
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
com.google.api-client:google-api-client-java6:1.27.0
@@ -18,7 +17,7 @@ com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.43.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:1.6.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:1.6.0
@@ -44,7 +43,7 @@ com.google.apis:google-api-services-bigquery:v2-rev20181104-1.27.0
com.google.apis:google-api-services-clouddebugger:v2-rev20180801-1.27.0
com.google.apis:google-api-services-cloudkms:v1-rev12-1.22.0
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20181015-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190126-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190607-1.27.0
com.google.apis:google-api-services-dns:v2beta1-rev6-1.22.0
com.google.apis:google-api-services-drive:v2-rev160-1.19.1
com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
@@ -165,22 +164,23 @@ javax.transaction:transaction-api:1.1
javax.validation:validation-api:1.0.0.GA
javax.xml.bind:jaxb-api:2.3.1
jline:jline:1.0
joda-time:joda-time:2.9.2
joda-time:joda-time:2.10.3
junit:junit:4.12
net.bytebuddy:byte-buddy:1.9.11
net.java.dev.jna:jna-platform:5.3.1
net.java.dev.jna:jna:5.3.1
org.apache.avro:avro:1.8.2
org.apache.beam:beam-model-job-management:2.11.0
org.apache.beam:beam-model-pipeline:2.11.0
org.apache.beam:beam-runners-core-construction-java:2.11.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.11.0
org.apache.beam:beam-sdks-java-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.11.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.11.0
org.apache.beam:beam-vendor-grpc-1_13_1:0.2
org.apache.beam:beam-vendor-guava-20_0:0.1
org.apache.beam:beam-model-job-management:2.16.0
org.apache.beam:beam-model-pipeline:2.16.0
org.apache.beam:beam-runners-core-construction-java:2.16.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.16.0
org.apache.beam:beam-sdks-java-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.16.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.16.0
org.apache.beam:beam-vendor-bytebuddy-1_9_3:0.1
org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
@@ -204,7 +204,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:1.9.5

View File

@@ -6,11 +6,10 @@ aopalliance:aopalliance:1.0
args4j:args4j:2.0.23
cglib:cglib-nodep:2.2
com.beust:jcommander:1.60
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.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
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
com.google.api-client:google-api-client-java6:1.27.0
@@ -18,7 +17,7 @@ com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.43.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:1.6.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:1.6.0
@@ -44,7 +43,7 @@ com.google.apis:google-api-services-bigquery:v2-rev20181104-1.27.0
com.google.apis:google-api-services-clouddebugger:v2-rev20180801-1.27.0
com.google.apis:google-api-services-cloudkms:v1-rev12-1.22.0
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20181015-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190126-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190607-1.27.0
com.google.apis:google-api-services-dns:v2beta1-rev6-1.22.0
com.google.apis:google-api-services-drive:v2-rev160-1.19.1
com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
@@ -163,22 +162,23 @@ javax.transaction:transaction-api:1.1
javax.validation:validation-api:1.0.0.GA
javax.xml.bind:jaxb-api:2.3.1
jline:jline:1.0
joda-time:joda-time:2.9.2
joda-time:joda-time:2.10.3
junit:junit:4.12
net.bytebuddy:byte-buddy:1.9.11
net.java.dev.jna:jna-platform:5.3.1
net.java.dev.jna:jna:5.3.1
org.apache.avro:avro:1.8.2
org.apache.beam:beam-model-job-management:2.11.0
org.apache.beam:beam-model-pipeline:2.11.0
org.apache.beam:beam-runners-core-construction-java:2.11.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.11.0
org.apache.beam:beam-sdks-java-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.11.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.11.0
org.apache.beam:beam-vendor-grpc-1_13_1:0.2
org.apache.beam:beam-vendor-guava-20_0:0.1
org.apache.beam:beam-model-job-management:2.16.0
org.apache.beam:beam-model-pipeline:2.16.0
org.apache.beam:beam-runners-core-construction-java:2.16.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.16.0
org.apache.beam:beam-sdks-java-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.16.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.16.0
org.apache.beam:beam-vendor-bytebuddy-1_9_3:0.1
org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
@@ -202,7 +202,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:1.9.5

View File

@@ -6,9 +6,9 @@ aopalliance:aopalliance:1.0
args4j:args4j:2.0.23
cglib:cglib-nodep:2.2
com.beust:jcommander:1.60
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.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
com.github.jnr:jffi:1.2.17
com.github.jnr:jnr-a64asm:1.0.0
@@ -18,7 +18,6 @@ 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
com.google.api-client:google-api-client-java6:1.27.0
@@ -26,7 +25,7 @@ com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.43.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:1.6.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:1.6.0
@@ -52,7 +51,7 @@ com.google.apis:google-api-services-bigquery:v2-rev20181104-1.27.0
com.google.apis:google-api-services-clouddebugger:v2-rev20180801-1.27.0
com.google.apis:google-api-services-cloudkms:v1-rev12-1.22.0
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20181015-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190126-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190607-1.27.0
com.google.apis:google-api-services-dns:v2beta1-rev6-1.22.0
com.google.apis:google-api-services-drive:v2-rev160-1.19.1
com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
@@ -176,22 +175,23 @@ javax.transaction:transaction-api:1.1
javax.validation:validation-api:1.0.0.GA
javax.xml.bind:jaxb-api:2.3.1
jline:jline:1.0
joda-time:joda-time:2.9.2
joda-time:joda-time:2.10.3
junit:junit:4.12
net.bytebuddy:byte-buddy:1.9.11
net.java.dev.jna:jna-platform:5.3.1
net.java.dev.jna:jna:5.3.1
org.apache.avro:avro:1.8.2
org.apache.beam:beam-model-job-management:2.11.0
org.apache.beam:beam-model-pipeline:2.11.0
org.apache.beam:beam-runners-core-construction-java:2.11.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.11.0
org.apache.beam:beam-sdks-java-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.11.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.11.0
org.apache.beam:beam-vendor-grpc-1_13_1:0.2
org.apache.beam:beam-vendor-guava-20_0:0.1
org.apache.beam:beam-model-job-management:2.16.0
org.apache.beam:beam-model-pipeline:2.16.0
org.apache.beam:beam-runners-core-construction-java:2.16.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.16.0
org.apache.beam:beam-sdks-java-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.16.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.16.0
org.apache.beam:beam-vendor-bytebuddy-1_9_3:0.1
org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
@@ -215,7 +215,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:1.9.5

View File

@@ -1,4 +1,4 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.4
org.jacoco:org.jacoco.agent:0.8.5

View File

@@ -1,11 +1,11 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
org.jacoco:org.jacoco.agent:0.8.4
org.jacoco:org.jacoco.ant:0.8.4
org.jacoco:org.jacoco.core:0.8.4
org.jacoco:org.jacoco.report:0.8.4
org.ow2.asm:asm-analysis:7.1
org.ow2.asm:asm-commons:7.1
org.ow2.asm:asm-tree:7.1
org.ow2.asm:asm:7.1
org.jacoco:org.jacoco.agent:0.8.5
org.jacoco:org.jacoco.ant:0.8.5
org.jacoco:org.jacoco.core:0.8.5
org.jacoco:org.jacoco.report:0.8.5
org.ow2.asm:asm-analysis:7.2
org.ow2.asm:asm-commons:7.2
org.ow2.asm:asm-tree:7.2
org.ow2.asm:asm:7.2

View File

@@ -6,11 +6,10 @@ aopalliance:aopalliance:1.0
args4j:args4j:2.0.23
cglib:cglib-nodep:2.2
com.beust:jcommander:1.60
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.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
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
com.google.api-client:google-api-client-java6:1.27.0
@@ -18,7 +17,7 @@ com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.43.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:1.6.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:1.6.0
@@ -44,7 +43,7 @@ com.google.apis:google-api-services-bigquery:v2-rev20181104-1.27.0
com.google.apis:google-api-services-clouddebugger:v2-rev20180801-1.27.0
com.google.apis:google-api-services-cloudkms:v1-rev12-1.22.0
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20181015-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190126-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190607-1.27.0
com.google.apis:google-api-services-dns:v2beta1-rev6-1.22.0
com.google.apis:google-api-services-drive:v2-rev160-1.19.1
com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
@@ -165,22 +164,23 @@ javax.transaction:transaction-api:1.1
javax.validation:validation-api:1.0.0.GA
javax.xml.bind:jaxb-api:2.3.1
jline:jline:1.0
joda-time:joda-time:2.9.2
joda-time:joda-time:2.10.3
junit:junit:4.12
net.bytebuddy:byte-buddy:1.9.11
net.java.dev.jna:jna-platform:5.3.1
net.java.dev.jna:jna:5.3.1
org.apache.avro:avro:1.8.2
org.apache.beam:beam-model-job-management:2.11.0
org.apache.beam:beam-model-pipeline:2.11.0
org.apache.beam:beam-runners-core-construction-java:2.11.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.11.0
org.apache.beam:beam-sdks-java-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.11.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.11.0
org.apache.beam:beam-vendor-grpc-1_13_1:0.2
org.apache.beam:beam-vendor-guava-20_0:0.1
org.apache.beam:beam-model-job-management:2.16.0
org.apache.beam:beam-model-pipeline:2.16.0
org.apache.beam:beam-runners-core-construction-java:2.16.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.16.0
org.apache.beam:beam-sdks-java-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.16.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.16.0
org.apache.beam:beam-vendor-bytebuddy-1_9_3:0.1
org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
@@ -204,7 +204,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:1.9.5

View File

@@ -6,9 +6,9 @@ aopalliance:aopalliance:1.0
args4j:args4j:2.0.23
cglib:cglib-nodep:2.2
com.beust:jcommander:1.60
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.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
com.github.jnr:jffi:1.2.17
com.github.jnr:jnr-a64asm:1.0.0
@@ -18,7 +18,6 @@ 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
com.google.api-client:google-api-client-java6:1.27.0
@@ -26,7 +25,7 @@ com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.43.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:1.6.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:1.6.0
@@ -52,7 +51,7 @@ com.google.apis:google-api-services-bigquery:v2-rev20181104-1.27.0
com.google.apis:google-api-services-clouddebugger:v2-rev20180801-1.27.0
com.google.apis:google-api-services-cloudkms:v1-rev12-1.22.0
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20181015-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190126-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190607-1.27.0
com.google.apis:google-api-services-dns:v2beta1-rev6-1.22.0
com.google.apis:google-api-services-drive:v2-rev160-1.19.1
com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
@@ -176,22 +175,23 @@ javax.transaction:transaction-api:1.1
javax.validation:validation-api:1.0.0.GA
javax.xml.bind:jaxb-api:2.3.1
jline:jline:1.0
joda-time:joda-time:2.9.2
joda-time:joda-time:2.10.3
junit:junit:4.12
net.bytebuddy:byte-buddy:1.9.11
net.java.dev.jna:jna-platform:5.3.1
net.java.dev.jna:jna:5.3.1
org.apache.avro:avro:1.8.2
org.apache.beam:beam-model-job-management:2.11.0
org.apache.beam:beam-model-pipeline:2.11.0
org.apache.beam:beam-runners-core-construction-java:2.11.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.11.0
org.apache.beam:beam-sdks-java-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.11.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.11.0
org.apache.beam:beam-vendor-grpc-1_13_1:0.2
org.apache.beam:beam-vendor-guava-20_0:0.1
org.apache.beam:beam-model-job-management:2.16.0
org.apache.beam:beam-model-pipeline:2.16.0
org.apache.beam:beam-runners-core-construction-java:2.16.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.16.0
org.apache.beam:beam-sdks-java-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.16.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.16.0
org.apache.beam:beam-vendor-bytebuddy-1_9_3:0.1
org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
@@ -215,7 +215,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:1.9.5

View File

@@ -6,11 +6,10 @@ aopalliance:aopalliance:1.0
args4j:args4j:2.33
cglib:cglib-nodep:2.2
com.beust:jcommander:1.60
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.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
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
com.google.api-client:google-api-client-java6:1.27.0
@@ -18,7 +17,7 @@ com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.43.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:1.6.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:1.6.0
@@ -44,7 +43,7 @@ com.google.apis:google-api-services-bigquery:v2-rev20181104-1.27.0
com.google.apis:google-api-services-clouddebugger:v2-rev20180801-1.27.0
com.google.apis:google-api-services-cloudkms:v1-rev12-1.22.0
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20181015-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190126-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190607-1.27.0
com.google.apis:google-api-services-dns:v2beta1-rev6-1.22.0
com.google.apis:google-api-services-drive:v2-rev160-1.19.1
com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
@@ -130,6 +129,7 @@ commons-codec:commons-codec:1.11
commons-logging:commons-logging:1.2
dnsjava:dnsjava:2.1.7
io.dropwizard.metrics:metrics-core:3.1.2
io.github.classgraph:classgraph:4.8.52
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
@@ -173,24 +173,25 @@ javax.transaction:transaction-api:1.1
javax.validation:validation-api:1.0.0.GA
javax.xml.bind:jaxb-api:2.3.1
jline:jline:1.0
joda-time:joda-time:2.9.2
joda-time:joda-time:2.10.3
junit:junit:4.12
net.bytebuddy:byte-buddy-agent:1.9.7
net.bytebuddy:byte-buddy:1.9.11
net.java.dev.jna:jna-platform:5.3.1
net.java.dev.jna:jna:5.3.1
org.apache.avro:avro:1.8.2
org.apache.beam:beam-model-job-management:2.11.0
org.apache.beam:beam-model-pipeline:2.11.0
org.apache.beam:beam-runners-core-construction-java:2.11.0
org.apache.beam:beam-runners-direct-java:2.11.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.11.0
org.apache.beam:beam-sdks-java-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.11.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.11.0
org.apache.beam:beam-vendor-grpc-1_13_1:0.2
org.apache.beam:beam-vendor-guava-20_0:0.1
org.apache.beam:beam-model-job-management:2.16.0
org.apache.beam:beam-model-pipeline:2.16.0
org.apache.beam:beam-runners-core-construction-java:2.16.0
org.apache.beam:beam-runners-direct-java:2.16.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.16.0
org.apache.beam:beam-sdks-java-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.16.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.16.0
org.apache.beam:beam-vendor-bytebuddy-1_9_3:0.1
org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
@@ -227,7 +228,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:2.25.0

View File

@@ -6,11 +6,10 @@ aopalliance:aopalliance:1.0
args4j:args4j:2.33
cglib:cglib-nodep:2.2
com.beust:jcommander:1.60
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.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
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
com.google.api-client:google-api-client-java6:1.27.0
@@ -18,7 +17,7 @@ com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.43.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:1.6.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:1.6.0
@@ -44,7 +43,7 @@ com.google.apis:google-api-services-bigquery:v2-rev20181104-1.27.0
com.google.apis:google-api-services-clouddebugger:v2-rev20180801-1.27.0
com.google.apis:google-api-services-cloudkms:v1-rev12-1.22.0
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20181015-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190126-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190607-1.27.0
com.google.apis:google-api-services-dns:v2beta1-rev6-1.22.0
com.google.apis:google-api-services-drive:v2-rev160-1.19.1
com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
@@ -129,6 +128,7 @@ commons-codec:commons-codec:1.11
commons-logging:commons-logging:1.2
dnsjava:dnsjava:2.1.7
io.dropwizard.metrics:metrics-core:3.1.2
io.github.classgraph:classgraph:4.8.52
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
@@ -171,24 +171,25 @@ javax.transaction:transaction-api:1.1
javax.validation:validation-api:1.0.0.GA
javax.xml.bind:jaxb-api:2.3.1
jline:jline:1.0
joda-time:joda-time:2.9.2
joda-time:joda-time:2.10.3
junit:junit:4.12
net.bytebuddy:byte-buddy-agent:1.9.7
net.bytebuddy:byte-buddy:1.9.11
net.java.dev.jna:jna-platform:5.3.1
net.java.dev.jna:jna:5.3.1
org.apache.avro:avro:1.8.2
org.apache.beam:beam-model-job-management:2.11.0
org.apache.beam:beam-model-pipeline:2.11.0
org.apache.beam:beam-runners-core-construction-java:2.11.0
org.apache.beam:beam-runners-direct-java:2.11.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.11.0
org.apache.beam:beam-sdks-java-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.11.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.11.0
org.apache.beam:beam-vendor-grpc-1_13_1:0.2
org.apache.beam:beam-vendor-guava-20_0:0.1
org.apache.beam:beam-model-job-management:2.16.0
org.apache.beam:beam-model-pipeline:2.16.0
org.apache.beam:beam-runners-core-construction-java:2.16.0
org.apache.beam:beam-runners-direct-java:2.16.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.16.0
org.apache.beam:beam-sdks-java-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.16.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.16.0
org.apache.beam:beam-vendor-bytebuddy-1_9_3:0.1
org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
@@ -225,7 +226,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:2.25.0

View File

@@ -1,4 +1,3 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
com.google.appengine:appengine-api-1.0-sdk:1.9.48

View File

@@ -6,9 +6,9 @@ aopalliance:aopalliance:1.0
args4j:args4j:2.33
cglib:cglib-nodep:2.2
com.beust:jcommander:1.60
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.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
com.github.jnr:jffi:1.2.17
com.github.jnr:jnr-a64asm:1.0.0
@@ -18,7 +18,6 @@ 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
com.google.api-client:google-api-client-java6:1.27.0
@@ -26,7 +25,7 @@ com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.43.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:1.6.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:1.6.0
@@ -52,7 +51,7 @@ com.google.apis:google-api-services-bigquery:v2-rev20181104-1.27.0
com.google.apis:google-api-services-clouddebugger:v2-rev20180801-1.27.0
com.google.apis:google-api-services-cloudkms:v1-rev12-1.22.0
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20181015-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190126-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190607-1.27.0
com.google.apis:google-api-services-dns:v2beta1-rev6-1.22.0
com.google.apis:google-api-services-drive:v2-rev160-1.19.1
com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
@@ -141,6 +140,7 @@ commons-codec:commons-codec:1.11
commons-logging:commons-logging:1.2
dnsjava:dnsjava:2.1.7
io.dropwizard.metrics:metrics-core:3.1.2
io.github.classgraph:classgraph:4.8.52
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
@@ -184,24 +184,25 @@ javax.transaction:transaction-api:1.1
javax.validation:validation-api:1.0.0.GA
javax.xml.bind:jaxb-api:2.3.1
jline:jline:1.0
joda-time:joda-time:2.9.2
joda-time:joda-time:2.10.3
junit:junit:4.12
net.bytebuddy:byte-buddy-agent:1.9.7
net.bytebuddy:byte-buddy:1.9.11
net.java.dev.jna:jna-platform:5.3.1
net.java.dev.jna:jna:5.3.1
org.apache.avro:avro:1.8.2
org.apache.beam:beam-model-job-management:2.11.0
org.apache.beam:beam-model-pipeline:2.11.0
org.apache.beam:beam-runners-core-construction-java:2.11.0
org.apache.beam:beam-runners-direct-java:2.11.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.11.0
org.apache.beam:beam-sdks-java-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.11.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.11.0
org.apache.beam:beam-vendor-grpc-1_13_1:0.2
org.apache.beam:beam-vendor-guava-20_0:0.1
org.apache.beam:beam-model-job-management:2.16.0
org.apache.beam:beam-model-pipeline:2.16.0
org.apache.beam:beam-runners-core-construction-java:2.16.0
org.apache.beam:beam-runners-direct-java:2.16.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.16.0
org.apache.beam:beam-sdks-java-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.16.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.16.0
org.apache.beam:beam-vendor-bytebuddy-1_9_3:0.1
org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
@@ -239,7 +240,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:2.25.0

View File

@@ -6,9 +6,9 @@ aopalliance:aopalliance:1.0
args4j:args4j:2.33
cglib:cglib-nodep:2.2
com.beust:jcommander:1.60
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.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
com.github.jnr:jffi:1.2.17
com.github.jnr:jnr-a64asm:1.0.0
@@ -18,7 +18,6 @@ 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
com.google.api-client:google-api-client-java6:1.27.0
@@ -26,7 +25,7 @@ com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.43.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:1.6.0
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:1.6.0
@@ -52,7 +51,7 @@ com.google.apis:google-api-services-bigquery:v2-rev20181104-1.27.0
com.google.apis:google-api-services-clouddebugger:v2-rev20180801-1.27.0
com.google.apis:google-api-services-cloudkms:v1-rev12-1.22.0
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20181015-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190126-1.27.0
com.google.apis:google-api-services-dataflow:v1b3-rev20190607-1.27.0
com.google.apis:google-api-services-dns:v2beta1-rev6-1.22.0
com.google.apis:google-api-services-drive:v2-rev160-1.19.1
com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
@@ -141,6 +140,7 @@ commons-codec:commons-codec:1.11
commons-logging:commons-logging:1.2
dnsjava:dnsjava:2.1.7
io.dropwizard.metrics:metrics-core:3.1.2
io.github.classgraph:classgraph:4.8.52
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
@@ -184,24 +184,25 @@ javax.transaction:transaction-api:1.1
javax.validation:validation-api:1.0.0.GA
javax.xml.bind:jaxb-api:2.3.1
jline:jline:1.0
joda-time:joda-time:2.9.2
joda-time:joda-time:2.10.3
junit:junit:4.12
net.bytebuddy:byte-buddy-agent:1.9.7
net.bytebuddy:byte-buddy:1.9.11
net.java.dev.jna:jna-platform:5.3.1
net.java.dev.jna:jna:5.3.1
org.apache.avro:avro:1.8.2
org.apache.beam:beam-model-job-management:2.11.0
org.apache.beam:beam-model-pipeline:2.11.0
org.apache.beam:beam-runners-core-construction-java:2.11.0
org.apache.beam:beam-runners-direct-java:2.11.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.11.0
org.apache.beam:beam-sdks-java-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.11.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.11.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.11.0
org.apache.beam:beam-vendor-grpc-1_13_1:0.2
org.apache.beam:beam-vendor-guava-20_0:0.1
org.apache.beam:beam-model-job-management:2.16.0
org.apache.beam:beam-model-pipeline:2.16.0
org.apache.beam:beam-runners-core-construction-java:2.16.0
org.apache.beam:beam-runners-direct-java:2.16.0
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.16.0
org.apache.beam:beam-sdks-java-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.16.0
org.apache.beam:beam-sdks-java-extensions-protobuf:2.16.0
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.16.0
org.apache.beam:beam-vendor-bytebuddy-1_9_3:0.1
org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-exec:1.3
org.apache.commons:commons-lang3:3.8.1
@@ -239,7 +240,7 @@ org.jboss.logging:jboss-logging:3.3.2.Final
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final
org.jboss:jandex:2.0.5.Final
org.jetbrains:annotations:17.0.0
org.joda:joda-money:0.10.0
org.joda:joda-money:1.0.1
org.json:json:20160810
org.jvnet.staxex:stax-ex:1.8
org.mockito:mockito-core:2.25.0

View File

@@ -16,6 +16,7 @@ process.env.CHROME_BIN = require('puppeteer').executablePath()
module.exports = function(config) {
config.set({
basePath: '..',
browsers: ['ChromeHeadlessNoSandbox'],
customLaunchers: {
ChromeHeadlessNoSandbox: {
@@ -41,10 +42,6 @@ module.exports = function(config) {
pattern: 'core/build/generated/source/custom/main/**/*.soy.js',
included: false
},
{
pattern: 'node_modules/soyutils_usegoog.js',
included: false
},
{
pattern: 'node_modules/google-closure-library/closure/goog/deps.js',
included: false,
@@ -69,7 +66,6 @@ module.exports = function(config) {
'node_modules/google-closure-library/closure/**/*.js': ['closure'],
'core/src/*/javascript/**/*.js': ['closure'],
'core/build/generated/source/custom/main/**/*.soy.js': ['closure'],
'node_modules/soyutils_usegoog.js': ['closure']
},
proxies: {
"/assets/": "/base/core/build/resources/main/google/registry/ui/assets/"

View File

@@ -85,7 +85,7 @@ public class InvoicingPipeline implements Serializable {
}
/** Custom options for running the invoicing pipeline. */
interface InvoicingPipelineOptions extends DataflowPipelineOptions {
public interface InvoicingPipelineOptions extends DataflowPipelineOptions {
/** Returns the yearMonth we're generating invoices for, in yyyy-MM format. */
@Description("The yearMonth we generate invoices for, in yyyy-MM format.")
ValueProvider<String> getYearMonth();

View File

@@ -105,7 +105,7 @@ public class Spec11Pipeline implements Serializable {
}
/** Custom options for running the spec11 pipeline. */
interface Spec11PipelineOptions extends DataflowPipelineOptions {
public interface Spec11PipelineOptions extends DataflowPipelineOptions {
/** Returns the local date we're generating the report for, in yyyy-MM-dd format. */
@Description("The local date we generate the report for, in yyyy-MM-dd format.")
ValueProvider<String> getDate();

View File

@@ -1296,12 +1296,6 @@ 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) {

View File

@@ -213,7 +213,6 @@ public class RegistryConfigSettings {
public static class RegistryTool {
public String clientId;
public String clientSecret;
public String jdbcUrl;
public String username;
}
}

View File

@@ -422,6 +422,4 @@ 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

View File

@@ -55,6 +55,12 @@
<url-pattern>/registrar-settings</url-pattern>
</servlet-mapping>
<!-- Registry lock get/post/verify. -->
<servlet-mapping>
<servlet-name>frontend-servlet</servlet-name>
<url-pattern>/registry-lock-get</url-pattern>
</servlet-mapping>
<!-- Security config -->
<security-constraint>
<web-resource-collection>

View File

@@ -187,6 +187,7 @@ import org.joda.time.Duration;
* @error {@link DomainFlowUtils.UnexpectedClaimsNoticeException}
* @error {@link DomainFlowUtils.UnsupportedFeeAttributeException}
* @error {@link DomainFlowUtils.UnsupportedMarkTypeException}
* @error {@link DomainPricingLogic.AllocationTokenInvalidForPremiumNameException}
*/
@ReportingSpec(ActivityReportField.DOMAIN_CREATE)
public class DomainCreateFlow implements TransactionalFlow {

View File

@@ -14,12 +14,12 @@
package google.registry.flows.domain;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.pricing.PricingEngineProxy.getDomainFeeClass;
import static google.registry.pricing.PricingEngineProxy.getDomainRenewCost;
import com.google.common.net.InternetDomainName;
import google.registry.flows.EppException;
import google.registry.flows.EppException.CommandUseErrorException;
import google.registry.flows.FlowScope;
import google.registry.flows.custom.DomainPricingCustomLogic;
import google.registry.flows.custom.DomainPricingCustomLogic.CreatePriceParameters;
@@ -182,13 +182,14 @@ public final class DomainPricingLogic {
}
private Money getDomainCreateCostWithDiscount(
String domainName, DateTime date, int years, Optional<AllocationToken> allocationToken) {
String domainName, DateTime date, int years, Optional<AllocationToken> allocationToken)
throws EppException {
DomainPrices domainPrices = PricingEngineProxy.getPricesForDomainName(domainName, date);
checkArgument(
!allocationToken.isPresent()
|| allocationToken.get().getDiscountFraction() == 0.0
|| !domainPrices.isPremium(),
"A nonzero discount code cannot be applied to premium domains");
if (allocationToken.isPresent()
&& allocationToken.get().getDiscountFraction() != 0.0
&& domainPrices.isPremium()) {
throw new AllocationTokenInvalidForPremiumNameException();
}
Money oneYearCreateCost = domainPrices.getCreateCost();
Money totalDomainCreateCost = oneYearCreateCost.multipliedBy(years);
// If a discount is applicable, apply it only to the first year
@@ -200,4 +201,12 @@ public final class DomainPricingLogic {
}
return totalDomainCreateCost;
}
/** An allocation token was provided that is invalid for premium domains. */
public static class AllocationTokenInvalidForPremiumNameException
extends CommandUseErrorException {
public AllocationTokenInvalidForPremiumNameException() {
super("A nonzero discount code cannot be applied to premium domains");
}
}
}

View File

@@ -79,7 +79,16 @@ public class Cursor extends ImmutableObject {
* stored is the last time that registrar changes were successfully synced to the sheet. If
* there were no changes since the last time the action run, the cursor is not updated.
*/
SYNC_REGISTRAR_SHEET(EntityGroupRoot.class);
SYNC_REGISTRAR_SHEET(EntityGroupRoot.class),
/** Cursor for tracking monthly uploads of ICANN transaction reports. */
ICANN_UPLOAD_TX(Registry.class),
/** Cursor for tracking monthly uploads of ICANN activity reports. */
ICANN_UPLOAD_ACTIVITY(Registry.class),
/** Cursor for tracking monthly upload of MANIFEST.txt to ICANN. */
ICANN_UPLOAD_MANIFEST(EntityGroupRoot.class);
/** See the definition of scope on {@link #getScopeClass}. */
private final Class<? extends ImmutableObject> scope;

View File

@@ -35,6 +35,8 @@ import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Index;
import com.googlecode.objectify.annotation.Mapify;
import google.registry.flows.EppException;
import google.registry.flows.domain.DomainFlowUtils;
import google.registry.model.BackupGroupRoot;
import google.registry.model.Buildable;
import google.registry.model.CreateAutoTimestamp;
@@ -201,6 +203,13 @@ public class AllocationToken extends BackupGroupRoot implements Buildable {
getInstance().redemptionHistoryEntry == null
|| TokenType.SINGLE_USE.equals(getInstance().tokenType),
"Redemption history entry can only be specified for SINGLE_USE tokens");
if (getInstance().domainName != null) {
try {
DomainFlowUtils.validateDomainName(getInstance().domainName);
} catch (EppException e) {
throw new IllegalArgumentException("Invalid domain name: " + getInstance().domainName, e);
}
}
return super.build();
}

View File

@@ -33,6 +33,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Streams;
import com.google.common.net.InternetDomainName;
import com.googlecode.objectify.Key;
import google.registry.model.registry.Registry.TldType;
import java.util.Optional;
@@ -80,6 +81,15 @@ public final class Registries {
return ImmutableSet.copyOf(filterValues(cache.get(), equalTo(type)).keySet());
}
/** Returns the Registry entities themselves of the given type loaded fresh from Datastore. */
public static ImmutableSet<Registry> getTldEntitiesOfType(TldType type) {
ImmutableSet<Key<Registry>> keys =
filterValues(cache.get(), equalTo(type)).keySet().stream()
.map(tld -> Key.create(getCrossTldKey(), Registry.class, tld))
.collect(toImmutableSet());
return ImmutableSet.copyOf(tm().doTransactionless(() -> ofy().load().keys(keys).values()));
}
/** Pass-through check that the specified TLD exists, otherwise throw an IAE. */
public static String assertTldExists(String tld) {
checkArgument(

View File

@@ -17,7 +17,9 @@ package google.registry.model.registry;
import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
import com.google.common.collect.ImmutableList;
import google.registry.schema.domain.RegistryLock;
import java.util.Optional;
import javax.persistence.EntityManager;
/** Data access object for {@link google.registry.schema.domain.RegistryLock}. */
@@ -40,13 +42,50 @@ public final class RegistryLockDao {
Long.class)
.setParameter("verificationCode", verificationCode)
.getSingleResult();
// TODO(gbrodman): Don't throw NPE here. Maybe NoResultException fits better?
checkNotNull(revisionId, "No registry lock with this code");
return em.find(RegistryLock.class, revisionId);
});
}
public static void save(RegistryLock registryLock) {
/** Returns all lock objects that this registrar has created. */
public static ImmutableList<RegistryLock> getByRegistrarId(String registrarId) {
return jpaTm()
.transact(
() ->
ImmutableList.copyOf(
jpaTm()
.getEntityManager()
.createQuery(
"SELECT lock FROM RegistryLock lock WHERE"
+ " lock.registrarId = :registrarId",
RegistryLock.class)
.setParameter("registrarId", registrarId)
.getResultList()));
}
/**
* Returns the most recent lock object for a given repo ID (i.e. a domain) or empty if this domain
* hasn't been locked before.
*/
public static Optional<RegistryLock> getMostRecentByRepoId(String repoId) {
return jpaTm()
.transact(
() ->
jpaTm()
.getEntityManager()
.createQuery(
"SELECT lock FROM RegistryLock lock WHERE lock.repoId = :repoId"
+ " ORDER BY lock.revisionId DESC",
RegistryLock.class)
.setParameter("repoId", repoId)
.setMaxResults(1)
.getResultStream()
.findFirst());
}
public static RegistryLock save(RegistryLock registryLock) {
checkNotNull(registryLock, "Null registry lock cannot be saved");
jpaTm().transact(() -> jpaTm().getEntityManager().persist(registryLock));
return jpaTm().transact(() -> jpaTm().getEntityManager().merge(registryLock));
}
}

View File

@@ -79,17 +79,14 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
T result = work.run();
txn.commit();
return result;
} catch (Throwable transactionException) {
String rollbackMessage;
} catch (RuntimeException e) {
try {
txn.rollback();
rollbackMessage = "transaction rolled back";
logger.atWarning().log("Error during transaction; transaction rolled back");
} catch (Throwable rollbackException) {
logger.atSevere().withCause(rollbackException).log("Rollback failed, suppressing error");
rollbackMessage = "transaction rollback failed";
logger.atSevere().withCause(rollbackException).log("Rollback failed; suppressing error");
}
throw new PersistenceException(
"Error during transaction, " + rollbackMessage, transactionException);
throw e;
} finally {
txnInfo.clear();
}

View File

@@ -14,8 +14,13 @@
package google.registry.model.transaction;
import com.google.appengine.api.utils.SystemProperty;
import com.google.appengine.api.utils.SystemProperty.Environment.Value;
import com.google.common.annotations.VisibleForTesting;
import google.registry.model.ofy.DatastoreTransactionManager;
import google.registry.persistence.DaggerPersistenceComponent;
import google.registry.tools.RegistryToolEnvironment;
/** Factory class to create {@link TransactionManager} instance. */
// TODO: Rename this to PersistenceFactory and move to persistence package.
@@ -27,19 +32,14 @@ public class TransactionManagerFactory {
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();
if (isInAppEngine()) {
return DaggerPersistenceComponent.create().appEngineJpaTransactionManager();
} else if (RegistryToolEnvironment.isInRegistryTool()
&& RegistryToolEnvironment.isJpaTmEnabled()) {
return DaggerPersistenceComponent.create().nomulusToolJpaTransactionManager();
} else {
return DummyJpaTransactionManager.create();
}
}
private static TransactionManager createTransactionManager() {
@@ -50,12 +50,16 @@ public class TransactionManagerFactory {
}
/**
* 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.
* This function uses App Engine API to determine if the current runtime environment is App
* Engine.
*
* @see <a
* href="https://cloud.google.com/appengine/docs/standard/java/javadoc/com/google/appengine/api/utils/SystemProperty">App
* Engine API public doc</a>
*/
public static void initForTool() {
// TODO(shicong): Uncomment the line below when we set up Cloud SQL instance in all environments
// jpaTm = DaggerPersistenceComponent.create().nomulusToolJpaTransactionManager();
private static boolean isInAppEngine() {
// SystemProperty.environment.value() returns null if the current runtime is local JVM
return SystemProperty.environment.value() == Value.Production;
}
/** Returns {@link TransactionManager} instance. */

View File

@@ -30,6 +30,7 @@ import google.registry.ui.server.registrar.ConsoleUiAction;
import google.registry.ui.server.registrar.OteStatusAction;
import google.registry.ui.server.registrar.RegistrarConsoleModule;
import google.registry.ui.server.registrar.RegistrarSettingsAction;
import google.registry.ui.server.registrar.RegistryLockGetAction;
/** Dagger component with per-request lifetime for "default" App Engine module. */
@RequestScope
@@ -50,6 +51,8 @@ interface FrontendRequestComponent {
OteStatusAction oteStatusAction();
RegistrarSettingsAction registrarSettingsAction();
RegistryLockGetAction registryLockGetAction();
@Subcomponent.Builder
abstract class Builder implements RequestComponentBuilder<FrontendRequestComponent> {
@Override public abstract Builder requestModule(RequestModule requestModule);

View File

@@ -0,0 +1,29 @@
// 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 javax.annotation.Nullable;
import javax.persistence.Converter;
import org.joda.money.CurrencyUnit;
/** JPA converter for {@link CurrencyUnit}s. */
@Converter(autoApply = true)
public class CurrencyUnitConverter extends ToStringConverterBase<CurrencyUnit> {
@Override
@Nullable
public CurrencyUnit convertToEntityAttribute(@Nullable String columnValue) {
return (columnValue == null) ? null : CurrencyUnit.of(columnValue);
}
}

View File

@@ -0,0 +1,41 @@
// 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 org.joda.time.DateTimeZone.UTC;
import java.sql.Timestamp;
import javax.annotation.Nullable;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import org.joda.time.DateTime;
/** JPA converter to for storing/retrieving {@link org.joda.time.DateTime} objects. */
@Converter(autoApply = true)
public class DateTimeConverter implements AttributeConverter<DateTime, Timestamp> {
@Override
@Nullable
public Timestamp convertToDatabaseColumn(@Nullable DateTime attribute) {
return attribute == null ? null : new Timestamp(attribute.getMillis());
}
@Override
@Nullable
public DateTime convertToEntityAttribute(@Nullable Timestamp dbData) {
DateTime result = dbData == null ? null : new DateTime(dbData.getTime(), UTC);
return result;
}
}

View File

@@ -0,0 +1,86 @@
// 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.collect.ImmutableList.toImmutableList;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import java.io.File;
import java.util.EnumSet;
import java.util.Map;
import java.util.stream.Stream;
import javax.persistence.AttributeConverter;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Environment;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType;
/** Utility class to export DDL script for given {@link javax.persistence.Entity} classes. */
public class HibernateSchemaExporter {
private final String jdbcUrl;
private final String username;
private final String password;
private HibernateSchemaExporter(String jdbcUrl, String username, String password) {
this.jdbcUrl = jdbcUrl;
this.username = username;
this.password = password;
}
/** Constructs a {@link HibernateSchemaExporter} instance. */
public static HibernateSchemaExporter create(String jdbcUrl, String username, String password) {
return new HibernateSchemaExporter(jdbcUrl, username, password);
}
/** Exports DDL script to the {@code outputFile} for the given {@code entityClasses}. */
public void export(ImmutableList<Class> entityClasses, File outputFile) {
// Configure Hibernate settings.
Map<String, String> settings = Maps.newHashMap();
settings.put(Environment.DIALECT, NomulusPostgreSQLDialect.class.getName());
settings.put(Environment.URL, jdbcUrl);
settings.put(Environment.USER, username);
settings.put(Environment.PASS, password);
settings.put(Environment.HBM2DDL_AUTO, "none");
settings.put(Environment.SHOW_SQL, "true");
settings.put(
Environment.PHYSICAL_NAMING_STRATEGY, NomulusNamingStrategy.class.getCanonicalName());
try (StandardServiceRegistry registry =
new StandardServiceRegistryBuilder().applySettings(settings).build()) {
MetadataSources metadata = new MetadataSources(registry);
// Note that we need to also add all converters to the Hibernate context because
// the entity class may use the customized type.
Stream.concat(entityClasses.stream(), findAllConverters().stream())
.forEach(metadata::addAnnotatedClass);
SchemaExport export = new SchemaExport();
export.setHaltOnError(true);
export.setFormat(true);
export.setDelimiter(";");
export.setOutputFile(outputFile.getAbsolutePath());
export.createOnly(EnumSet.of(TargetType.SCRIPT), metadata.buildMetadata());
}
}
private ImmutableList<Class> findAllConverters() {
return PersistenceXmlUtility.getManagedClasses().stream()
.filter(AttributeConverter.class::isAssignableFrom)
.collect(toImmutableList());
}
}

View File

@@ -51,6 +51,10 @@ public class PersistenceModule {
public static final String HIKARI_MAXIMUM_POOL_SIZE = "hibernate.hikari.maximumPoolSize";
public static final String HIKARI_IDLE_TIMEOUT = "hibernate.hikari.idleTimeout";
public static final String HIKARI_DS_SOCKET_FACTORY = "hibernate.hikari.dataSource.socketFactory";
public static final String HIKARI_DS_CLOUD_SQL_INSTANCE =
"hibernate.hikari.dataSource.cloudSqlInstance";
@Provides
@DefaultHibernateConfigs
public static ImmutableMap<String, String> providesDefaultDatabaseConfigs() {
@@ -79,27 +83,31 @@ public class PersistenceModule {
return properties.build();
}
@Provides
@Singleton
@PartialCloudSqlConfigs
public static ImmutableMap<String, String> providesPartialCloudSqlConfigs(
@Config("cloudSqlJdbcUrl") String jdbcUrl,
@Config("cloudSqlInstanceConnectionName") String instanceConnectionName,
@DefaultHibernateConfigs ImmutableMap<String, String> defaultConfigs) {
HashMap<String, String> overrides = Maps.newHashMap(defaultConfigs);
overrides.put(Environment.URL, jdbcUrl);
overrides.put(HIKARI_DS_SOCKET_FACTORY, "com.google.cloud.sql.postgres.SocketFactory");
overrides.put(HIKARI_DS_CLOUD_SQL_INSTANCE, instanceConnectionName);
return ImmutableMap.copyOf(overrides);
}
@Provides
@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,
@PartialCloudSqlConfigs ImmutableMap<String, String> cloudSqlConfigs,
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);
overrides.put(Environment.URL, jdbcUrl);
HashMap<String, String> overrides = Maps.newHashMap(cloudSqlConfigs);
overrides.put(Environment.USER, username);
overrides.put(Environment.PASS, kmsKeyring.getCloudSqlPassword());
return new JpaTransactionManagerImpl(create(overrides), clock);
}
@@ -107,27 +115,13 @@ public class PersistenceModule {
@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,
@PartialCloudSqlConfigs ImmutableMap<String, String> cloudSqlConfigs,
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);
HashMap<String, String> overrides = Maps.newHashMap(cloudSqlConfigs);
overrides.put(Environment.USER, username);
overrides.put(Environment.PASS, kmsKeyring.getToolsCloudSqlPassword());
return new JpaTransactionManagerImpl(create(overrides), clock);
}
@@ -166,6 +160,11 @@ public class PersistenceModule {
@Documented
@interface NomulusToolJpaTm {}
/** Dagger qualifier for the partial Cloud SQL configs. */
@Qualifier
@Documented
@interface PartialCloudSqlConfigs {}
/** 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

View File

@@ -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.collect.ImmutableList.toImmutableList;
import com.google.common.collect.ImmutableList;
import java.util.Properties;
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
/** Utility class that provides methods to manipulate persistence.xml file. */
public class PersistenceXmlUtility {
private PersistenceXmlUtility() {}
/**
* Returns the {@link ParsedPersistenceXmlDescriptor} instance constructed from persistence.xml.
*/
public static ParsedPersistenceXmlDescriptor getParsedPersistenceXmlDescriptor() {
return PersistenceXmlParser.locatePersistenceUnits(new 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)));
}
/** Returns all managed classes defined in persistence.xml. */
public static ImmutableList<Class> getManagedClasses() {
return getParsedPersistenceXmlDescriptor().getManagedClassNames().stream()
.map(
className -> {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(
String.format(
"Could not load class with name %s present in persistence.xml", className),
e);
}
})
.collect(toImmutableList());
}
}

View File

@@ -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 javax.annotation.Nullable;
import javax.persistence.AttributeConverter;
/** Abstract JPA converter for objects that are stored by their toString() value. */
abstract class ToStringConverterBase<T> implements AttributeConverter<T, String> {
@Override
@Nullable
public String convertToDatabaseColumn(@Nullable T entity) {
return (entity == null) ? null : entity.toString();
}
}

View File

@@ -39,6 +39,7 @@ import google.registry.util.Retrier;
import google.registry.util.SendEmailService;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.mail.internet.InternetAddress;
@@ -102,7 +103,7 @@ public final class IcannReportingUploadAction implements Runnable {
final byte[] payload = readBytesFromGcs(gcsFilename);
return icannReporter.send(payload, reportFilename);
},
IOException.class);
IcannReportingUploadAction::isUploadFailureRetryable);
} catch (RuntimeException e) {
logger.atWarning().withCause(e).log("Upload to %s failed.", gcsFilename);
}
@@ -115,6 +116,21 @@ public final class IcannReportingUploadAction implements Runnable {
String.format("OK, attempted uploading %d reports", manifestedFiles.size()));
}
/** Don't retry when reports are already uploaded or can't be uploaded. */
private static final String ICANN_UPLOAD_PERMANENT_ERROR_MESSAGE =
"A report for that month already exists, the cut-off date already passed.";
/** Don't retry when the IP address isn't whitelisted, as retries go through the same IP. */
private static final Pattern ICANN_UPLOAD_WHITELIST_ERROR =
Pattern.compile("Your IP address .+ is not allowed to connect");
/** Predicate to retry uploads on IOException, so long as they aren't non-retryable errors. */
private static boolean isUploadFailureRetryable(Throwable e) {
return (e instanceof IOException)
&& !e.getMessage().contains(ICANN_UPLOAD_PERMANENT_ERROR_MESSAGE)
&& !ICANN_UPLOAD_WHITELIST_ERROR.matcher(e.getMessage()).matches();
}
private void emailUploadResults(ImmutableMap<String, Boolean> reportSummary) {
String subject = String.format(
"ICANN Monthly report upload summary: %d/%d succeeded",

View File

@@ -347,7 +347,7 @@ public class AuthenticatedRegistrarAccessor {
/** Exception thrown when the current user doesn't have access to the requested Registrar. */
public static class RegistrarAccessDeniedException extends Exception {
RegistrarAccessDeniedException(String message) {
public RegistrarAccessDeniedException(String message) {
super(message);
}
}

View File

@@ -65,7 +65,8 @@ import org.joda.time.DateTime;
name = "idx_registry_lock_repo_id_revision_id",
columnList = "repoId, revisionId",
unique = true),
@Index(name = "idx_registry_lock_verification_code", columnList = "verificationCode")
@Index(name = "idx_registry_lock_verification_code", columnList = "verificationCode"),
@Index(name = "idx_registry_lock_registrar_id", columnList = "registrarId")
})
public final class RegistryLock extends ImmutableObject implements Buildable {
@@ -175,12 +176,13 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
this.completionTimestamp = toZonedDateTime(dateTime);
}
public boolean isVerified() {
return completionTimestamp != null;
}
@Override
public Builder asBuilder() {
RegistryLock clone = clone(this);
// Revision ID should be different for every object
clone.revisionId = null;
return new Builder(clone);
return new Builder(clone(this));
}
/** Builder for {@link google.registry.schema.domain.RegistryLock}. */

View File

@@ -72,7 +72,7 @@ final class CreateDomainCommand extends CreateOrUpdateDomainCommand
!force || forcePremiums,
"Forced creates on premium domain(s) require --force_premiums");
Money createCost = prices.getCreateCost();
currency = createCost.getCurrencyUnit().getCurrencyCode();
currency = createCost.getCurrencyUnit().getCode();
cost = createCost.multipliedBy(period).getAmount().toString();
System.out.printf(
"NOTE: %s is premium at %s per year; sending total cost for %d year(s) of %s %s.\n",

View File

@@ -19,23 +19,12 @@ 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 google.registry.persistence.NomulusNamingStrategy;
import google.registry.persistence.NomulusPostgreSQLDialect;
import google.registry.persistence.PersistenceModule;
import google.registry.persistence.HibernateSchemaExporter;
import google.registry.persistence.NomulusPostgreSql;
import google.registry.persistence.PersistenceXmlUtility;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
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.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.testcontainers.containers.PostgreSQLContainer;
/**
@@ -47,6 +36,9 @@ import org.testcontainers.containers.PostgreSQLContainer;
*/
@Parameters(separators = " =", commandDescription = "Generate PostgreSQL schema.")
public class GenerateSqlSchemaCommand implements Command {
private static final String DB_NAME = "postgres";
private static final String DB_USERNAME = "postgres";
private static final String DB_PASSWORD = "domain-registry";
@VisibleForTesting
public static final String DB_OPTIONS_CLASH =
@@ -91,10 +83,11 @@ public class GenerateSqlSchemaCommand implements Command {
}
// Start the container and store the address information.
postgresContainer = new PostgreSQLContainer()
.withDatabaseName("postgres")
.withUsername("postgres")
.withPassword("domain-registry");
postgresContainer =
new PostgreSQLContainer(NomulusPostgreSql.getDockerTag())
.withDatabaseName(DB_NAME)
.withUsername(DB_USERNAME)
.withPassword(DB_PASSWORD);
postgresContainer.start();
databaseHost = postgresContainer.getContainerIpAddress();
databasePort = postgresContainer.getMappedPort(POSTGRESQL_PORT);
@@ -119,29 +112,7 @@ public class GenerateSqlSchemaCommand implements Command {
}
try {
// Configure Hibernate settings.
Map<String, String> settings = new HashMap<>();
settings.put("hibernate.dialect", NomulusPostgreSQLDialect.class.getName());
settings.put(
"hibernate.connection.url",
"jdbc:postgresql://" + databaseHost + ":" + databasePort + "/postgres?useSSL=false");
settings.put("hibernate.connection.username", "postgres");
settings.put("hibernate.connection.password", "domain-registry");
settings.put("hibernate.hbm2ddl.auto", "none");
settings.put("show_sql", "true");
settings.put(
Environment.PHYSICAL_NAMING_STRATEGY, NomulusNamingStrategy.class.getCanonicalName());
MetadataSources metadata =
new MetadataSources(new StandardServiceRegistryBuilder().applySettings(settings).build());
addAnnotatedClasses(metadata, settings);
SchemaExport schemaExport = new SchemaExport();
schemaExport.setHaltOnError(true);
schemaExport.setFormat(true);
schemaExport.setDelimiter(";");
schemaExport.setOutputFile(outFile);
File outputFile = new File(outFile);
// Generate the copyright header (this file gets checked for copyright). The schema exporter
// appends to the existing file, so this has the additional desired effect of clearing any
@@ -161,44 +132,30 @@ public class GenerateSqlSchemaCommand implements Command {
+ "-- See the License for the specific language governing permissions and\n"
+ "-- limitations under the License.\n";
try {
Files.write(Paths.get(outFile), copyright.getBytes(UTF_8));
Files.write(outputFile.toPath(), copyright.getBytes(UTF_8));
} catch (IOException e) {
System.err.println("Error writing sql file: " + e);
e.printStackTrace();
System.exit(1);
}
schemaExport.createOnly(EnumSet.of(TargetType.SCRIPT), metadata.buildMetadata());
HibernateSchemaExporter exporter =
HibernateSchemaExporter.create(
"jdbc:postgresql://"
+ databaseHost
+ ":"
+ databasePort
+ "/"
+ DB_NAME
+ "?useSSL=false",
DB_USERNAME,
DB_PASSWORD);
exporter.export(PersistenceXmlUtility.getManagedClasses(), outputFile);
} finally {
if (postgresContainer != null) {
postgresContainer.stop();
}
}
}
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);
}
}
}
}

View File

@@ -31,7 +31,6 @@ 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;
@@ -237,7 +236,7 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
}
if (command instanceof CommandWithCloudSql) {
TransactionManagerFactory.initForTool();
RegistryToolEnvironment.get().enableJpaTm();
}
command.run();

View File

@@ -25,7 +25,7 @@ import google.registry.config.RegistryEnvironment;
import google.registry.config.SystemPropertySetter;
/** Enum of production environments, used for the {@code --environment} flag. */
enum RegistryToolEnvironment {
public enum RegistryToolEnvironment {
PRODUCTION(RegistryEnvironment.PRODUCTION),
ALPHA(RegistryEnvironment.ALPHA),
CRASH(RegistryEnvironment.CRASH),
@@ -39,6 +39,7 @@ enum RegistryToolEnvironment {
private static final ImmutableList<String> FLAGS = ImmutableList.of("-e", "--environment");
private static RegistryToolEnvironment instance;
private static boolean isJpaTmEnabled = false;
private final RegistryEnvironment actualEnvironment;
private final ImmutableMap<String, String> extraProperties;
@@ -72,7 +73,7 @@ enum RegistryToolEnvironment {
*
* <p>This should be called after {@link #parseFromArgs(String[])}.
*/
static RegistryToolEnvironment get() {
public static RegistryToolEnvironment get() {
checkState(instance != null, "No RegistryToolEnvironment has been set up");
return instance;
}
@@ -98,6 +99,26 @@ enum RegistryToolEnvironment {
}
}
/** Returns true if the RegistryToolEnvironment is set up. */
public static boolean isInRegistryTool() {
return instance != null;
}
/**
* Sets the flag to indicate that the running command needs JpaTransactionManager to be enabled.
*/
public static void enableJpaTm() {
isJpaTmEnabled = true;
}
/**
* Returns true if the JpaTransactionManager is enabled. Note that JpaTm is actually enabled in
* {@link google.registry.model.transaction.TransactionManagerFactory} by reading this flag.
*/
public static boolean isJpaTmEnabled() {
return isJpaTmEnabled;
}
/** Extracts value from command-line arguments associated with any {@code flags}. */
private static String getFlagValue(String[] args, Iterable<String> flags) {
for (String flag : flags) {

View File

@@ -32,7 +32,7 @@ import java.util.List;
/** A command to upload a {@link ClaimsListShard}. */
@Parameters(separators = " =", commandDescription = "Manually upload a new claims list file")
final class UploadClaimsListCommand extends ConfirmingCommand implements CommandWithRemoteApi {
final class UploadClaimsListCommand extends ConfirmingCommand implements CommandWithCloudSql {
@Parameter(description = "Claims list filename")
private List<String> mainParameters = new ArrayList<>();

View File

@@ -21,7 +21,9 @@ import static google.registry.util.DomainNameUtils.canonicalizeDomainName;
import com.google.common.base.Ascii;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.InternetDomainName;
import com.google.re2j.Pattern;
import google.registry.model.registrar.Registrar;
@@ -194,12 +196,10 @@ public final class RegistrarFormFields {
FormField.named("visibleInDomainWhoisAsAbuse", Boolean.class).build();
public static final FormField<String, String> CONTACT_PHONE_NUMBER_FIELD =
FormFields.PHONE_NUMBER.asBuilder()
.build();
FormFields.PHONE_NUMBER.asBuilder().build();
public static final FormField<String, String> CONTACT_FAX_NUMBER_FIELD =
FormFields.PHONE_NUMBER.asBuilderNamed("faxNumber")
.build();
FormFields.PHONE_NUMBER.asBuilderNamed("faxNumber").build();
public static final FormField<String, String> CONTACT_GAE_USER_ID_FIELD =
FormFields.NAME.asBuilderNamed("gaeUserId").build();
@@ -217,11 +217,8 @@ public final class RegistrarFormFields {
.asSet(Splitter.on(',').omitEmptyStrings().trimResults())
.build();
public static final FormField<List<Map<String, ?>>, List<RegistrarContact.Builder>>
CONTACTS_FIELD = FormField.mapNamed("contacts")
.transform(RegistrarContact.Builder.class, RegistrarFormFields::toRegistrarContactBuilder)
.asList()
.build();
public static final FormField<List<Map<String, ?>>, List<Map<String, ?>>> CONTACTS_AS_MAPS =
FormField.mapNamed("contacts").asList().build();
public static final FormField<List<String>, List<String>> I18N_STREET_FIELD =
FormFields.XS_NORMALIZED_STRING.asBuilderNamed("street")
@@ -344,33 +341,60 @@ public final class RegistrarFormFields {
}
}
private static @Nullable RegistrarContact.Builder toRegistrarContactBuilder(
@Nullable Map<String, ?> args) {
public static ImmutableList<RegistrarContact.Builder> getRegistrarContactBuilders(
ImmutableSet<RegistrarContact> existingContacts, @Nullable Map<String, ?> args) {
if (args == null) {
return null;
return ImmutableList.of();
}
RegistrarContact.Builder builder = new RegistrarContact.Builder();
CONTACT_NAME_FIELD.extractUntyped(args).ifPresent(builder::setName);
CONTACT_EMAIL_ADDRESS_FIELD.extractUntyped(args).ifPresent(builder::setEmailAddress);
CONTACT_VISIBLE_IN_WHOIS_AS_ADMIN_FIELD
.extractUntyped(args)
.ifPresent(builder::setVisibleInWhoisAsAdmin);
CONTACT_VISIBLE_IN_WHOIS_AS_TECH_FIELD
.extractUntyped(args)
.ifPresent(builder::setVisibleInWhoisAsTech);
PHONE_AND_EMAIL_VISIBLE_IN_DOMAIN_WHOIS_AS_ABUSE_FIELD
.extractUntyped(args)
.ifPresent(builder::setVisibleInDomainWhoisAsAbuse);
CONTACT_PHONE_NUMBER_FIELD.extractUntyped(args).ifPresent(builder::setPhoneNumber);
CONTACT_FAX_NUMBER_FIELD.extractUntyped(args).ifPresent(builder::setFaxNumber);
CONTACT_TYPES.extractUntyped(args).ifPresent(builder::setTypes);
CONTACT_GAE_USER_ID_FIELD.extractUntyped(args).ifPresent(builder::setGaeUserId);
CONTACT_ALLOWED_TO_SET_REGISTRY_LOCK_PASSWORD
.extractUntyped(args)
.ifPresent(builder::setAllowedToSetRegistryLockPassword);
Optional<List<Map<String, ?>>> contactsAsMaps = CONTACTS_AS_MAPS.extractUntyped(args);
if (!contactsAsMaps.isPresent()) {
return ImmutableList.of();
}
ImmutableList.Builder<RegistrarContact.Builder> result = new ImmutableList.Builder<>();
for (Map<String, ?> contactAsMap : contactsAsMaps.get()) {
String emailAddress =
CONTACT_EMAIL_ADDRESS_FIELD
.extractUntyped(contactAsMap)
.orElseThrow(
() -> new IllegalArgumentException("Contacts from UI must have email addresses"));
// Start with a new builder if the contact didn't previously exist
RegistrarContact.Builder contactBuilder =
existingContacts.stream()
.filter(rc -> rc.getEmailAddress().equals(emailAddress))
.findFirst()
.map(RegistrarContact::asBuilder)
.orElse(new RegistrarContact.Builder());
applyRegistrarContactArgs(contactBuilder, contactAsMap);
result.add(contactBuilder);
}
return result.build();
}
private static void applyRegistrarContactArgs(
RegistrarContact.Builder builder, Map<String, ?> args) {
builder.setName(CONTACT_NAME_FIELD.extractUntyped(args).orElse(null));
builder.setEmailAddress(CONTACT_EMAIL_ADDRESS_FIELD.extractUntyped(args).orElse(null));
builder.setVisibleInWhoisAsAdmin(
CONTACT_VISIBLE_IN_WHOIS_AS_ADMIN_FIELD.extractUntyped(args).orElse(false));
builder.setVisibleInWhoisAsTech(
CONTACT_VISIBLE_IN_WHOIS_AS_TECH_FIELD.extractUntyped(args).orElse(false));
builder.setVisibleInDomainWhoisAsAbuse(
PHONE_AND_EMAIL_VISIBLE_IN_DOMAIN_WHOIS_AS_ABUSE_FIELD.extractUntyped(args).orElse(false));
builder.setPhoneNumber(CONTACT_PHONE_NUMBER_FIELD.extractUntyped(args).orElse(null));
builder.setFaxNumber(CONTACT_FAX_NUMBER_FIELD.extractUntyped(args).orElse(null));
builder.setTypes(CONTACT_TYPES.extractUntyped(args).orElse(ImmutableSet.of()));
builder.setGaeUserId(CONTACT_GAE_USER_ID_FIELD.extractUntyped(args).orElse(null));
builder.setAllowedToSetRegistryLockPassword(
CONTACT_ALLOWED_TO_SET_REGISTRY_LOCK_PASSWORD.extractUntyped(args).orElse(false));
// Registry lock password does not need to be set every time
CONTACT_REGISTRY_LOCK_PASSWORD_FIELD
.extractUntyped(args)
.ifPresent(builder::setRegistryLockPassword);
return builder;
.ifPresent(
password -> {
if (!Strings.isNullOrEmpty(password)) {
builder.setRegistryLockPassword(password);
}
});
}
}

View File

@@ -19,6 +19,7 @@ import static com.google.common.io.Resources.asCharSource;
import static com.google.common.io.Resources.getResource;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
@@ -42,6 +43,12 @@ import java.util.Map;
/** Helper methods for rendering Soy templates from Java code. */
public final class SoyTemplateUtils {
@VisibleForTesting
public static final Supplier<SoyCssRenamingMap> CSS_RENAMING_MAP_SUPPLIER =
SoyTemplateUtils.createCssRenamingMapSupplier(
Resources.getResource("google/registry/ui/css/registrar_bin.css.js"),
Resources.getResource("google/registry/ui/css/registrar_dbg.css.js"));
/** Returns a memoized supplier containing compiled tofu. */
public static Supplier<SoyTofu> createTofuSupplier(final SoyFileInfo... soyInfos) {
return memoize(

View File

@@ -15,45 +15,30 @@
package google.registry.ui.server.registrar;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.net.HttpHeaders.LOCATION;
import static com.google.common.net.HttpHeaders.X_FRAME_OPTIONS;
import static google.registry.config.RegistryEnvironment.PRODUCTION;
import static google.registry.ui.server.SoyTemplateUtils.CSS_RENAMING_MAP_SUPPLIER;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Ascii;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.Resources;
import com.google.common.net.MediaType;
import com.google.template.soy.shared.SoyCssRenamingMap;
import com.google.template.soy.tofu.SoyTofu;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryEnvironment;
import google.registry.model.OteAccountBuilder;
import google.registry.request.Action;
import google.registry.request.Action.Method;
import google.registry.request.Parameter;
import google.registry.request.RequestMethod;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.security.XsrfTokenManager;
import google.registry.ui.server.SendEmailUtils;
import google.registry.ui.server.SoyTemplateUtils;
import google.registry.ui.soy.registrar.OteSetupConsoleSoyInfo;
import google.registry.util.StringGenerator;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
/**
* Action that serves OT&amp;E setup web page.
@@ -69,14 +54,9 @@ import javax.servlet.http.HttpServletRequest;
path = ConsoleOteSetupAction.PATH,
method = {Method.POST, Method.GET},
auth = Auth.AUTH_PUBLIC)
public final class ConsoleOteSetupAction implements Runnable {
public final class ConsoleOteSetupAction extends HtmlAction {
public static final String PATH = "/registrar-ote-setup";
@VisibleForTesting // webdriver and screenshot tests need this
public static final Supplier<SoyCssRenamingMap> CSS_RENAMING_MAP_SUPPLIER =
SoyTemplateUtils.createCssRenamingMapSupplier(
Resources.getResource("google/registry/ui/css/registrar_bin.css.js"),
Resources.getResource("google/registry/ui/css/registrar_dbg.css.js"));
private static final int PASSWORD_LENGTH = 16;
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final Supplier<SoyTofu> TOFU_SUPPLIER =
@@ -85,27 +65,10 @@ public final class ConsoleOteSetupAction implements Runnable {
google.registry.ui.soy.FormsSoyInfo.getInstance(),
google.registry.ui.soy.AnalyticsSoyInfo.getInstance(),
google.registry.ui.soy.registrar.OteSetupConsoleSoyInfo.getInstance());
@Inject HttpServletRequest req;
@Inject @RequestMethod Method method;
@Inject Response response;
@Inject AuthenticatedRegistrarAccessor registrarAccessor;
@Inject UserService userService;
@Inject XsrfTokenManager xsrfTokenManager;
@Inject AuthResult authResult;
@Inject SendEmailUtils sendEmailUtils;
@Inject
@Config("logoFilename")
String logoFilename;
@Inject
@Config("productName")
String productName;
@Inject
@Config("analyticsConfig")
Map<String, Object> analyticsConfig;
@Inject
@Named("base58StringGenerator")
StringGenerator passwordGenerator;
@@ -126,43 +89,9 @@ public final class ConsoleOteSetupAction implements Runnable {
ConsoleOteSetupAction() {}
@Override
public void run() {
response.setHeader(X_FRAME_OPTIONS, "SAMEORIGIN"); // Disallow iframing.
response.setHeader("X-Ui-Compatible", "IE=edge"); // Ask IE not to be silly.
logger.atInfo().log(
"User %s is accessing the OT&E setup page. Method= %s",
registrarAccessor.userIdForLogging(), method);
public void runAfterLogin(HashMap<String, Object> data) {
checkState(
!RegistryEnvironment.get().equals(PRODUCTION), "Can't create OT&E in prod");
if (!authResult.userAuthInfo().isPresent()) {
response.setStatus(SC_MOVED_TEMPORARILY);
String location;
try {
location = userService.createLoginURL(req.getRequestURI());
} catch (IllegalArgumentException e) {
// UserServiceImpl.createLoginURL() throws IllegalArgumentException if underlying API call
// returns an error code of NOT_ALLOWED. createLoginURL() assumes that the error is caused
// by an invalid URL. But in fact, the error can also occur if UserService doesn't have any
// user information, which happens when the request has been authenticated as internal. In
// this case, we want to avoid dying before we can send the redirect, so just redirect to
// the root path.
location = "/";
}
response.setHeader(LOCATION, location);
return;
}
User user = authResult.userAuthInfo().get().user();
// Using HashMap to allow null values
HashMap<String, Object> data = new HashMap<>();
data.put("logoFilename", logoFilename);
data.put("productName", productName);
data.put("username", user.getNickname());
data.put("logoutUrl", userService.createLogoutURL(PATH));
data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail()));
data.put("analyticsConfig", analyticsConfig);
response.setContentType(MediaType.HTML_UTF_8);
if (!registrarAccessor.isAdmin()) {
response.setStatus(SC_FORBIDDEN);
@@ -187,6 +116,11 @@ public final class ConsoleOteSetupAction implements Runnable {
}
}
@Override
public String getPath() {
return PATH;
}
private void runPost(HashMap<String, Object> data) {
try {
checkState(clientId.isPresent() && email.isPresent(), "Must supply clientId and email");

View File

@@ -18,27 +18,18 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.net.HttpHeaders.LOCATION;
import static com.google.common.net.HttpHeaders.X_FRAME_OPTIONS;
import static google.registry.model.common.GaeUserIdConverter.convertEmailAddressToGaeUserId;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.transaction.TransactionManagerFactory.tm;
import static google.registry.ui.server.SoyTemplateUtils.CSS_RENAMING_MAP_SUPPLIER;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Ascii;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.Resources;
import com.google.common.net.MediaType;
import com.google.template.soy.shared.SoyCssRenamingMap;
import com.google.template.soy.tofu.SoyTofu;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryEnvironment;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
@@ -46,23 +37,17 @@ import google.registry.model.registrar.RegistrarContact;
import google.registry.request.Action;
import google.registry.request.Action.Method;
import google.registry.request.Parameter;
import google.registry.request.RequestMethod;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.security.XsrfTokenManager;
import google.registry.ui.server.SendEmailUtils;
import google.registry.ui.server.SoyTemplateUtils;
import google.registry.ui.soy.registrar.RegistrarCreateConsoleSoyInfo;
import google.registry.util.StringGenerator;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import org.joda.money.CurrencyUnit;
/**
@@ -79,7 +64,7 @@ import org.joda.money.CurrencyUnit;
path = ConsoleRegistrarCreatorAction.PATH,
method = {Method.POST, Method.GET},
auth = Auth.AUTH_PUBLIC)
public final class ConsoleRegistrarCreatorAction implements Runnable {
public final class ConsoleRegistrarCreatorAction extends HtmlAction {
private static final int PASSWORD_LENGTH = 16;
private static final int PASSCODE_LENGTH = 5;
@@ -95,23 +80,8 @@ public final class ConsoleRegistrarCreatorAction implements Runnable {
google.registry.ui.soy.AnalyticsSoyInfo.getInstance(),
google.registry.ui.soy.registrar.RegistrarCreateConsoleSoyInfo.getInstance());
@VisibleForTesting // webdriver and screenshot tests need this
public static final Supplier<SoyCssRenamingMap> CSS_RENAMING_MAP_SUPPLIER =
SoyTemplateUtils.createCssRenamingMapSupplier(
Resources.getResource("google/registry/ui/css/registrar_bin.css.js"),
Resources.getResource("google/registry/ui/css/registrar_dbg.css.js"));
@Inject HttpServletRequest req;
@Inject @RequestMethod Method method;
@Inject Response response;
@Inject AuthenticatedRegistrarAccessor registrarAccessor;
@Inject UserService userService;
@Inject XsrfTokenManager xsrfTokenManager;
@Inject AuthResult authResult;
@Inject SendEmailUtils sendEmailUtils;
@Inject @Config("logoFilename") String logoFilename;
@Inject @Config("productName") String productName;
@Inject @Config("analyticsConfig") Map<String, Object> analyticsConfig;
@Inject @Named("base58StringGenerator") StringGenerator passwordGenerator;
@Inject @Named("digitOnlyStringGenerator") StringGenerator passcodeGenerator;
@Inject @Parameter("clientId") Optional<String> clientId;
@@ -137,42 +107,7 @@ public final class ConsoleRegistrarCreatorAction implements Runnable {
@Inject ConsoleRegistrarCreatorAction() {}
@Override
public void run() {
response.setHeader(X_FRAME_OPTIONS, "SAMEORIGIN"); // Disallow iframing.
response.setHeader("X-Ui-Compatible", "IE=edge"); // Ask IE not to be silly.
logger.atInfo().log(
"User %s is accessing the Registrar creation page. Method= %s",
registrarAccessor.userIdForLogging(), method);
if (!authResult.userAuthInfo().isPresent()) {
response.setStatus(SC_MOVED_TEMPORARILY);
String location;
try {
location = userService.createLoginURL(req.getRequestURI());
} catch (IllegalArgumentException e) {
// UserServiceImpl.createLoginURL() throws IllegalArgumentException if underlying API call
// returns an error code of NOT_ALLOWED. createLoginURL() assumes that the error is caused
// by an invalid URL. But in fact, the error can also occur if UserService doesn't have any
// user information, which happens when the request has been authenticated as internal. In
// this case, we want to avoid dying before we can send the redirect, so just redirect to
// the root path.
location = "/";
}
response.setHeader(LOCATION, location);
return;
}
User user = authResult.userAuthInfo().get().user();
// Using HashMap to allow null values
HashMap<String, Object> data = new HashMap<>();
data.put("logoFilename", logoFilename);
data.put("productName", productName);
data.put("username", user.getNickname());
data.put("logoutUrl", userService.createLogoutURL(PATH));
data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail()));
data.put("analyticsConfig", analyticsConfig);
response.setContentType(MediaType.HTML_UTF_8);
public void runAfterLogin(HashMap<String, Object> data) {
if (!registrarAccessor.isAdmin()) {
response.setStatus(SC_FORBIDDEN);
response.setPayload(
@@ -196,6 +131,11 @@ public final class ConsoleRegistrarCreatorAction implements Runnable {
}
}
@Override
public String getPath() {
return PATH;
}
private void checkPresent(Optional<?> value, String name) {
checkState(value.isPresent(), "Missing value for %s", name);
}
@@ -226,7 +166,6 @@ public final class ConsoleRegistrarCreatorAction implements Runnable {
private void runPost(HashMap<String, Object> data) {
try {
checkPresent(clientId, "clientId");
checkPresent(name, "name");
checkPresent(billingAccount, "billingAccount");
@@ -321,11 +260,11 @@ public final class ConsoleRegistrarCreatorAction implements Runnable {
data.put("errorMessage", e.getMessage());
response.setPayload(
TOFU_SUPPLIER
.get()
.newRenderer(RegistrarCreateConsoleSoyInfo.FORM_PAGE)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.render());
.get()
.newRenderer(RegistrarCreateConsoleSoyInfo.FORM_PAGE)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.render());
}
}
@@ -357,8 +296,8 @@ public final class ConsoleRegistrarCreatorAction implements Runnable {
String environment = Ascii.toLowerCase(String.valueOf(RegistryEnvironment.get()));
String body =
String.format(
"The following registrar was created in %s by %s:\n",
environment, registrarAccessor.userIdForLogging())
"The following registrar was created in %s by %s:\n",
environment, registrarAccessor.userIdForLogging())
+ toEmailLine(clientId, "clientId")
+ toEmailLine(name, "name")
+ toEmailLine(billingAccount, "billingAccount")

View File

@@ -14,47 +14,35 @@
package google.registry.ui.server.registrar;
import static com.google.common.net.HttpHeaders.LOCATION;
import static com.google.common.net.HttpHeaders.X_FRAME_OPTIONS;
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.ADMIN;
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.OWNER;
import static google.registry.ui.server.SoyTemplateUtils.CSS_RENAMING_MAP_SUPPLIER;
import static google.registry.ui.server.registrar.RegistrarConsoleModule.PARAM_CLIENT_ID;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.Resources;
import com.google.common.net.MediaType;
import com.google.template.soy.data.SoyMapData;
import com.google.template.soy.shared.SoyCssRenamingMap;
import com.google.template.soy.tofu.SoyTofu;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryEnvironment;
import google.registry.request.Action;
import google.registry.request.Parameter;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
import google.registry.request.auth.AuthenticatedRegistrarAccessor.Role;
import google.registry.security.XsrfTokenManager;
import google.registry.ui.server.SoyTemplateUtils;
import google.registry.ui.soy.registrar.ConsoleSoyInfo;
import java.util.Map;
import java.util.HashMap;
import java.util.Optional;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
/** Action that serves Registrar Console single HTML page (SPA). */
@Action(service = Action.Service.DEFAULT, path = ConsoleUiAction.PATH, auth = Auth.AUTH_PUBLIC)
public final class ConsoleUiAction implements Runnable {
public final class ConsoleUiAction extends HtmlAction {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -66,27 +54,8 @@ public final class ConsoleUiAction implements Runnable {
google.registry.ui.soy.registrar.ConsoleSoyInfo.getInstance(),
google.registry.ui.soy.AnalyticsSoyInfo.getInstance());
@VisibleForTesting // webdriver and screenshot tests need this
public static final Supplier<SoyCssRenamingMap> CSS_RENAMING_MAP_SUPPLIER =
SoyTemplateUtils.createCssRenamingMapSupplier(
Resources.getResource("google/registry/ui/css/registrar_bin.css.js"),
Resources.getResource("google/registry/ui/css/registrar_dbg.css.js"));
@Inject HttpServletRequest req;
@Inject Response response;
@Inject RegistrarConsoleMetrics registrarConsoleMetrics;
@Inject AuthenticatedRegistrarAccessor registrarAccessor;
@Inject UserService userService;
@Inject XsrfTokenManager xsrfTokenManager;
@Inject AuthResult authResult;
@Inject
@Config("logoFilename")
String logoFilename;
@Inject
@Config("productName")
String productName;
@Inject
@Config("integrationEmail")
@@ -112,10 +81,6 @@ public final class ConsoleUiAction implements Runnable {
@Config("registrarConsoleEnabled")
boolean enabled;
@Inject
@Config("analyticsConfig")
Map<String, Object> analyticsConfig;
@Inject
@Parameter(PARAM_CLIENT_ID)
Optional<String> paramClientId;
@@ -124,37 +89,15 @@ public final class ConsoleUiAction implements Runnable {
ConsoleUiAction() {}
@Override
public void run() {
if (!authResult.userAuthInfo().isPresent()) {
response.setStatus(SC_MOVED_TEMPORARILY);
String location;
try {
location = userService.createLoginURL(req.getRequestURI());
} catch (IllegalArgumentException e) {
// UserServiceImpl.createLoginURL() throws IllegalArgumentException if underlying API call
// returns an error code of NOT_ALLOWED. createLoginURL() assumes that the error is caused
// by an invalid URL. But in fact, the error can also occur if UserService doesn't have any
// user information, which happens when the request has been authenticated as internal. In
// this case, we want to avoid dying before we can send the redirect, so just redirect to
// the root path.
location = "/";
}
response.setHeader(LOCATION, location);
return;
}
User user = authResult.userAuthInfo().get().user();
response.setContentType(MediaType.HTML_UTF_8);
response.setHeader(X_FRAME_OPTIONS, "SAMEORIGIN"); // Disallow iframing.
response.setHeader("X-Ui-Compatible", "IE=edge"); // Ask IE not to be silly.
SoyMapData data = new SoyMapData();
data.put("logoFilename", logoFilename);
data.put("productName", productName);
data.put("integrationEmail", integrationEmail);
data.put("supportEmail", supportEmail);
data.put("announcementsEmail", announcementsEmail);
data.put("supportPhoneNumber", supportPhoneNumber);
data.put("technicalDocsUrl", technicalDocsUrl);
data.put("analyticsConfig", analyticsConfig);
public void runAfterLogin(HashMap<String, Object> data) {
SoyMapData soyMapData = new SoyMapData();
data.forEach((key, value) -> soyMapData.put(key, value));
soyMapData.put("integrationEmail", integrationEmail);
soyMapData.put("supportEmail", supportEmail);
soyMapData.put("announcementsEmail", announcementsEmail);
soyMapData.put("supportPhoneNumber", supportPhoneNumber);
soyMapData.put("technicalDocsUrl", technicalDocsUrl);
if (!enabled) {
response.setStatus(SC_SERVICE_UNAVAILABLE);
response.setPayload(
@@ -162,23 +105,20 @@ public final class ConsoleUiAction implements Runnable {
.get()
.newRenderer(ConsoleSoyInfo.DISABLED)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.setData(soyMapData)
.render());
return;
}
data.put("username", user.getNickname());
data.put("logoutUrl", userService.createLogoutURL(PATH));
data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail()));
ImmutableSetMultimap<String, Role> roleMap = registrarAccessor.getAllClientIdWithRoles();
data.put("allClientIds", roleMap.keySet());
data.put("environment", RegistryEnvironment.get().toString());
soyMapData.put("allClientIds", roleMap.keySet());
soyMapData.put("environment", RegistryEnvironment.get().toString());
// We set the initial value to the value that will show if guessClientId throws.
String clientId = "<null>";
try {
clientId = paramClientId.orElse(registrarAccessor.guessClientId());
data.put("clientId", clientId);
data.put("isOwner", roleMap.containsEntry(clientId, OWNER));
data.put("isAdmin", roleMap.containsEntry(clientId, ADMIN));
soyMapData.put("clientId", clientId);
soyMapData.put("isOwner", roleMap.containsEntry(clientId, OWNER));
soyMapData.put("isAdmin", roleMap.containsEntry(clientId, ADMIN));
// We want to load the registrar even if we won't use it later (even if we remove the
// requireFeeExtension) - to make sure the user indeed has access to the guessed registrar.
@@ -197,7 +137,7 @@ public final class ConsoleUiAction implements Runnable {
.get()
.newRenderer(ConsoleSoyInfo.WHOAREYOU)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.setData(soyMapData)
.render());
registrarConsoleMetrics.registerConsoleRequest(
clientId, paramClientId.isPresent(), roleMap.get(clientId), "FORBIDDEN");
@@ -213,10 +153,15 @@ public final class ConsoleUiAction implements Runnable {
.get()
.newRenderer(ConsoleSoyInfo.MAIN)
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
.setData(data)
.setData(soyMapData)
.render();
response.setPayload(payload);
registrarConsoleMetrics.registerConsoleRequest(
clientId, paramClientId.isPresent(), roleMap.get(clientId), "SUCCESS");
}
@Override
public String getPath() {
return PATH;
}
}

View File

@@ -0,0 +1,109 @@
// 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.ui.server.registrar;
import static com.google.common.net.HttpHeaders.LOCATION;
import static com.google.common.net.HttpHeaders.X_FRAME_OPTIONS;
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import google.registry.config.RegistryConfig.Config;
import google.registry.request.Action;
import google.registry.request.RequestMethod;
import google.registry.request.Response;
import google.registry.request.auth.AuthResult;
import google.registry.security.XsrfTokenManager;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
/**
* Handles some of the nitty-gritty of responding to requests that should return HTML, including
* login, redirects, analytics, and some headers.
*
* If the user is not logged in, this will redirect to the login URL.
*/
public abstract class HtmlAction implements Runnable {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@Inject HttpServletRequest req;
@Inject Response response;
@Inject UserService userService;
@Inject XsrfTokenManager xsrfTokenManager;
@Inject AuthResult authResult;
@Inject @RequestMethod Action.Method method;
@Inject
@Config("logoFilename")
String logoFilename;
@Inject
@Config("productName")
String productName;
@Inject
@Config("analyticsConfig")
Map<String, Object> analyticsConfig;
@Override
public void run() {
response.setHeader(X_FRAME_OPTIONS, "SAMEORIGIN"); // Disallow iframing.
response.setHeader("X-Ui-Compatible", "IE=edge"); // Ask IE not to be silly.
if (!authResult.userAuthInfo().isPresent()) {
response.setStatus(SC_MOVED_TEMPORARILY);
String location;
try {
location = userService.createLoginURL(req.getRequestURI());
} catch (IllegalArgumentException e) {
// UserServiceImpl.createLoginURL() throws IllegalArgumentException if underlying API call
// returns an error code of NOT_ALLOWED. createLoginURL() assumes that the error is caused
// by an invalid URL. But in fact, the error can also occur if UserService doesn't have any
// user information, which happens when the request has been authenticated as internal. In
// this case, we want to avoid dying before we can send the redirect, so just redirect to
// the root path.
location = "/";
}
response.setHeader(LOCATION, location);
return;
}
response.setContentType(MediaType.HTML_UTF_8);
User user = authResult.userAuthInfo().get().user();
// Using HashMap to allow null values
HashMap<String, Object> data = new HashMap<>();
data.put("logoFilename", logoFilename);
data.put("productName", productName);
data.put("username", user.getNickname());
data.put("logoutUrl", userService.createLogoutURL(getPath()));
data.put("analyticsConfig", analyticsConfig);
data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail()));
logger.atInfo().log(
"User %s is accessing %s. Method= %s",
authResult.userIdForLogging(), getClass().getName(), method);
runAfterLogin(data);
}
public abstract void runAfterLogin(HashMap<String, Object> data);
public abstract String getPath();
}

View File

@@ -0,0 +1,21 @@
// 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.ui.server.registrar;
/**
* Marker interface for {@link google.registry.request.Action}s that serve GET requests and return
* JSON, rather than HTML.
*/
public interface JsonGetAction extends Runnable {}

View File

@@ -60,7 +60,6 @@ import google.registry.util.CollectionUtils;
import google.registry.util.DiffUtils;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -175,8 +174,7 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
}
private RegistrarResult update(final Map<String, ?> args, String clientId) {
return tm()
.transact(
return tm().transact(
() -> {
// We load the registrar here rather than outside of the transaction - to make
// sure we have the latest version. This one is loaded inside the transaction, so it's
@@ -215,7 +213,8 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
updatedRegistrar = checkAndUpdateAdminControlledFields(updatedRegistrar, args);
// read the contacts from the request.
ImmutableSet<RegistrarContact> updatedContacts = readContacts(registrar, args);
ImmutableSet<RegistrarContact> updatedContacts =
readContacts(registrar, contacts, args);
// Save the updated contacts
if (!updatedContacts.equals(contacts)) {
@@ -240,11 +239,18 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
});
}
private Map<String, Object> expandRegistrarWithContacts(Iterable<RegistrarContact> contacts,
Registrar registrar) {
private Map<String, Object> expandRegistrarWithContacts(
Iterable<RegistrarContact> contacts, Registrar registrar) {
ImmutableSet<Map<String, Object>> expandedContacts =
Streams.stream(contacts)
.map(RegistrarContact::toDiffableFieldMap)
// Note: per the javadoc, toDiffableFieldMap includes sensitive data but we don't want
// to display it here
.peek(
map -> {
map.remove("registryLockPasswordHash");
map.remove("registryLockPasswordSalt");
})
.collect(toImmutableSet());
// Use LinkedHashMap here to preserve ordering; null values mean we can't use ImmutableMap.
LinkedHashMap<String, Object> result = new LinkedHashMap<>(registrar.toDiffableFieldMap());
@@ -377,16 +383,10 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
/** Reads the contacts from the supplied args. */
public static ImmutableSet<RegistrarContact> readContacts(
Registrar registrar, Map<String, ?> args) {
ImmutableSet.Builder<RegistrarContact> contacts = new ImmutableSet.Builder<>();
Optional<List<RegistrarContact.Builder>> builders =
RegistrarFormFields.CONTACTS_FIELD.extractUntyped(args);
if (builders.isPresent()) {
builders.get().forEach(c -> contacts.add(c.setParent(registrar).build()));
}
return contacts.build();
Registrar registrar, ImmutableSet<RegistrarContact> existingContacts, Map<String, ?> args) {
return RegistrarFormFields.getRegistrarContactBuilders(existingContacts, args).stream()
.map(builder -> builder.setParent(registrar).build())
.collect(toImmutableSet());
}
/**
@@ -452,8 +452,17 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
() ->
new FormException(
"Not allowed to set registry lock password directly on new contact"));
if (!existingContact.isAllowedToSetRegistryLockPassword()) {
throw new FormException("Registrar contact not allowed to set registry lock password");
if (updatedContact.isRegistryLockAllowed()) {
// the password must have been set before or the user was allowed to set it now
if (!existingContact.isAllowedToSetRegistryLockPassword()
&& !existingContact.isRegistryLockAllowed()) {
throw new FormException("Registrar contact not allowed to set registry lock password");
}
}
if (updatedContact.isAllowedToSetRegistryLockPassword()) {
if (!existingContact.isAllowedToSetRegistryLockPassword()) {
throw new FormException("Cannot set isAllowedToSetRegistryLockPassword through UI");
}
}
}
}

View File

@@ -0,0 +1,168 @@
// 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.ui.server.registrar;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.security.JsonResponseHelper.Status.SUCCESS;
import static google.registry.ui.server.registrar.RegistrarConsoleModule.PARAM_CLIENT_ID;
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import com.google.appengine.api.users.User;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import com.google.gson.Gson;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarContact;
import google.registry.model.registry.RegistryLockDao;
import google.registry.request.Action;
import google.registry.request.Action.Method;
import google.registry.request.Parameter;
import google.registry.request.RequestMethod;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
import google.registry.request.auth.UserAuthInfo;
import google.registry.schema.domain.RegistryLock;
import google.registry.security.JsonResponseHelper;
import java.util.Optional;
import javax.inject.Inject;
import org.joda.time.DateTime;
/**
* Servlet that allows for getting locks for a particular registrar.
*
* <p>Note: at the moment we have no mechanism for JSON GET/POSTs in the same class or at the same
* URL, which is why this is distinct from the {@link RegistryLockPostAction}.
*/
@Action(
service = Action.Service.DEFAULT,
path = RegistryLockGetAction.PATH,
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
public final class RegistryLockGetAction implements JsonGetAction {
public static final String PATH = "/registry-lock-get";
private static final String LOCK_ENABLED_FOR_CONTACT_PARAM = "lockEnabledForContact";
private static final String EMAIL_PARAM = "email";
private static final String LOCKS_PARAM = "locks";
private static final String FULLY_QUALIFIED_DOMAIN_NAME_PARAM = "fullyQualifiedDomainName";
private static final String LOCKED_TIME_PARAM = "lockedTime";
private static final String LOCKED_BY_PARAM = "lockedBy";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final Gson GSON = new Gson();
@VisibleForTesting Method method;
private final Response response;
private final AuthenticatedRegistrarAccessor registrarAccessor;
@VisibleForTesting AuthResult authResult;
@VisibleForTesting Optional<String> paramClientId;
@Inject
RegistryLockGetAction(
@RequestMethod Method method,
Response response,
AuthenticatedRegistrarAccessor registrarAccessor,
AuthResult authResult,
@Parameter(PARAM_CLIENT_ID) Optional<String> paramClientId) {
this.method = method;
this.response = response;
this.registrarAccessor = registrarAccessor;
this.authResult = authResult;
this.paramClientId = paramClientId;
}
@Override
public void run() {
checkArgument(Method.GET.equals(method), "Only GET requests allowed");
checkArgument(authResult.userAuthInfo().isPresent(), "User auth info must be present");
checkArgument(paramClientId.isPresent(), "clientId must be present");
response.setContentType(MediaType.JSON_UTF_8);
try {
ImmutableMap<String, ?> resultMap = getLockedDomainsMap(paramClientId.get());
ImmutableMap<String, ?> payload =
JsonResponseHelper.create(SUCCESS, "Successful locks retrieval", resultMap);
response.setPayload(GSON.toJson(payload));
} catch (RegistrarAccessDeniedException e) {
logger.atWarning().withCause(e).log(
"User %s doesn't have access to this registrar", authResult.userIdForLogging());
response.setStatus(SC_FORBIDDEN);
} catch (Exception e) {
logger.atWarning().withCause(e).log("Unexpected error when retrieving locks for a registrar");
response.setStatus(SC_INTERNAL_SERVER_ERROR);
}
}
private ImmutableMap<String, ?> getLockedDomainsMap(String clientId)
throws RegistrarAccessDeniedException {
// Note: admins always have access to the locks page
checkArgument(authResult.userAuthInfo().isPresent(), "User auth info must be present");
UserAuthInfo userAuthInfo = authResult.userAuthInfo().get();
boolean isAdmin = userAuthInfo.isUserAdmin();
Registrar registrar = getRegistrarAndVerifyLockAccess(clientId, isAdmin);
User user = userAuthInfo.user();
boolean isRegistryLockAllowed =
isAdmin
|| registrar.getContacts().stream()
.filter(contact -> contact.getEmailAddress().equals(user.getEmail()))
.findFirst()
.map(RegistrarContact::isRegistryLockAllowed)
.orElse(false);
return ImmutableMap.of(
LOCK_ENABLED_FOR_CONTACT_PARAM,
isRegistryLockAllowed,
EMAIL_PARAM,
user.getEmail(),
PARAM_CLIENT_ID,
registrar.getClientId(),
LOCKS_PARAM,
getLockedDomains(clientId));
}
private Registrar getRegistrarAndVerifyLockAccess(String clientId, boolean isAdmin)
throws RegistrarAccessDeniedException {
Registrar registrar = registrarAccessor.getRegistrar(clientId);
checkArgument(
isAdmin || registrar.isRegistryLockAllowed(),
"Registry lock not allowed for this registrar");
return registrar;
}
private ImmutableList<ImmutableMap<String, ?>> getLockedDomains(String clientId) {
ImmutableList<RegistryLock> locks =
RegistryLockDao.getByRegistrarId(clientId).stream()
.filter(RegistryLock::isVerified)
.collect(toImmutableList());
return locks.stream().map(this::lockToMap).collect(toImmutableList());
}
private ImmutableMap<String, ?> lockToMap(RegistryLock lock) {
return ImmutableMap.of(
FULLY_QUALIFIED_DOMAIN_NAME_PARAM,
lock.getDomainName(),
LOCKED_TIME_PARAM,
lock.getCompletionTimestamp().map(DateTime::toString).orElse(""),
LOCKED_BY_PARAM,
lock.isSuperuser() ? "admin" : lock.getRegistrarPocId());
}
}

View File

@@ -1,66 +0,0 @@
#!/bin/sh
# 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.
tmp="$(mktemp -d "${TMPDIR:-/tmp}/list_generated_files.XXXXXXXX")"
[[ "${tmp}" != "" ]] || exit 1
trap "rm -rf ${tmp}" EXIT
base="${PWD}"
export LC_ALL=C
cd "${tmp}"
cp "${base}/java/google/registry/xjc/bindings.xjb" .
cp "${base}"/java/google/registry/xml/xsd/*.xsd .
"${base}/third_party/java/jaxb/jaxb-xjc" -extension -d "${tmp}" -b *.xjb *.xsd \
| sed -ne s@google/registry/xjc/@@p \
| grep -v package-info.java \
| sort \
> xjc_generated_files
cat <<EOF
#
# .'\`\`'. ...
# :o o \`....'\` ;
# \`. O :'
# \`': \`.
# \`:. \`.
# : \`. \`.
# \`..'\`... \`.
# \`... \`.
# DO NOT EDIT \`\`... \`.
# THIS FILE \`\`\`\`\`.
#
# When you make changes to the XML schemas (*.xsd) or the JAXB bindings file
# (bindings.xjb), you must regenerate this file with the following commands:
#
# bazel run java/google/registry/xjc:list_generated_files | tee /tmp/lol
# mv /tmp/lol java/google/registry/xjc/generated_files.bzl
#
EOF
echo
echo "pkginfo_generated_files = ["
while read package; do
printf ' "%s/package-info.java",\n' "${package}"
done < <(awk -F/ '{print $1}' xjc_generated_files | sort -u)
echo "]"
echo
echo "xjc_generated_files = ["
while read path; do
printf ' "%s",\n' "${path}"
done <xjc_generated_files
echo "]"

View File

@@ -1,57 +0,0 @@
#!/bin/bash
# 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.
[[ $# != 2 ]] && { echo "usage: $0 TEMPLATE OUTDIR" >&2; exit 1; }
template="$1"
outdir="$2"
create() {
package=$1
namespace=$2
sed -e "s,@PACKAGE@,${package},g" \
-e "s,@NAMESPACE@,${namespace},g" \
< "${template}" \
> "${outdir}/${package}/package-info.java"
}
create contact urn:ietf:params:xml:ns:contact-1.0
create domain urn:ietf:params:xml:ns:domain-1.0
create dsig http://www.w3.org/2000/09/xmldsig#
create epp urn:ietf:params:xml:ns:epp-1.0
create eppcom urn:ietf:params:xml:ns:eppcom-1.0
create fee06 urn:ietf:params:xml:ns:fee-0.6
create fee11 urn:ietf:params:xml:ns:fee-0.11
create fee12 urn:ietf:params:xml:ns:fee-0.12
create host urn:ietf:params:xml:ns:host-1.0
create iirdea urn:ietf:params:xml:ns:iirdea-1.0
create launch urn:ietf:params:xml:ns:launch-1.0
create mark urn:ietf:params:xml:ns:mark-1.0
create rde urn:ietf:params:xml:ns:rde-1.0
create rdecontact urn:ietf:params:xml:ns:rdeContact-1.0
create rdedomain urn:ietf:params:xml:ns:rdeDomain-1.0
create rdeeppparams urn:ietf:params:xml:ns:rdeEppParams-1.0
create rdeheader urn:ietf:params:xml:ns:rdeHeader-1.0
create rdehost urn:ietf:params:xml:ns:rdeHost-1.0
create rdeidn urn:ietf:params:xml:ns:rdeIDN-1.0
create rdenndn urn:ietf:params:xml:ns:rdeNNDN-1.0
create rdenotification urn:ietf:params:xml:ns:rdeNotification-1.0
create rdepolicy urn:ietf:params:xml:ns:rdePolicy-1.0
create rderegistrar urn:ietf:params:xml:ns:rdeRegistrar-1.0
create rdereport urn:ietf:params:xml:ns:rdeReport-1.0
create rgp urn:ietf:params:xml:ns:rgp-1.0
create secdns urn:ietf:params:xml:ns:secDNS-1.1
create smd urn:ietf:params:xml:ns:signedMark-1.0

View File

@@ -1,4 +1,3 @@
// See build.xml and make_pkginfo.sh which preprocess this into actual files.
@XmlSchema(
elementFormDefault = XmlNsForm.QUALIFIED,
namespace = "@NAMESPACE@",

View File

@@ -0,0 +1,27 @@
contact urn:ietf:params:xml:ns:contact-1.0
domain urn:ietf:params:xml:ns:domain-1.0
dsig http://www.w3.org/2000/09/xmldsig#
epp urn:ietf:params:xml:ns:epp-1.0
eppcom urn:ietf:params:xml:ns:eppcom-1.0
fee06 urn:ietf:params:xml:ns:fee-0.6
fee11 urn:ietf:params:xml:ns:fee-0.11
fee12 urn:ietf:params:xml:ns:fee-0.12
host urn:ietf:params:xml:ns:host-1.0
iirdea urn:ietf:params:xml:ns:iirdea-1.0
launch urn:ietf:params:xml:ns:launch-1.0
mark urn:ietf:params:xml:ns:mark-1.0
rde urn:ietf:params:xml:ns:rde-1.0
rdecontact urn:ietf:params:xml:ns:rdeContact-1.0
rdedomain urn:ietf:params:xml:ns:rdeDomain-1.0
rdeeppparams urn:ietf:params:xml:ns:rdeEppParams-1.0
rdeheader urn:ietf:params:xml:ns:rdeHeader-1.0
rdehost urn:ietf:params:xml:ns:rdeHost-1.0
rdeidn urn:ietf:params:xml:ns:rdeIDN-1.0
rdenndn urn:ietf:params:xml:ns:rdeNNDN-1.0
rdenotification urn:ietf:params:xml:ns:rdeNotification-1.0
rdepolicy urn:ietf:params:xml:ns:rdePolicy-1.0
rderegistrar urn:ietf:params:xml:ns:rdeRegistrar-1.0
rdereport urn:ietf:params:xml:ns:rdeReport-1.0
rgp urn:ietf:params:xml:ns:rgp-1.0
secdns urn:ietf:params:xml:ns:secDNS-1.1
smd urn:ietf:params:xml:ns:signedMark-1.0

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd"
version="2.2">
<embeddable class="org.joda.money.Money" access="FIELD">
<attributes>
<embedded name="money" access="FIELD"/>
</attributes>
</embeddable>
<embeddable class="org.joda.money.BigMoney" access="FIELD">
<attributes>
<basic name="amount" access="FIELD"/>
<basic name="currency" access="FIELD"/>
</attributes>
</embeddable>
</entity-mappings>

View File

@@ -35,6 +35,8 @@
<!-- Customized type converters -->
<class>google.registry.persistence.BloomFilterConverter</class>
<class>google.registry.persistence.CreateAutoTimestampConverter</class>
<class>google.registry.persistence.CurrencyUnitConverter</class>
<class>google.registry.persistence.DateTimeConverter</class>
<class>google.registry.persistence.UpdateAutoTimestampConverter</class>
<class>google.registry.persistence.ZonedDateTimeConverter</class>

View File

@@ -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>

View File

@@ -129,6 +129,7 @@ import google.registry.flows.domain.DomainFlowUtils.TrailingDashException;
import google.registry.flows.domain.DomainFlowUtils.UnexpectedClaimsNoticeException;
import google.registry.flows.domain.DomainFlowUtils.UnsupportedFeeAttributeException;
import google.registry.flows.domain.DomainFlowUtils.UnsupportedMarkTypeException;
import google.registry.flows.domain.DomainPricingLogic.AllocationTokenInvalidForPremiumNameException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotInPromotionException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForRegistrarException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForTldException;
@@ -1227,9 +1228,9 @@ public class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow,
.build());
clock.advanceOneMilli();
setEppInput("domain_create_premium_allocationtoken.xml");
assertThat(assertThrows(IllegalArgumentException.class, this::runFlow))
.hasMessageThat()
.isEqualTo("A nonzero discount code cannot be applied to premium domains");
assertAboutEppExceptions()
.that(assertThrows(AllocationTokenInvalidForPremiumNameException.class, this::runFlow))
.marshalsToXml();
}
@Test

View File

@@ -0,0 +1,154 @@
// 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.flows.domain;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
import static google.registry.testing.JUnitBackports.assertThrows;
import google.registry.flows.EppException;
import google.registry.flows.ResourceFlowTestCase;
import google.registry.flows.domain.DomainFlowUtils.BadDomainNameCharacterException;
import google.registry.flows.domain.DomainFlowUtils.BadDomainNamePartsCountException;
import google.registry.flows.domain.DomainFlowUtils.DashesInThirdAndFourthException;
import google.registry.flows.domain.DomainFlowUtils.DomainLabelTooLongException;
import google.registry.flows.domain.DomainFlowUtils.EmptyDomainNamePartException;
import google.registry.flows.domain.DomainFlowUtils.InvalidPunycodeException;
import google.registry.flows.domain.DomainFlowUtils.LeadingDashException;
import google.registry.flows.domain.DomainFlowUtils.TldDoesNotExistException;
import google.registry.flows.domain.DomainFlowUtils.TrailingDashException;
import google.registry.model.domain.DomainBase;
import google.registry.testing.AppEngineRule;
import org.junit.Before;
import org.junit.Test;
public class DomainFlowUtilsTest extends ResourceFlowTestCase<DomainInfoFlow, DomainBase> {
@Before
public void setup() {
setEppInput("domain_info.xml");
createTld("tld");
persistResource(AppEngineRule.makeRegistrar1().asBuilder().build());
}
@Test
public void testValidateDomainNameAcceptsValidName() throws EppException {
assertThat(DomainFlowUtils.validateDomainName("example.tld")).isNotNull();
}
@Test
public void testValidateDomainName_IllegalCharacters() {
BadDomainNameCharacterException thrown =
assertThrows(
BadDomainNameCharacterException.class,
() -> DomainFlowUtils.validateDomainName("$.foo"));
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Domain names can only contain a-z, 0-9, '.' and '-'");
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
public void testValidateDomainName_DomainNameWithEmptyParts() {
EmptyDomainNamePartException thrown =
assertThrows(
EmptyDomainNamePartException.class,
() -> DomainFlowUtils.validateDomainName("example."));
assertThat(thrown).hasMessageThat().isEqualTo("No part of a domain name can be empty");
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
public void testValidateDomainName_DomainNameWithLessThanTwoParts() {
BadDomainNamePartsCountException thrown =
assertThrows(
BadDomainNamePartsCountException.class,
() -> DomainFlowUtils.validateDomainName("example"));
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Domain name must have exactly one part above the TLD");
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
public void testValidateDomainName_invalidTLD() {
TldDoesNotExistException thrown =
assertThrows(
TldDoesNotExistException.class,
() -> DomainFlowUtils.validateDomainName("example.nosuchtld"));
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Domain name is under tld nosuchtld which doesn't exist");
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
public void testValidateDomainName_DomainNameIsTooLong() {
DomainLabelTooLongException thrown =
assertThrows(
DomainLabelTooLongException.class,
() ->
DomainFlowUtils.validateDomainName(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.foo"));
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Domain labels cannot be longer than 63 characters");
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
public void testValidateDomainName_leadingDash() {
LeadingDashException thrown =
assertThrows(
LeadingDashException.class, () -> DomainFlowUtils.validateDomainName("-example.foo"));
assertThat(thrown).hasMessageThat().isEqualTo("Domain labels cannot begin with a dash");
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
public void testValidateDomainName_trailingDash() {
TrailingDashException thrown =
assertThrows(
TrailingDashException.class, () -> DomainFlowUtils.validateDomainName("example-.foo"));
assertThat(thrown).hasMessageThat().isEqualTo("Domain labels cannot end with a dash");
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
public void testValidateDomainName_invalidIDN() {
InvalidPunycodeException thrown =
assertThrows(
InvalidPunycodeException.class,
() -> DomainFlowUtils.validateDomainName("xn--abcd.foo"));
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Domain name starts with xn-- but is not a valid IDN");
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
public void testValidateDomainName_containsInvalidDashes() {
DashesInThirdAndFourthException thrown =
assertThrows(
DashesInThirdAndFourthException.class,
() -> DomainFlowUtils.validateDomainName("ab--cd.foo"));
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Non-IDN domain names cannot contain dashes in the third or fourth position");
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
}

View File

@@ -23,6 +23,7 @@ import static google.registry.model.domain.token.AllocationToken.TokenStatus.VAL
import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE;
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.JUnitBackports.assertThrows;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
@@ -36,11 +37,17 @@ import google.registry.model.domain.token.AllocationToken.TokenStatus;
import google.registry.model.domain.token.AllocationToken.TokenType;
import google.registry.model.reporting.HistoryEntry;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test;
/** Unit tests for {@link AllocationToken}. */
public class AllocationTokenTest extends EntityTestCase {
@Before
public void setup() {
createTld("foo");
}
@Test
public void testPersistence() {
AllocationToken unlimitedUseToken =
@@ -66,7 +73,7 @@ public class AllocationTokenTest extends EntityTestCase {
new AllocationToken.Builder()
.setToken("abc123")
.setRedemptionHistoryEntry(Key.create(HistoryEntry.class, 1L))
.setDomainName("foo.example")
.setDomainName("example.foo")
.setCreationTimeForTest(DateTime.parse("2010-11-12T05:00:00Z"))
.setTokenType(SINGLE_USE)
.build());
@@ -81,7 +88,7 @@ public class AllocationTokenTest extends EntityTestCase {
.setToken("abc123")
.setTokenType(SINGLE_USE)
.setRedemptionHistoryEntry(Key.create(HistoryEntry.class, 1L))
.setDomainName("blahdomain.fake")
.setDomainName("blahdomain.foo")
.setCreationTimeForTest(DateTime.parse("2010-11-12T05:00:00Z"))
.build()),
"token",
@@ -129,13 +136,49 @@ public class AllocationTokenTest extends EntityTestCase {
assertThat(thrown).hasMessageThat().isEqualTo("Token type can only be set once");
}
@Test
public void testBuild_DomainNameWithLessThanTwoParts() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() ->
new AllocationToken.Builder()
.setDomainName("example")
.setTokenType(SINGLE_USE)
.setToken("barfoo")
.build());
assertThat(thrown)
.hasCauseThat()
.hasMessageThat()
.isEqualTo("Domain name must have exactly one part above the TLD");
assertThat(thrown).hasMessageThat().isEqualTo("Invalid domain name: example");
}
@Test
public void testBuild_invalidTLD() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() ->
new AllocationToken.Builder()
.setDomainName("example.nosuchtld")
.setTokenType(SINGLE_USE)
.setToken("barfoo")
.build());
assertThat(thrown)
.hasCauseThat()
.hasMessageThat()
.isEqualTo("Domain name is under tld nosuchtld which doesn't exist");
assertThat(thrown).hasMessageThat().isEqualTo("Invalid domain name: example.nosuchtld");
}
@Test
public void testBuild_domainNameOnlyOnSingleUse() {
AllocationToken.Builder builder =
new AllocationToken.Builder()
.setToken("foobar")
.setTokenType(TokenType.UNLIMITED_USE)
.setDomainName("foo.example");
.setDomainName("example.foo");
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, builder::build);
assertThat(thrown)
.hasMessageThat()

View File

@@ -17,9 +17,12 @@ package google.registry.model.registry;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static google.registry.testing.DatastoreHelper.createTlds;
import static google.registry.testing.DatastoreHelper.newRegistry;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.JUnitBackports.assertThrows;
import com.google.common.net.InternetDomainName;
import google.registry.model.registry.Registry.TldType;
import google.registry.testing.AppEngineRule;
import org.junit.Rule;
import org.junit.Test;
@@ -32,6 +35,7 @@ public class RegistriesTest {
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
private void initTestTlds() {
createTlds("foo", "a.b.c"); // Test a multipart tld.
}
@@ -42,6 +46,16 @@ public class RegistriesTest {
assertThat(Registries.getTlds()).containsExactly("foo", "a.b.c");
}
@Test
public void test_getTldEntities() {
initTestTlds();
persistResource(newRegistry("testtld", "TESTTLD").asBuilder().setTldType(TldType.TEST).build());
assertThat(Registries.getTldEntitiesOfType(TldType.REAL))
.containsExactly(Registry.get("foo"), Registry.get("a.b.c"));
assertThat(Registries.getTldEntitiesOfType(TldType.TEST))
.containsExactly(Registry.get("testtld"));
}
@Test
public void testGetTlds_withNoRegistriesPersisted_returnsEmptySet() {
assertThat(Registries.getTlds()).isEmpty();

View File

@@ -14,6 +14,7 @@
package google.registry.model.registry;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.testing.JUnitBackports.assertThrows;
@@ -22,8 +23,8 @@ 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.Optional;
import java.util.UUID;
import javax.persistence.PersistenceException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,15 +53,11 @@ public final class RegistryLockDaoTest {
public void testSaveAndLoad_failure_differentCode() {
RegistryLock lock = createLock();
RegistryLockDao.save(lock);
PersistenceException exception =
NullPointerException thrown =
assertThrows(
PersistenceException.class,
NullPointerException.class,
() -> RegistryLockDao.getByVerificationCode(UUID.randomUUID().toString()));
assertThat(exception)
.hasCauseThat()
.hasMessageThat()
.isEqualTo("No registry lock with this code");
assertThat(exception).hasCauseThat().isInstanceOf(NullPointerException.class);
assertThat(thrown).hasMessageThat().isEqualTo("No registry lock with this code");
}
@Test
@@ -71,10 +68,10 @@ public final class RegistryLockDaoTest {
jpaTm()
.transact(
() -> {
RegistryLock secondLock =
RegistryLock updatedLock =
RegistryLockDao.getByVerificationCode(lock.getVerificationCode());
secondLock.setCompletionTimestamp(jpaTmRule.getTxnClock().nowUtc());
RegistryLockDao.save(secondLock);
updatedLock.setCompletionTimestamp(jpaTmRule.getTxnClock().nowUtc());
RegistryLockDao.save(updatedLock);
});
jpaTm()
.transact(
@@ -86,11 +83,63 @@ public final class RegistryLockDaoTest {
});
}
@Test
public void testUpdateLock_usingSamePrimaryKey() {
RegistryLock lock = RegistryLockDao.save(createLock());
jpaTmRule.getTxnClock().advanceOneMilli();
RegistryLock updatedLock =
lock.asBuilder().setCompletionTimestamp(jpaTmRule.getTxnClock().nowUtc()).build();
jpaTm().transact(() -> RegistryLockDao.save(updatedLock));
jpaTm()
.transact(
() -> {
RegistryLock fromDatabase =
RegistryLockDao.getByVerificationCode(lock.getVerificationCode());
assertThat(fromDatabase.getCompletionTimestamp())
.isEqualTo(Optional.of(jpaTmRule.getTxnClock().nowUtc()));
});
}
@Test
public void testFailure_saveNull() {
assertThrows(NullPointerException.class, () -> RegistryLockDao.save(null));
}
@Test
public void testLoad_byRegistrarId() {
RegistryLock lock = createLock();
RegistryLock secondLock = createLock().asBuilder().setDomainName("otherexample.test").build();
RegistryLockDao.save(lock);
RegistryLockDao.save(secondLock);
assertThat(
RegistryLockDao.getByRegistrarId("TheRegistrar").stream()
.map(RegistryLock::getDomainName)
.collect(toImmutableSet()))
.containsExactly("example.test", "otherexample.test");
assertThat(RegistryLockDao.getByRegistrarId("nonexistent")).isEmpty();
}
@Test
public void testLoad_byRepoId() {
RegistryLock completedLock =
createLock().asBuilder().setCompletionTimestamp(jpaTmRule.getTxnClock().nowUtc()).build();
RegistryLockDao.save(completedLock);
jpaTmRule.getTxnClock().advanceOneMilli();
RegistryLock inProgressLock = createLock();
RegistryLockDao.save(inProgressLock);
Optional<RegistryLock> mostRecent = RegistryLockDao.getMostRecentByRepoId("repoId");
assertThat(mostRecent.isPresent()).isTrue();
assertThat(mostRecent.get().isVerified()).isFalse();
}
@Test
public void testLoad_byRepoId_empty() {
assertThat(RegistryLockDao.getMostRecentByRepoId("nonexistent").isPresent()).isFalse();
}
private RegistryLock createLock() {
return new RegistryLock.Builder()
.setRepoId("repoId")

View File

@@ -22,7 +22,6 @@ 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;
@@ -71,9 +70,7 @@ public class ClaimsListDaoTest {
@Test
public void getCurrent_throwsNoResultExceptionIfTableIsEmpty() {
PersistenceException thrown =
assertThrows(PersistenceException.class, () -> ClaimsListDao.getCurrent());
assertThat(thrown).hasCauseThat().isInstanceOf(NoResultException.class);
assertThrows(NoResultException.class, ClaimsListDao::getCurrent);
}
@Test

View File

@@ -14,28 +14,42 @@
package google.registry.model.transaction;
import static com.google.common.truth.Truth.assertThat;
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.HibernateSchemaExporter;
import google.registry.persistence.NomulusPostgreSql;
import google.registry.persistence.PersistenceModule;
import google.registry.persistence.PersistenceXmlUtility;
import google.registry.testing.FakeClock;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
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.junit.rules.RuleChain;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.containers.PostgreSQLContainer;
@@ -48,38 +62,59 @@ import org.testcontainers.containers.PostgreSQLContainer;
* 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 GOLDEN_SCHEMA_SQL_PATH = "sql/schema/nomulus.golden.sql";
private static final String DB_CLEANUP_SQL_PATH =
"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 initScript;
private final String initScriptPath;
private final ImmutableList<Class> extraEntityClasses;
private final ImmutableMap userProperties;
private JdbcDatabaseContainer database;
private static final JdbcDatabaseContainer database = create();
private static final long ACTIVE_CONNECTIONS_BASELINE =
getActiveConnectionCountByUser(database.getUsername());
;
private static final HibernateSchemaExporter exporter =
HibernateSchemaExporter.create(
database.getJdbcUrl(), database.getUsername(), database.getPassword());
private EntityManagerFactory emf;
private JpaTransactionManager cachedTm;
private JpaTransactionManagerRule(
String initScript,
String initScriptPath,
ImmutableList<Class> extraEntityClasses,
ImmutableMap<String, String> userProperties) {
this.initScript = initScript;
this.initScriptPath = initScriptPath;
this.extraEntityClasses = extraEntityClasses;
this.userProperties = userProperties;
}
/** Wraps {@link JpaTransactionManagerRule} in a {@link PostgreSQLContainer}. */
@Override
public Statement apply(Statement base, Description description) {
database = new PostgreSQLContainer().withInitScript(initScript);
return RuleChain.outerRule(database)
.around(JpaTransactionManagerRule.super::apply)
.apply(base, description);
private static JdbcDatabaseContainer create() {
PostgreSQLContainer container =
new PostgreSQLContainer(NomulusPostgreSql.getDockerTag())
.withDatabaseName(MANAGEMENT_DB_NAME);
container.start();
Runtime.getRuntime().addShutdownHook(new Thread(() -> container.close()));
return container;
}
@Override
public void before() {
public void before() throws Exception {
executeSql(MANAGEMENT_DB_NAME, readSqlInClassPath(DB_CLEANUP_SQL_PATH));
executeSql(POSTGRES_DB_NAME, readSqlInClassPath(initScriptPath));
if (!extraEntityClasses.isEmpty()) {
File tempSqlFile = File.createTempFile("tempSqlFile", ".sql");
tempSqlFile.deleteOnExit();
exporter.export(extraEntityClasses, tempSqlFile);
executeSql(
POSTGRES_DB_NAME,
new String(Files.readAllBytes(tempSqlFile.toPath()), StandardCharsets.UTF_8));
}
ImmutableMap properties = PersistenceModule.providesDefaultDatabaseConfigs();
if (!userProperties.isEmpty()) {
// If there are user properties, create a new properties object with these added.
@@ -87,10 +122,10 @@ public class JpaTransactionManagerRule extends ExternalResource {
builder.putAll(userProperties);
properties = builder.build();
}
assertNormalActiveConnection();
emf =
createEntityManagerFactory(
database.getJdbcUrl(),
getJdbcUrlFor(POSTGRES_DB_NAME),
database.getUsername(),
database.getPassword(),
properties,
@@ -105,8 +140,72 @@ public class JpaTransactionManagerRule extends ExternalResource {
TransactionManagerFactory.jpaTm = cachedTm;
if (emf != null) {
emf.close();
emf = null;
}
cachedTm = null;
assertNormalActiveConnection();
}
private static long getActiveConnectionCountByUser(String userName) {
try (Connection conn = createConnection(POSTGRES_DB_NAME);
Statement statement = conn.createStatement()) {
ResultSet rs =
statement.executeQuery(
"SELECT COUNT(1) FROM pg_stat_activity WHERE usename = '" + userName + "'");
rs.next();
return rs.getLong(1);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* This function throws exception if it detects connection leak by checking the metadata table
* pg_stat_activity.
*/
private void assertNormalActiveConnection() {
assertThat(getActiveConnectionCountByUser(database.getUsername()))
.isEqualTo(ACTIVE_CONNECTIONS_BASELINE);
}
private static String readSqlInClassPath(String sqlScriptPath) {
try {
return Resources.toString(Resources.getResource(sqlScriptPath), Charsets.UTF_8);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private void executeSql(String dbName, String sqlScript) {
try (Connection conn = createConnection(dbName);
Statement statement = conn.createStatement()) {
statement.execute(sqlScript);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static 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 static 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. */
@@ -122,15 +221,7 @@ public class JpaTransactionManagerRule extends ExternalResource {
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)));
PersistenceXmlUtility.getParsedPersistenceXmlDescriptor();
extraEntityClasses.stream().map(Class::getName).forEach(descriptor::addClasses);
return Bootstrap.getEntityManagerFactoryBuilder(descriptor, properties).build();
@@ -171,7 +262,7 @@ public class JpaTransactionManagerRule extends ExternalResource {
/** Builds a {@link JpaTransactionManagerRule} instance. */
public JpaTransactionManagerRule build() {
if (initScript == null) {
initScript = SCHEMA_GOLDEN_SQL;
initScript = GOLDEN_SCHEMA_SQL_PATH;
}
return new JpaTransactionManagerRule(
initScript,

View File

@@ -23,7 +23,6 @@ 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;
@@ -37,7 +36,6 @@ public class JpaTransactionManagerRuleTest {
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.build();
@Test

View File

@@ -24,12 +24,12 @@ 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;
/** Unit tests for {@link BloomFilterConverter}. */
@RunWith(JUnit4.class)
public class BloomFilterConverterTest {
@@ -37,7 +37,6 @@ public class BloomFilterConverterTest {
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.build();
@Test
@@ -60,7 +59,7 @@ public class BloomFilterConverterTest {
public TestEntity() {}
public TestEntity(BloomFilter<String> bloomFilter) {
TestEntity(BloomFilter<String> bloomFilter) {
this.bloomFilter = bloomFilter;
}
}

View File

@@ -21,13 +21,13 @@ 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;
/** Unit tests for {@link CreateAutoTimestampConverter}. */
@RunWith(JUnit4.class)
public class CreateAutoTimestampConverterTest {
@@ -35,7 +35,6 @@ public class CreateAutoTimestampConverterTest {
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.build();
@Test
@@ -70,7 +69,7 @@ public class CreateAutoTimestampConverterTest {
public TestEntity() {}
public TestEntity(String name, CreateAutoTimestamp cat) {
TestEntity(String name, CreateAutoTimestamp cat) {
this.name = name;
this.cat = cat;
}

View File

@@ -0,0 +1,93 @@
// 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 static google.registry.testing.JUnitBackports.assertThrows;
import google.registry.model.ImmutableObject;
import google.registry.model.transaction.JpaTransactionManagerRule;
import javax.persistence.Entity;
import javax.persistence.Id;
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 CurrencyUnitConverter}. */
@RunWith(JUnit4.class)
public class CurrencyUnitConverterTest {
@Rule
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class)
.build();
@Test
public void roundTripConversion() {
TestEntity entity = new TestEntity(CurrencyUnit.EUR);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
assertThat(
jpaTm()
.transact(
() ->
jpaTm()
.getEntityManager()
.createNativeQuery(
"SELECT currency FROM \"TestEntity\" WHERE name = 'id'")
.getResultList()))
.containsExactly("EUR");
TestEntity persisted =
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "id"));
assertThat(persisted.currency).isEqualTo(CurrencyUnit.EUR);
}
@Test
public void invalidCurrency() {
jpaTm()
.transact(
() ->
jpaTm()
.getEntityManager()
.createNativeQuery(
"INSERT INTO \"TestEntity\" (name, currency) VALUES('id', 'XXXX')")
.executeUpdate());
PersistenceException thrown =
assertThrows(
PersistenceException.class,
() ->
jpaTm()
.transact(
() -> jpaTm().getEntityManager().find(TestEntity.class, "id").currency));
assertThat(thrown).hasCauseThat().hasMessageThat().isEqualTo("Unknown currency 'XXXX'");
}
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
public static class TestEntity extends ImmutableObject {
@Id String name = "id";
CurrencyUnit currency;
public TestEntity() {}
TestEntity(CurrencyUnit currency) {
this.currency = currency;
}
}
}

View File

@@ -0,0 +1,107 @@
// 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 javax.persistence.Entity;
import javax.persistence.Id;
import org.joda.time.DateTime;
import org.joda.time.format.ISODateTimeFormat;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link DateTimeConverter}. */
@RunWith(JUnit4.class)
public class DateTimeConverterTest {
@Rule
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder().withEntityClass(TestEntity.class).build();
private final DateTimeConverter converter = new DateTimeConverter();
@Test
public void convertToDatabaseColumn_returnsNullIfInputIsNull() {
assertThat(converter.convertToDatabaseColumn(null)).isNull();
}
@Test
public void convertToDatabaseColumn_convertsCorrectly() {
DateTime dateTime = DateTime.parse("2019-09-01T01:01:01");
assertThat(converter.convertToDatabaseColumn(dateTime).getTime())
.isEqualTo(dateTime.getMillis());
}
@Test
public void convertToEntityAttribute_returnsNullIfInputIsNull() {
assertThat(converter.convertToEntityAttribute(null)).isNull();
}
@Test
public void convertToEntityAttribute_convertsCorrectly() {
DateTime dateTime = DateTime.parse("2019-09-01T01:01:01Z");
long millis = dateTime.getMillis();
assertThat(converter.convertToEntityAttribute(new Timestamp(millis))).isEqualTo(dateTime);
}
static DateTime parseDateTime(String value) {
return ISODateTimeFormat.dateTimeNoMillis().withOffsetParsed().parseDateTime(value);
}
@Test
public void converter_generatesTimestampWithNormalizedZone() {
DateTime dt = parseDateTime("2019-09-01T01:01:01Z");
TestEntity entity = new TestEntity("normalized_utc_time", dt);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
TestEntity retrievedEntity =
jpaTm()
.transact(
() -> jpaTm().getEntityManager().find(TestEntity.class, "normalized_utc_time"));
assertThat(retrievedEntity.dt.toString()).isEqualTo("2019-09-01T01:01:01.000Z");
}
@Test
public void converter_convertsNonUtcZoneCorrectly() {
DateTime dt = parseDateTime("2019-09-01T01:01:01-05:00");
TestEntity entity = new TestEntity("new_york_time", dt);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
TestEntity retrievedEntity =
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "new_york_time"));
assertThat(retrievedEntity.dt.toString()).isEqualTo("2019-09-01T06:01:01.000Z");
}
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
private static class TestEntity extends ImmutableObject {
@Id String name;
DateTime dt;
public TestEntity() {}
TestEntity(String name, DateTime dt) {
this.name = name;
this.dt = dt;
}
}
}

View File

@@ -0,0 +1,75 @@
// 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 com.google.common.collect.ImmutableList;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.joda.money.CurrencyUnit;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.testcontainers.containers.PostgreSQLContainer;
/** Unit tests for {@link HibernateSchemaExporter}. */
@RunWith(JUnit4.class)
public class HibernateSchemaExporterTest {
@ClassRule
public static final PostgreSQLContainer database =
new PostgreSQLContainer(NomulusPostgreSql.getDockerTag());
private static HibernateSchemaExporter exporter;
@Rule public final TemporaryFolder tempFolder = new TemporaryFolder();
@BeforeClass
public static void init() {
exporter =
HibernateSchemaExporter.create(
database.getJdbcUrl(), database.getUsername(), database.getPassword());
}
@Test
public void export_succeeds() throws IOException {
File sqlFile = tempFolder.newFile();
exporter.export(ImmutableList.of(TestEntity.class), sqlFile);
assertThat(Files.readAllBytes(sqlFile.toPath()))
.isEqualTo(
("\n"
+ " create table \"TestEntity\" (\n"
+ " name text not null,\n"
+ " cu text,\n"
+ " primary key (name)\n"
+ " );\n")
.getBytes(StandardCharsets.UTF_8));
}
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
private static class TestEntity {
@Id String name;
CurrencyUnit cu;
}
}

View File

@@ -0,0 +1,217 @@
// 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 com.google.common.collect.ImmutableMap;
import google.registry.model.ImmutableObject;
import google.registry.model.transaction.JpaTransactionManagerRule;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapKeyColumn;
import javax.persistence.PostLoad;
import org.hibernate.cfg.Environment;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Unit tests for embeddable {@link Money}.
*
* <p>{@link Money} is a wrapper around {@link org.joda.money.BigMoney} which itself contains two
* fields: a {@link BigDecimal} {@code amount} and a {@link CurrencyUnit} {@code currency}. When we
* store an entity with a {@link Money} field, we would like to store it in two columns, for the
* amount and the currency separately, so that it is easily queryable. This requires that we make
* {@link Money} a nested embeddable object.
*
* <p>However becaues {@link Money} is not a class that we control, we cannot use annotation-based
* mapping. Therefore there is no {@code JodaMoneyConverter} class. Instead, we define the mapping
* in {@code META-INF/orm.xml}.
*
* <p>Also note that any entity that contains a {@link Money} should should implement a
* {@link @PostLoad} callback that converts the amount in the {@link Money} to a scale that is
* appropriate for the currency. This is espcially necessary for currencies like JPY where the scale
* is 0, which is different from the default scale that {@link BigDecimal} is persisted in database.
*/
@RunWith(JUnit4.class)
public class JodaMoneyConverterTest {
@Rule
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class, ComplexTestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.build();
@Test
public void roundTripConversion() {
Money money = Money.of(CurrencyUnit.USD, 100);
TestEntity entity = new TestEntity(money);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
List<?> result =
jpaTm()
.transact(
() ->
jpaTm()
.getEntityManager()
.createNativeQuery(
"SELECT amount, currency FROM TestEntity WHERE name = 'id'")
.getResultList());
assertThat(result.size()).isEqualTo(1);
assertThat(Arrays.asList((Object[]) result.get(0)))
.containsExactly(
BigDecimal.valueOf(100).setScale(CurrencyUnit.USD.getDecimalPlaces()), "USD")
.inOrder();
TestEntity persisted =
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "id"));
assertThat(persisted.money).isEqualTo(money);
}
@Test
public void roundTripConversionWithComplexEntity() {
Money myMoney = Money.of(CurrencyUnit.USD, 100);
Money yourMoney = Money.of(CurrencyUnit.GBP, 80);
ImmutableMap<String, Money> moneyMap =
ImmutableMap.of(
"uno", Money.of(CurrencyUnit.EUR, 500),
"dos", Money.ofMajor(CurrencyUnit.JPY, 2000),
"tres", Money.of(CurrencyUnit.GBP, 20));
ComplexTestEntity entity = new ComplexTestEntity(moneyMap, myMoney, yourMoney);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
List<?> result =
jpaTm()
.transact(
() ->
jpaTm()
.getEntityManager()
.createNativeQuery(
"SELECT my_amount, my_currency, your_amount, your_currency FROM"
+ " ComplexTestEntity WHERE name = 'id'")
.getResultList());
assertThat(result.size()).isEqualTo(1);
assertThat(Arrays.asList((Object[]) result.get(0)))
.containsExactly(
BigDecimal.valueOf(100).setScale(2), "USD", BigDecimal.valueOf(80).setScale(2), "GBP")
.inOrder();
result =
jpaTm()
.transact(
() ->
jpaTm()
.getEntityManager()
.createNativeQuery(
"SELECT map_amount, map_currency FROM MoneyMap"
+ " WHERE entity_name = 'id' AND map_key = 'dos'")
.getResultList());
ComplexTestEntity persisted =
jpaTm().transact(() -> jpaTm().getEntityManager().find(ComplexTestEntity.class, "id"));
assertThat(result.size()).isEqualTo(1);
// Note that the amount has two decimal places even though JPY is supposed to have scale 0.
// This is due to the unfournate fact that we need to accommodate differet currencies stored
// in the same table so that the scale has to be set to the largest (2). When a Money field is
// persisted in an entity, the entity should always have a @PostLoad callback to convert the
// Money to the correct scale.
assertThat(Arrays.asList((Object[]) result.get(0)))
.containsExactly(BigDecimal.valueOf(2000).setScale(2), "JPY")
.inOrder();
// Make sure that the loaded entity contains the fields exactly as they are persisted.
assertThat(persisted.myMoney).isEqualTo(myMoney);
assertThat(persisted.yourMoney).isEqualTo(yourMoney);
assertThat(persisted.moneyMap).containsExactlyEntriesIn(moneyMap);
}
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
public static class TestEntity extends ImmutableObject {
@Id String name = "id";
Money money;
public TestEntity() {}
TestEntity(Money money) {
this.money = money;
}
}
@Entity(name = "ComplexTestEntity") // Override entity name to avoid the nested class reference.
// This entity is used to test column override for embedded fields and collections.
public static class ComplexTestEntity extends ImmutableObject {
// After the entity is loaded from the database, go through the money map and make sure that
// the scale is consistent with the currency. This is necessary for currency like JPY where
// the scale is 0 but the amount is persisteted as BigDecimal with scale 2.
@PostLoad
void setCurrencyScale() {
moneyMap
.entrySet()
.forEach(
entry -> {
Money money = entry.getValue();
if (!money.toBigMoney().isCurrencyScale()) {
CurrencyUnit currency = money.getCurrencyUnit();
BigDecimal amount = money.getAmount().setScale(currency.getDecimalPlaces());
entry.setValue(Money.of(currency, amount));
}
});
}
@Id String name = "id";
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "MoneyMap", joinColumns = @JoinColumn(name = "entity_name"))
@MapKeyColumn(name = "map_key")
@AttributeOverrides({
@AttributeOverride(name = "value.money.amount", column = @Column(name = "map_amount")),
@AttributeOverride(name = "value.money.currency", column = @Column(name = "map_currency"))
})
Map<String, Money> moneyMap;
@AttributeOverrides({
@AttributeOverride(name = "money.amount", column = @Column(name = "my_amount")),
@AttributeOverride(name = "money.currency", column = @Column(name = "my_currency"))
})
Money myMoney;
@AttributeOverrides({
@AttributeOverride(name = "money.amount", column = @Column(name = "your_amount")),
@AttributeOverride(name = "money.currency", column = @Column(name = "your_currency"))
})
Money yourMoney;
public ComplexTestEntity() {}
ComplexTestEntity(ImmutableMap<String, Money> moneyMap, Money myMoney, Money yourMoney) {
this.moneyMap = moneyMap;
this.myMoney = myMoney;
this.yourMoney = yourMoney;
}
}
}

View File

@@ -29,7 +29,8 @@ import org.testcontainers.containers.PostgreSQLContainer;
/** Unit tests for {@link PersistenceModule}. */
@RunWith(JUnit4.class)
public class PersistenceModuleTest {
@Rule public PostgreSQLContainer database = new PostgreSQLContainer();
@Rule
public PostgreSQLContainer database = new PostgreSQLContainer(NomulusPostgreSql.getDockerTag());
private EntityManagerFactory emf;

View File

@@ -21,12 +21,12 @@ 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;
/** Unit tests for {@link UpdateAutoTimestampConverter}. */
@RunWith(JUnit4.class)
public class UpdateAutoTimestampConverterTest {
@@ -34,7 +34,6 @@ public class UpdateAutoTimestampConverterTest {
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.build();
@Test
@@ -81,7 +80,7 @@ public class UpdateAutoTimestampConverterTest {
public TestEntity() {}
public TestEntity(String name, UpdateAutoTimestamp uat) {
TestEntity(String name, UpdateAutoTimestamp uat) {
this.name = name;
this.uat = uat;
}

View File

@@ -24,7 +24,6 @@ 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;
@@ -38,7 +37,6 @@ public class ZonedDateTimeConverterTest {
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder()
.withEntityClass(TestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.build();
private final ZonedDateTimeConverter converter = new ZonedDateTimeConverter();
@@ -113,7 +111,7 @@ public class ZonedDateTimeConverterTest {
public TestEntity() {}
public TestEntity(String name, ZonedDateTime zdt) {
TestEntity(String name, ZonedDateTime zdt) {
this.name = name;
this.zdt = zdt;
}

View File

@@ -154,6 +154,45 @@ public class IcannReportingUploadActionTest {
new InternetAddress("recipient@example.com"),
new InternetAddress("sender@example.com")));
}
@Test
public void testFailure_quicklySkipsOverNonRetryableUploadException() throws Exception {
runTest_nonRetryableException(
new IOException(
"<msg>A report for that month already exists, the cut-off date already"
+ " passed.</msg>"));
}
@Test
public void testFailure_quicklySkipsOverIpWhitelistException() throws Exception {
runTest_nonRetryableException(
new IOException("Your IP address 25.147.130.158 is not allowed to connect"));
}
private void runTest_nonRetryableException(Exception nonRetryableException) throws Exception {
IcannReportingUploadAction action = createAction();
when(mockReporter.send(PAYLOAD_FAIL, "a-activity-201706.csv"))
.thenThrow(nonRetryableException)
.thenThrow(
new AssertionError(
"This should never be thrown because the previous exception isn't retryable"));
action.run();
verify(mockReporter, times(1)).send(PAYLOAD_FAIL, "a-activity-201706.csv");
verify(mockReporter).send(PAYLOAD_SUCCESS, "test-transactions-201706.csv");
verifyNoMoreInteractions(mockReporter);
assertThat(((FakeResponse) action.response).getPayload())
.isEqualTo("OK, attempted uploading 2 reports");
verify(emailService)
.sendEmail(
EmailMessage.create(
"ICANN Monthly report upload summary: 1/2 succeeded",
"Report Filename - Upload status:\n"
+ "test-transactions-201706.csv - SUCCESS\n"
+ "a-activity-201706.csv - FAILURE",
new InternetAddress("recipient@example.com"),
new InternetAddress("sender@example.com")));
}
@Test
public void testFail_FileNotFound() throws Exception {
IcannReportingUploadAction action = createAction();

View File

@@ -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();

View File

@@ -0,0 +1,78 @@
// Copyright 2018 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.integration;
import static com.google.common.truth.Truth.assertWithMessage;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import google.registry.model.transaction.JpaTransactionManagerRule;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ScanResult;
import java.lang.reflect.Field;
import java.util.stream.Stream;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.junit.runners.Suite.SuiteClasses;
/**
* Verifies that all tests that depends on the Cloud SQL schema are included in the project's
* sqlIntegrationTest suite. Names of the test classes is set to the 'test.sqlIntergrationTests'
* system property as a comma-separated string.
*
* <p>A test is deemed dependent on the SQL schema iff it has a field with type {@link
* JpaTransactionManagerRule}.
*/
// TODO(weiminyu): consider generating a TestSuite class instead.
@RunWith(JUnit4.class)
public class SqlIntegrationMembershipTest {
@Test
public void sqlIntegrationMembershipComplete() {
ImmutableSet<String> sqlDependentTests;
try (ScanResult scanResult =
new ClassGraph().enableAnnotationInfo().whitelistPackages("google.registry").scan()) {
sqlDependentTests =
scanResult.getClassesWithAnnotation(RunWith.class.getName()).stream()
.filter(clazz -> clazz.getSimpleName().endsWith("Test"))
.map(clazz -> clazz.loadClass())
.filter(SqlIntegrationMembershipTest::isSqlDependent)
.map(Class::getName)
.collect(ImmutableSet.toImmutableSet());
}
ImmutableSet<String> declaredTests =
Stream.of(SqlIntegrationTestSuite.class.getAnnotation(SuiteClasses.class).value())
.map(Class::getName)
.collect(ImmutableSet.toImmutableSet());
SetView<String> undeclaredTests = Sets.difference(sqlDependentTests, declaredTests);
assertWithMessage(
"Undeclared sql-dependent tests found. "
+ "Please add them to SqlIntegrationTestSuite.java.")
.that(undeclaredTests)
.isEmpty();
SetView<String> unnecessaryDeclarations = Sets.difference(declaredTests, sqlDependentTests);
assertWithMessage("Found tests that should not be included in SqlIntegrationTestSuite.java.")
.that(unnecessaryDeclarations)
.isEmpty();
}
private static boolean isSqlDependent(Class<?> testClass) {
return Stream.of(testClass.getDeclaredFields())
.map(Field::getType)
.anyMatch(JpaTransactionManagerRule.class::equals);
}
}

View File

@@ -0,0 +1,60 @@
// Copyright 2018 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.integration;
import google.registry.model.registry.RegistryLockDaoTest;
import google.registry.model.tmch.ClaimsListDaoTest;
import google.registry.model.transaction.JpaTransactionManagerImplTest;
import google.registry.model.transaction.JpaTransactionManagerRuleTest;
import google.registry.persistence.BloomFilterConverterTest;
import google.registry.persistence.CreateAutoTimestampConverterTest;
import google.registry.persistence.CurrencyUnitConverterTest;
import google.registry.persistence.DateTimeConverterTest;
import google.registry.persistence.JodaMoneyConverterTest;
import google.registry.persistence.UpdateAutoTimestampConverterTest;
import google.registry.persistence.ZonedDateTimeConverterTest;
import google.registry.schema.tld.PremiumListDaoTest;
import google.registry.ui.server.registrar.RegistryLockGetActionTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
/**
* Groups all tests that may depends on Cloud SQL schema. They will be run for server-schema
* compatibility check.
*
* <p>Schema dependency is approximated by the use of {@link
* google.registry.model.transaction.JpaTransactionManagerRule}.
*
* @see SqlIntegrationMembershipTest
*/
// TODO(weiminyu): refactor JpaTransactionManagerRule to eliminate false positives.
@RunWith(Suite.class)
@SuiteClasses({
BloomFilterConverterTest.class,
ClaimsListDaoTest.class,
CreateAutoTimestampConverterTest.class,
CurrencyUnitConverterTest.class,
DateTimeConverterTest.class,
JodaMoneyConverterTest.class,
JpaTransactionManagerImplTest.class,
JpaTransactionManagerRuleTest.class,
PremiumListDaoTest.class,
RegistryLockDaoTest.class,
RegistryLockGetActionTest.class,
UpdateAutoTimestampConverterTest.class,
ZonedDateTimeConverterTest.class
})
public class SqlIntegrationTestSuite {}

View File

@@ -21,7 +21,6 @@ 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;
@@ -68,16 +67,13 @@ public class PremiumListDaoTest {
@Test
public void saveNew_throwsWhenPremiumListAlreadyExists() {
PremiumListDao.saveNew(PremiumList.create("testlist", CurrencyUnit.USD, TEST_PRICES));
PersistenceException thrown =
IllegalArgumentException thrown =
assertThrows(
PersistenceException.class,
IllegalArgumentException.class,
() ->
PremiumListDao.saveNew(
PremiumList.create("testlist", CurrencyUnit.USD, TEST_PRICES)));
assertThat(thrown)
.hasCauseThat()
.hasMessageThat()
.contains("A premium list of this name already exists");
assertThat(thrown).hasMessageThat().contains("A premium list of this name already exists");
}
@Test

Some files were not shown because too many files have changed in this diff Show More