1
0
mirror of https://github.com/google/nomulus synced 2026-07-14 20:12:19 +00:00

Compare commits

...

5 Commits

Author SHA1 Message Date
Lai Jiang 76603812e3 Create kzip file for Kythe cross-referencing (#424)
This is set up per b/141716384.

TESTED=Tested on alpha and successfully uploaded the merged kzip file to
GCS.
2020-01-03 16:57:39 -05:00
Shicong Huang a28754dc5d Add dual read claims list (#413)
* Add dual read claims list

* Improve warning log and use longer duration for cache

* Extract the comparison logic to a method

* Move cache to DAO
2020-01-03 10:59:34 -05:00
Weimin Yu d6bf6f375e Fix flakiness in JodaMoneyConverterTest (#421)
* Fix flakiness in JodaMoneyConverterTest

JpdaMoneyConverterTest relies on Hibernate to deploy its schema.
This introduces an extra jdbc connection in the middle of a test
suite, and may break the connection count checks between tests made
by JpaTransactionManagerRule.

This change updated HibernateSchemaExporter to include Hibernate
proprietary mappings in META-INF/orm.xml.

This change also disabled Hibernate schema push for all tests,
and enabled sql statement logging.
2020-01-02 11:51:20 -05:00
Ben McIlwain 8f67c4b9cf Support premium list updating in Cloud SQL (#422)
* Support premium list updating in Cloud SQL

This also removes the requirement to specify --also_cloud_sql in nomulus premium
list tooling, instead always persisting to Cloud SQL. It removes a non-USD
premium label in the global test premium list (the Cloud SQL schema doesn't
support a mix of currency units in a single premium list). And it adds a method
to PremiumListDao to grab the most recent version of a given list.

* Merge branch 'master' into premium-lists-always-cloud-sql

* Revert test change

* Create new PremiumListUtils class and refactor out existing method

* Fix tests and update an existing premium price
2020-01-02 11:30:58 -05:00
gbrodman c17a5c489c Add unlock fields to RegistryLocks (#408)
* Add unlock fields to RegistryLocks

This will make it easier to reason around inter-connected registry lock
objects (like when we add dependent roids). It will make it easier to
answer the question of "Have all locks associated with this host/contact
roid been unlocked?", as well as the question of "Was the last lock
object associated with this domain unlocked?"

* Responses to CR

* Make the DAO API more specific

* whoops, undo rename
2019-12-30 14:34:06 -07:00
41 changed files with 614 additions and 324 deletions
+10
View File
@@ -179,6 +179,16 @@ allprojects {
mavenCentral()
}
}
if (rootProject.enableCrossReferencing.toBoolean()) {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.fork = true
options.forkOptions.executable =
"${project.rootDir}/kythe/extractors/javac-wrapper.sh"
}
}
}
}
task runPresubmits(type: Exec) {
@@ -10,11 +10,11 @@ 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.google.api-client:google-api-client-appengine:1.30.6
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
com.google.api-client:google-api-client-servlet:1.30.6
com.google.api-client:google-api-client:1.30.6
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.38.0
@@ -84,22 +84,22 @@ 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.2
com.google.http-client:google-http-client-appengine:1.32.1
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.32.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.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.6
com.google.monitoring-client:stackdriver:1.0.6
com.google.oauth-client:google-oauth-client-appengine:1.30.4
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.30.4
com.google.oauth-client:google-oauth-client:1.30.4
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -124,7 +124,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.22.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -146,10 +146,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.24.0
io.opencensus:opencensus-contrib-http-util:0.21.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -183,8 +183,8 @@ 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.10
org.apache.httpcomponents:httpcore:4.4.12
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -10,11 +10,11 @@ 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.google.api-client:google-api-client-appengine:1.30.6
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
com.google.api-client:google-api-client-servlet:1.30.6
com.google.api-client:google-api-client:1.30.6
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.38.0
@@ -83,22 +83,22 @@ 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.2
com.google.http-client:google-http-client-appengine:1.32.1
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.32.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.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.6
com.google.monitoring-client:stackdriver:1.0.6
com.google.oauth-client:google-oauth-client-appengine:1.30.4
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.30.4
com.google.oauth-client:google-oauth-client:1.30.4
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -123,7 +123,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.22.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-core:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
io.grpc:grpc-netty:1.17.1
@@ -144,10 +144,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.24.0
io.opencensus:opencensus-contrib-http-util:0.21.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -181,8 +181,8 @@ 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.10
org.apache.httpcomponents:httpcore:4.4.12
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -10,11 +10,11 @@ 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.google.api-client:google-api-client-appengine:1.30.6
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
com.google.api-client:google-api-client-servlet:1.30.6
com.google.api-client:google-api-client:1.30.6
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.38.0
@@ -84,22 +84,22 @@ 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.2
com.google.http-client:google-http-client-appengine:1.32.1
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.32.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.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.6
com.google.monitoring-client:stackdriver:1.0.6
com.google.oauth-client:google-oauth-client-appengine:1.30.4
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.30.4
com.google.oauth-client:google-oauth-client:1.30.4
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -124,7 +124,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.22.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -146,10 +146,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.24.0
io.opencensus:opencensus-contrib-http-util:0.21.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -183,8 +183,8 @@ 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.10
org.apache.httpcomponents:httpcore:4.4.12
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -10,11 +10,11 @@ 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.google.api-client:google-api-client-appengine:1.30.6
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
com.google.api-client:google-api-client-servlet:1.30.6
com.google.api-client:google-api-client:1.30.6
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.38.0
@@ -84,22 +84,22 @@ 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.2
com.google.http-client:google-http-client-appengine:1.32.1
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.32.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.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.6
com.google.monitoring-client:stackdriver:1.0.6
com.google.oauth-client:google-oauth-client-appengine:1.30.4
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.30.4
com.google.oauth-client:google-oauth-client:1.30.4
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -124,7 +124,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.22.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -146,10 +146,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.24.0
io.opencensus:opencensus-contrib-http-util:0.21.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -183,8 +183,8 @@ 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.10
org.apache.httpcomponents:httpcore:4.4.12
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -32,7 +32,15 @@ public class CacheUtils {
* lists downloaded from the TMCH get updated in Datastore and the caches need to be refreshed.)
*/
public static <T> Supplier<T> memoizeWithShortExpiration(Supplier<T> original) {
Duration expiration = getSingletonCacheRefreshDuration();
return tryMemoizeWithExpiration(getSingletonCacheRefreshDuration(), original);
}
/**
* Memoize a supplier with the given expiration. If the expiration is zero(likely happens in a
* unit test), it returns the original supplier.
*/
public static <T> Supplier<T> tryMemoizeWithExpiration(
Duration expiration, Supplier<T> original) {
return expiration.isEqual(ZERO)
? original
: memoizeWithExpiration(original, expiration.getMillis(), MILLISECONDS);
@@ -49,7 +49,7 @@ public final class RegistryLockDao {
}
/** Returns all lock objects that this registrar has created. */
public static ImmutableList<RegistryLock> getByRegistrarId(String registrarId) {
public static ImmutableList<RegistryLock> getLockedDomainsByRegistrarId(String registrarId) {
return jpaTm()
.transact(
() ->
@@ -58,7 +58,9 @@ public final class RegistryLockDao {
.getEntityManager()
.createQuery(
"SELECT lock FROM RegistryLock lock WHERE"
+ " lock.registrarId = :registrarId",
+ " lock.registrarId = :registrarId "
+ "AND lock.lockCompletionTimestamp IS NOT NULL "
+ "AND lock.unlockCompletionTimestamp IS NULL",
RegistryLock.class)
.setParameter("registrarId", registrarId)
.getResultList()));
@@ -27,6 +27,10 @@ import static google.registry.util.DateTimeUtils.START_OF_TIME;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.MapDifference;
import com.google.common.collect.MapDifference.ValueDifference;
import com.google.common.collect.Maps;
import com.google.common.flogger.FluentLogger;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.EmbedMap;
@@ -40,6 +44,8 @@ import google.registry.model.annotations.NotBackedUp;
import google.registry.model.annotations.NotBackedUp.Reason;
import google.registry.model.annotations.VirtualEntity;
import google.registry.model.common.CrossTldSingleton;
import google.registry.schema.tmch.ClaimsList;
import google.registry.schema.tmch.ClaimsListDao;
import google.registry.util.CollectionUtils;
import google.registry.util.Concurrent;
import google.registry.util.Retrier;
@@ -71,6 +77,8 @@ import org.joda.time.DateTime;
@NotBackedUp(reason = Reason.EXTERNALLY_SOURCED)
public class ClaimsListShard extends ImmutableObject {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
/** The number of claims list entries to store per shard. */
private static final int SHARD_SIZE = 10000;
@@ -112,8 +120,7 @@ public class ClaimsListShard extends ImmutableObject {
Concurrent.transform(
shardKeys,
key ->
tm()
.transactNewReadOnly(
tm().transactNewReadOnly(
() -> {
ClaimsListShard claimsListShard = ofy().load().key(key).now();
checkState(
@@ -142,9 +149,52 @@ public class ClaimsListShard extends ImmutableObject {
}
}
}
return create(creationTime, ImmutableMap.copyOf(combinedLabelsToKeys));
ClaimsListShard datastoreList =
create(creationTime, ImmutableMap.copyOf(combinedLabelsToKeys));
// Also load the list from Cloud SQL, compare the two lists, and log if different.
try {
loadAndCompareCloudSqlList(datastoreList);
} catch (Throwable t) {
logger.atSevere().withCause(t).log("Error comparing reserved lists.");
}
return datastoreList;
};
private static final void loadAndCompareCloudSqlList(ClaimsListShard datastoreList) {
Optional<ClaimsList> maybeCloudSqlList = ClaimsListDao.getLatestRevision();
if (maybeCloudSqlList.isPresent()) {
ClaimsList cloudSqlList = maybeCloudSqlList.get();
MapDifference<String, String> diff =
Maps.difference(datastoreList.labelsToKeys, cloudSqlList.getLabelsToKeys());
if (!diff.areEqual()) {
if (diff.entriesDiffering().size() > 10) {
logger.atWarning().log(
String.format(
"Unequal claims lists detected, Cloud SQL list with revision id %d has %d"
+ " different records than the current Datastore list.",
cloudSqlList.getRevisionId(), diff.entriesDiffering().size()));
} else {
StringBuilder diffMessage = new StringBuilder("Unequal claims lists detected:\n");
diff.entriesDiffering().entrySet().stream()
.forEach(
entry -> {
String label = entry.getKey();
ValueDifference<String> valueDiff = entry.getValue();
diffMessage.append(
String.format(
"Domain label %s has key %s in Datastore and key %s in Cloud"
+ " SQL.\n",
label, valueDiff.leftValue(), valueDiff.rightValue()));
});
logger.atWarning().log(diffMessage.toString());
}
}
} else {
logger.atWarning().log("Claims list in Cloud SQL is empty.");
}
}
/**
* A cached supplier that fetches the claims list shards from Datastore and recombines them into a
* single {@link ClaimsListShard} object.
@@ -32,6 +32,9 @@ import org.hibernate.tool.schema.TargetType;
/** Utility class to export DDL script for given {@link javax.persistence.Entity} classes. */
public class HibernateSchemaExporter {
// Hibernate proprietary mappings.
private static final String HIBERNATE_MAPPING_RESOURCES = "META-INF/orm.xml";
private final String jdbcUrl;
private final String username;
private final String password;
@@ -63,6 +66,7 @@ public class HibernateSchemaExporter {
try (StandardServiceRegistry registry =
new StandardServiceRegistryBuilder().applySettings(settings).build()) {
MetadataSources metadata = new MetadataSources(registry);
metadata.addResource(HIBERNATE_MAPPING_RESOURCES);
// Note that we need to also add all converters to the Hibernate context because
// the entity class may use the customized type.
@@ -21,13 +21,12 @@ import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.model.Buildable;
import google.registry.model.CreateAutoTimestamp;
import google.registry.model.ImmutableObject;
import google.registry.model.UpdateAutoTimestamp;
import google.registry.util.DateTimeUtils;
import java.time.ZonedDateTime;
import java.util.Optional;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@@ -70,12 +69,6 @@ import org.joda.time.DateTime;
})
public final class RegistryLock extends ImmutableObject implements Buildable {
/** Describes the action taken by the user. */
public enum Action {
LOCK,
UNLOCK
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
@@ -99,28 +92,26 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
/** The POC that performed the action, or null if it was a superuser. */
private String registrarPocId;
/**
* Lock action is immutable and describes whether the action performed was a lock or an unlock.
*/
@Enumerated(EnumType.STRING)
/** When the lock is first requested. */
@Column(nullable = false)
private Action action;
private CreateAutoTimestamp lockRequestTimestamp = CreateAutoTimestamp.create(null);
/** Creation timestamp is when the lock/unlock is first requested. */
@Column(nullable = false)
private CreateAutoTimestamp creationTimestamp = CreateAutoTimestamp.create(null);
/** When the unlock is first requested. */
private ZonedDateTime unlockRequestTimestamp;
/**
* Completion timestamp is when the user has verified the lock/unlock, when this object de facto
* becomes immutable. If this field is null, it means that the lock has not been verified yet (and
* thus not been put into effect).
* When the user has verified the lock. If this field is null, it means the lock has not been
* verified yet (and thus not been put into effect).
*/
private ZonedDateTime completionTimestamp;
private ZonedDateTime lockCompletionTimestamp;
/**
* The user must provide the random verification code in order to complete the lock and move the
* status from PENDING to COMPLETED.
* When the user has verified the unlock of this lock. If this field is null, it means the unlock
* action has not been verified yet (and has not been put into effect).
*/
private ZonedDateTime unlockCompletionTimestamp;
/** The user must provide the random verification code in order to complete the action. */
@Column(nullable = false)
private String verificationCode;
@@ -131,6 +122,9 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
@Column(nullable = false)
private boolean isSuperuser;
/** Time that this entity was last updated. */
private UpdateAutoTimestamp lastUpdateTimestamp;
public String getRepoId() {
return repoId;
}
@@ -147,17 +141,25 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
return registrarPocId;
}
public Action getAction() {
return action;
public DateTime getLockRequestTimestamp() {
return lockRequestTimestamp.getTimestamp();
}
public DateTime getCreationTimestamp() {
return creationTimestamp.getTimestamp();
/** Returns the unlock request timestamp or null if an unlock has not been requested yet. */
public Optional<DateTime> getUnlockRequestTimestamp() {
return Optional.ofNullable(unlockRequestTimestamp).map(DateTimeUtils::toJodaDateTime);
}
/** Returns the completion timestamp, or empty if this lock has not been completed yet. */
public Optional<DateTime> getCompletionTimestamp() {
return Optional.ofNullable(completionTimestamp).map(DateTimeUtils::toJodaDateTime);
public Optional<DateTime> getLockCompletionTimestamp() {
return Optional.ofNullable(lockCompletionTimestamp).map(DateTimeUtils::toJodaDateTime);
}
/**
* Returns the unlock completion timestamp, or empty if this unlock has not been completed yet.
*/
public Optional<DateTime> getUnlockCompletionTimestamp() {
return Optional.ofNullable(unlockCompletionTimestamp).map(DateTimeUtils::toJodaDateTime);
}
public String getVerificationCode() {
@@ -168,16 +170,16 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
return isSuperuser;
}
public DateTime getLastUpdateTimestamp() {
return lastUpdateTimestamp.getTimestamp();
}
public Long getRevisionId() {
return revisionId;
}
public void setCompletionTimestamp(DateTime dateTime) {
this.completionTimestamp = toZonedDateTime(dateTime);
}
public boolean isVerified() {
return completionTimestamp != null;
public boolean isLocked() {
return lockCompletionTimestamp != null && unlockCompletionTimestamp == null;
}
@Override
@@ -198,8 +200,7 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
checkArgumentNotNull(getInstance().repoId, "Repo ID cannot be null");
checkArgumentNotNull(getInstance().domainName, "Domain name cannot be null");
checkArgumentNotNull(getInstance().registrarId, "Registrar ID cannot be null");
checkArgumentNotNull(getInstance().action, "Action cannot be null");
checkArgumentNotNull(getInstance().verificationCode, "Verification codecannot be null");
checkArgumentNotNull(getInstance().verificationCode, "Verification code cannot be null");
checkArgument(
getInstance().registrarPocId != null || getInstance().isSuperuser,
"Registrar POC ID must be provided if superuser is false");
@@ -226,18 +227,18 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
return this;
}
public Builder setAction(Action action) {
getInstance().action = action;
public Builder setUnlockRequestTimestamp(DateTime unlockRequestTimestamp) {
getInstance().unlockRequestTimestamp = toZonedDateTime(unlockRequestTimestamp);
return this;
}
public Builder setCreationTimestamp(CreateAutoTimestamp creationTimestamp) {
getInstance().creationTimestamp = creationTimestamp;
public Builder setLockCompletionTimestamp(DateTime lockCompletionTimestamp) {
getInstance().lockCompletionTimestamp = toZonedDateTime(lockCompletionTimestamp);
return this;
}
public Builder setCompletionTimestamp(DateTime lockTimestamp) {
getInstance().completionTimestamp = toZonedDateTime(lockTimestamp);
public Builder setUnlockCompletionTimestamp(DateTime unlockCompletionTimestamp) {
getInstance().unlockCompletionTimestamp = toZonedDateTime(unlockCompletionTimestamp);
return this;
}
@@ -80,7 +80,7 @@ public class PremiumListDao {
* <p>Note that this does not load <code>PremiumList.labelsToPrices</code>! If you need to check
* prices, use {@link #getPremiumPrice}.
*/
static Optional<PremiumList> getLatestRevision(String premiumListName) {
public static Optional<PremiumList> getLatestRevision(String premiumListName) {
return jpaTm()
.transact(
() ->
@@ -0,0 +1,61 @@
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.schema.tld;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import google.registry.model.registry.label.PremiumList.PremiumListEntry;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import org.joda.money.CurrencyUnit;
/** Static utility methods for {@link PremiumList}. */
public class PremiumListUtils {
public static PremiumList parseToPremiumList(String name, String inputData) {
List<String> inputDataPreProcessed =
Splitter.on('\n').omitEmptyStrings().splitToList(inputData);
ImmutableMap<String, PremiumListEntry> prices =
new google.registry.model.registry.label.PremiumList.Builder()
.setName(name)
.build()
.parse(inputDataPreProcessed);
ImmutableSet<CurrencyUnit> currencies =
prices.values().stream()
.map(e -> e.getValue().getCurrencyUnit())
.distinct()
.collect(toImmutableSet());
checkArgument(
currencies.size() == 1,
"The Cloud SQL schema requires exactly one currency, but got: %s",
ImmutableSortedSet.copyOf(currencies));
CurrencyUnit currency = Iterables.getOnlyElement(currencies);
Map<String, BigDecimal> priceAmounts =
Maps.transformValues(prices, ple -> ple.getValue().getAmount());
return google.registry.schema.tld.PremiumList.create(name, currency, priceAmounts);
}
private PremiumListUtils() {}
}
@@ -14,9 +14,14 @@
package google.registry.schema.tmch;
import static google.registry.config.RegistryConfig.getDomainLabelListCacheDuration;
import static google.registry.model.CacheUtils.tryMemoizeWithExpiration;
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
import com.google.common.base.Supplier;
import com.google.common.flogger.FluentLogger;
import google.registry.util.NonFinalForTesting;
import java.util.Optional;
import javax.persistence.EntityManager;
/** Data access object for {@link ClaimsList}. */
@@ -24,6 +29,11 @@ public class ClaimsListDao {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
/** In-memory cache for claims list. */
@NonFinalForTesting
private static Supplier<Optional<ClaimsList>> cacheClaimsList =
tryMemoizeWithExpiration(getDomainLabelListCacheDuration(), ClaimsListDao::getLatestRevision);
private static void save(ClaimsList claimsList) {
jpaTm().transact(() -> jpaTm().getEntityManager().persist(claimsList));
}
@@ -47,10 +57,12 @@ public class ClaimsListDao {
}
/**
* Returns the current revision of the {@link ClaimsList} in Cloud SQL. Throws exception if there
* is no claims in the table.
* Returns the most recent revision of the {@link ClaimsList} in Cloud SQL, if it exists.
* TODO(shicong): Change this method to package level access after dual-read phase.
* ClaimsListShard uses this method to retrieve claims list in Cloud SQL for the comparison, and
* ClaimsListShard is not in this package.
*/
public static ClaimsList getCurrent() {
public static Optional<ClaimsList> getLatestRevision() {
return jpaTm()
.transact(
() -> {
@@ -63,9 +75,15 @@ public class ClaimsListDao {
+ " :revisionId",
ClaimsList.class)
.setParameter("revisionId", revisionId)
.getSingleResult();
.getResultStream()
.findFirst();
});
}
/** Returns the most recent revision of the {@link ClaimsList}, from cache. */
public static Optional<ClaimsList> getLatestRevisionCached() {
return cacheClaimsList.get();
}
private ClaimsListDao() {}
}
@@ -16,7 +16,6 @@ package google.registry.tools;
import static com.google.common.base.Strings.isNullOrEmpty;
import static google.registry.security.JsonHttp.JSON_SAFETY_PREFIX;
import static google.registry.tools.server.CreateOrUpdatePremiumListAction.ALSO_CLOUD_SQL_PARAM;
import static google.registry.tools.server.CreateOrUpdatePremiumListAction.INPUT_PARAM;
import static google.registry.tools.server.CreateOrUpdatePremiumListAction.NAME_PARAM;
import static google.registry.util.ListNamingUtils.convertFilePathToName;
@@ -58,12 +57,6 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand
required = true)
Path inputFile;
@Parameter(
names = {"--also_cloud_sql"},
description =
"Persist premium list to Cloud SQL in addition to Datastore; defaults to false.")
boolean alsoCloudSql;
protected AppEngineConnection connection;
protected int inputLineCount;
@@ -97,7 +90,6 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand
public String execute() throws Exception {
ImmutableMap.Builder<String, String> params = new ImmutableMap.Builder<>();
params.put(NAME_PARAM, name);
params.put(ALSO_CLOUD_SQL_PARAM, Boolean.toString(alsoCloudSql));
String inputFileContents = new String(Files.readAllBytes(inputFile), UTF_8);
String requestBody =
Joiner.on('&').withKeyValueSeparator("=").join(
@@ -14,26 +14,13 @@
package google.registry.tools.server;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.flogger.LazyArgs.lazy;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.flogger.FluentLogger;
import google.registry.model.registry.label.PremiumList;
import google.registry.model.registry.label.PremiumList.PremiumListEntry;
import google.registry.request.JsonResponse;
import google.registry.request.Parameter;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.joda.money.CurrencyUnit;
/** Abstract base class for actions that update premium lists. */
public abstract class CreateOrUpdatePremiumListAction implements Runnable {
@@ -44,7 +31,6 @@ public abstract class CreateOrUpdatePremiumListAction implements Runnable {
public static final String NAME_PARAM = "name";
public static final String INPUT_PARAM = "inputData";
public static final String ALSO_CLOUD_SQL_PARAM = "alsoCloudSql";
@Inject JsonResponse response;
@@ -56,10 +42,6 @@ public abstract class CreateOrUpdatePremiumListAction implements Runnable {
@Parameter(INPUT_PARAM)
String inputData;
@Inject
@Parameter(ALSO_CLOUD_SQL_PARAM)
boolean alsoCloudSql;
@Override
public void run() {
try {
@@ -76,40 +58,15 @@ public abstract class CreateOrUpdatePremiumListAction implements Runnable {
return;
}
if (alsoCloudSql) {
try {
saveToCloudSql();
} catch (Throwable e) {
logger.atSevere().withCause(e).log(
"Unexpected error saving premium list to Cloud SQL from nomulus tool command");
response.setPayload(ImmutableMap.of("error", e.toString(), "status", "error"));
return;
}
try {
saveToCloudSql();
} catch (Throwable e) {
logger.atSevere().withCause(e).log(
"Unexpected error saving premium list to Cloud SQL from nomulus tool command");
response.setPayload(ImmutableMap.of("error", e.toString(), "status", "error"));
}
}
google.registry.schema.tld.PremiumList parseInputToPremiumList() {
List<String> inputDataPreProcessed =
Splitter.on('\n').omitEmptyStrings().splitToList(inputData);
ImmutableMap<String, PremiumListEntry> prices =
new PremiumList.Builder().setName(name).build().parse(inputDataPreProcessed);
ImmutableSet<CurrencyUnit> currencies =
prices.values().stream()
.map(e -> e.getValue().getCurrencyUnit())
.distinct()
.collect(toImmutableSet());
checkArgument(
currencies.size() == 1,
"The Cloud SQL schema requires exactly one currency, but got: %s",
ImmutableSortedSet.copyOf(currencies));
CurrencyUnit currency = Iterables.getOnlyElement(currencies);
Map<String, BigDecimal> priceAmounts =
Maps.transformValues(prices, ple -> ple.getValue().getAmount());
return google.registry.schema.tld.PremiumList.create(name, currency, priceAmounts);
}
/** Logs the premium list data at INFO, truncated if too long. */
void logInputData() {
logger.atInfo().log(
@@ -19,6 +19,7 @@ import static google.registry.model.registry.Registries.assertTldExists;
import static google.registry.model.registry.label.PremiumListUtils.doesPremiumListExist;
import static google.registry.model.registry.label.PremiumListUtils.savePremiumListAndEntries;
import static google.registry.request.Action.Method.POST;
import static google.registry.schema.tld.PremiumListUtils.parseToPremiumList;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
@@ -81,7 +82,7 @@ public class CreatePremiumListAction extends CreateOrUpdatePremiumListAction {
logger.atInfo().log("Saving premium list to Cloud SQL for TLD %s", name);
// TODO(mcilwain): Call logInputData() here once Datastore persistence is removed.
google.registry.schema.tld.PremiumList premiumList = parseInputToPremiumList();
google.registry.schema.tld.PremiumList premiumList = parseToPremiumList(name, inputData);
PremiumListDao.saveNew(premiumList);
String message =
@@ -60,12 +60,6 @@ public class ToolsServerModule {
return extractRequiredParameter(req, CreatePremiumListAction.INPUT_PARAM);
}
@Provides
@Parameter("alsoCloudSql")
static boolean provideAlsoCloudSql(HttpServletRequest req) {
return extractBooleanParameter(req, CreatePremiumListAction.ALSO_CLOUD_SQL_PARAM);
}
@Provides
@Parameter("premiumListName")
static String provideName(HttpServletRequest req) {
@@ -17,6 +17,7 @@ package google.registry.tools.server;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.model.registry.label.PremiumListUtils.savePremiumListAndEntries;
import static google.registry.request.Action.Method.POST;
import static google.registry.schema.tld.PremiumListUtils.parseToPremiumList;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
@@ -24,6 +25,7 @@ import com.google.common.flogger.FluentLogger;
import google.registry.model.registry.label.PremiumList;
import google.registry.request.Action;
import google.registry.request.auth.Auth;
import google.registry.schema.tld.PremiumListDao;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
@@ -68,10 +70,17 @@ public class UpdatePremiumListAction extends CreateOrUpdatePremiumListAction {
response.setPayload(ImmutableMap.of("status", "success", "message", message));
}
// TODO(mcilwain): Implement this in a subsequent PR.
@Override
protected void saveToCloudSql() {
throw new UnsupportedOperationException(
"Updating of premium lists in Cloud SQL is not supported yet");
logger.atInfo().log("Updating premium list '%s' in Cloud SQL.", name);
// TODO(mcilwain): Add logInputData() call here once DB migration is complete.
google.registry.schema.tld.PremiumList premiumList = parseToPremiumList(name, inputData);
PremiumListDao.update(premiumList);
String message =
String.format(
"Updated premium list '%s' with %d entries.",
premiumList.getName(), premiumList.getLabelsToPrices().size());
logger.atInfo().log(message);
// TODO(mcilwain): Call response.setPayload() here once DB migration is complete.
}
}
@@ -149,11 +149,9 @@ public final class RegistryLockGetAction implements JsonGetAction {
}
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());
return RegistryLockDao.getLockedDomainsByRegistrarId(clientId).stream()
.map(this::lockToMap)
.collect(toImmutableList());
}
private ImmutableMap<String, ?> lockToMap(RegistryLock lock) {
@@ -161,7 +159,7 @@ public final class RegistryLockGetAction implements JsonGetAction {
FULLY_QUALIFIED_DOMAIN_NAME_PARAM,
lock.getDomainName(),
LOCKED_TIME_PARAM,
lock.getCompletionTimestamp().map(DateTime::toString).orElse(""),
lock.getLockCompletionTimestamp().map(DateTime::toString).orElse(""),
LOCKED_BY_PARAM,
lock.isSuperuser() ? "admin" : lock.getRegistrarPocId());
}
@@ -22,7 +22,6 @@ import static google.registry.testing.JUnitBackports.assertThrows;
import google.registry.model.transaction.JpaTestRules;
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
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;
@@ -48,6 +47,7 @@ public final class RegistryLockDaoTest {
RegistryLock fromDatabase = RegistryLockDao.getByVerificationCode(lock.getVerificationCode());
assertThat(fromDatabase.getDomainName()).isEqualTo(lock.getDomainName());
assertThat(fromDatabase.getVerificationCode()).isEqualTo(lock.getVerificationCode());
assertThat(fromDatabase.getLastUpdateTimestamp()).isEqualTo(jpaRule.getTxnClock().nowUtc());
}
@Test
@@ -71,32 +71,56 @@ public final class RegistryLockDaoTest {
() -> {
RegistryLock updatedLock =
RegistryLockDao.getByVerificationCode(lock.getVerificationCode());
updatedLock.setCompletionTimestamp(jpaRule.getTxnClock().nowUtc());
RegistryLockDao.save(updatedLock);
RegistryLockDao.save(
updatedLock
.asBuilder()
.setLockCompletionTimestamp(jpaRule.getTxnClock().nowUtc())
.build());
});
jpaTm()
.transact(
() -> {
RegistryLock fromDatabase =
RegistryLockDao.getByVerificationCode(lock.getVerificationCode());
assertThat(fromDatabase.getCompletionTimestamp().get())
assertThat(fromDatabase.getLockCompletionTimestamp().get())
.isEqualTo(jpaRule.getTxnClock().nowUtc());
assertThat(fromDatabase.getLastUpdateTimestamp())
.isEqualTo(jpaRule.getTxnClock().nowUtc());
});
}
@Test
public void testSave_load_withUnlock() {
RegistryLock lock =
RegistryLockDao.save(
createLock()
.asBuilder()
.setLockCompletionTimestamp(jpaRule.getTxnClock().nowUtc())
.setUnlockRequestTimestamp(jpaRule.getTxnClock().nowUtc())
.setUnlockCompletionTimestamp(jpaRule.getTxnClock().nowUtc())
.build());
RegistryLockDao.save(lock);
RegistryLock fromDatabase = RegistryLockDao.getByVerificationCode(lock.getVerificationCode());
assertThat(fromDatabase.getUnlockRequestTimestamp())
.isEqualTo(Optional.of(jpaRule.getTxnClock().nowUtc()));
assertThat(fromDatabase.getUnlockCompletionTimestamp())
.isEqualTo(Optional.of(jpaRule.getTxnClock().nowUtc()));
assertThat(fromDatabase.isLocked()).isFalse();
}
@Test
public void testUpdateLock_usingSamePrimaryKey() {
RegistryLock lock = RegistryLockDao.save(createLock());
jpaRule.getTxnClock().advanceOneMilli();
RegistryLock updatedLock =
lock.asBuilder().setCompletionTimestamp(jpaRule.getTxnClock().nowUtc()).build();
lock.asBuilder().setLockCompletionTimestamp(jpaRule.getTxnClock().nowUtc()).build();
jpaTm().transact(() -> RegistryLockDao.save(updatedLock));
jpaTm()
.transact(
() -> {
RegistryLock fromDatabase =
RegistryLockDao.getByVerificationCode(lock.getVerificationCode());
assertThat(fromDatabase.getCompletionTimestamp())
assertThat(fromDatabase.getLockCompletionTimestamp())
.isEqualTo(Optional.of(jpaRule.getTxnClock().nowUtc()));
});
}
@@ -107,24 +131,39 @@ public final class RegistryLockDaoTest {
}
@Test
public void testLoad_byRegistrarId() {
RegistryLock lock = createLock();
RegistryLock secondLock = createLock().asBuilder().setDomainName("otherexample.test").build();
public void testLoad_lockedDomains_byRegistrarId() {
RegistryLock lock =
createLock().asBuilder().setLockCompletionTimestamp(jpaRule.getTxnClock().nowUtc()).build();
RegistryLock secondLock =
createLock()
.asBuilder()
.setDomainName("otherexample.test")
.setLockCompletionTimestamp(jpaRule.getTxnClock().nowUtc())
.build();
RegistryLock unlockedLock =
createLock()
.asBuilder()
.setDomainName("unlocked.test")
.setLockCompletionTimestamp(jpaRule.getTxnClock().nowUtc())
.setUnlockRequestTimestamp(jpaRule.getTxnClock().nowUtc())
.setUnlockCompletionTimestamp(jpaRule.getTxnClock().nowUtc())
.build();
RegistryLockDao.save(lock);
RegistryLockDao.save(secondLock);
RegistryLockDao.save(unlockedLock);
assertThat(
RegistryLockDao.getByRegistrarId("TheRegistrar").stream()
RegistryLockDao.getLockedDomainsByRegistrarId("TheRegistrar").stream()
.map(RegistryLock::getDomainName)
.collect(toImmutableSet()))
.containsExactly("example.test", "otherexample.test");
assertThat(RegistryLockDao.getByRegistrarId("nonexistent")).isEmpty();
assertThat(RegistryLockDao.getLockedDomainsByRegistrarId("nonexistent")).isEmpty();
}
@Test
public void testLoad_byRepoId() {
RegistryLock completedLock =
createLock().asBuilder().setCompletionTimestamp(jpaRule.getTxnClock().nowUtc()).build();
createLock().asBuilder().setLockCompletionTimestamp(jpaRule.getTxnClock().nowUtc()).build();
RegistryLockDao.save(completedLock);
jpaRule.getTxnClock().advanceOneMilli();
@@ -133,7 +172,7 @@ public final class RegistryLockDaoTest {
Optional<RegistryLock> mostRecent = RegistryLockDao.getMostRecentByRepoId("repoId");
assertThat(mostRecent.isPresent()).isTrue();
assertThat(mostRecent.get().isVerified()).isFalse();
assertThat(mostRecent.get().isLocked()).isFalse();
}
@Test
@@ -146,7 +185,6 @@ public final class RegistryLockDaoTest {
.setRepoId("repoId")
.setDomainName("example.test")
.setRegistrarId("TheRegistrar")
.setAction(Action.LOCK)
.setVerificationCode(UUID.randomUUID().toString())
.isSuperuser(true)
.build();
@@ -119,6 +119,9 @@ abstract class JpaTransactionManagerRule extends ExternalResource {
// If there are user properties, create a new properties object with these added.
ImmutableMap.Builder builder = properties.builder();
builder.putAll(userProperties);
// Forbid Hibernate push to stay consistent with flyway-based schema management.
builder.put(Environment.HBM2DDL_AUTO, "none");
builder.put(Environment.SHOW_SQL, "true");
properties = builder.build();
}
assertNormalActiveConnection();
@@ -35,7 +35,6 @@ 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;
@@ -67,7 +66,6 @@ public class JodaMoneyConverterTest {
public final JpaUnitTestRule jpaRule =
new JpaTestRules.Builder()
.withEntityClass(TestEntity.class, ComplexTestEntity.class)
.withProperty(Environment.HBM2DDL_AUTO, "update")
.buildUnitTestRule();
@Test
@@ -82,7 +80,7 @@ public class JodaMoneyConverterTest {
jpaTm()
.getEntityManager()
.createNativeQuery(
"SELECT amount, currency FROM TestEntity WHERE name = 'id'")
"SELECT amount, currency FROM \"TestEntity\" WHERE name = 'id'")
.getResultList());
assertThat(result.size()).isEqualTo(1);
assertThat(Arrays.asList((Object[]) result.get(0)))
@@ -113,7 +111,7 @@ public class JodaMoneyConverterTest {
.getEntityManager()
.createNativeQuery(
"SELECT my_amount, my_currency, your_amount, your_currency FROM"
+ " ComplexTestEntity WHERE name = 'id'")
+ " \"ComplexTestEntity\" WHERE name = 'id'")
.getResultList());
assertThat(result.size()).isEqualTo(1);
assertThat(Arrays.asList((Object[]) result.get(0)))
@@ -127,7 +125,7 @@ public class JodaMoneyConverterTest {
jpaTm()
.getEntityManager()
.createNativeQuery(
"SELECT map_amount, map_currency FROM MoneyMap"
"SELECT map_amount, map_currency FROM \"MoneyMap\""
+ " WHERE entity_name = 'id' AND map_key = 'dos'")
.getResultList());
ComplexTestEntity persisted =
@@ -148,7 +146,9 @@ public class JodaMoneyConverterTest {
assertThat(persisted.moneyMap).containsExactlyEntriesIn(moneyMap);
}
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
// Override entity name to exclude outer-class name in table name. Not necessary if class is not
// inner class. The double quotes are added to conform to our schema generation convention.
@Entity(name = "\"TestEntity\"")
public static class TestEntity extends ImmutableObject {
@Id String name = "id";
@@ -162,7 +162,8 @@ public class JodaMoneyConverterTest {
}
}
@Entity(name = "ComplexTestEntity") // Override entity name to avoid the nested class reference.
// See comments on the annotation for TestEntity above for reason.
@Entity(name = "\"ComplexTestEntity\"")
// This entity is used to test column override for embedded fields and collections.
public static class ComplexTestEntity extends ImmutableObject {
@@ -18,10 +18,13 @@ import google.registry.model.registry.RegistryLockDaoTest;
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
import google.registry.schema.cursor.CursorDaoTest;
import google.registry.schema.tld.PremiumListDaoTest;
import google.registry.schema.tld.PremiumListUtilsTest;
import google.registry.schema.tld.ReservedListDaoTest;
import google.registry.schema.tmch.ClaimsListDaoTest;
import google.registry.tools.CreateReservedListCommandTest;
import google.registry.tools.UpdateReservedListCommandTest;
import google.registry.tools.server.CreatePremiumListActionTest;
import google.registry.tools.server.UpdatePremiumListActionTest;
import google.registry.ui.server.registrar.RegistryLockGetActionTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -41,10 +44,13 @@ import org.junit.runners.Suite.SuiteClasses;
ClaimsListDaoTest.class,
CreateReservedListCommandTest.class,
CursorDaoTest.class,
CreatePremiumListActionTest.class,
PremiumListDaoTest.class,
PremiumListUtilsTest.class,
RegistryLockDaoTest.class,
RegistryLockGetActionTest.class,
ReservedListDaoTest.class,
UpdatePremiumListActionTest.class,
UpdateReservedListCommandTest.class
})
public class SqlIntegrationTestSuite {}
@@ -32,8 +32,8 @@ import google.registry.model.transaction.JpaTestRules;
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
import google.registry.testing.AppEngineRule;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.junit.Rule;
import org.junit.Test;
@@ -66,13 +66,9 @@ public class PremiumListDaoTest {
jpaTm()
.transact(
() -> {
PremiumList persistedList =
jpaTm()
.getEntityManager()
.createQuery(
"SELECT pl FROM PremiumList pl WHERE pl.name = :name", PremiumList.class)
.setParameter("name", "testname")
.getSingleResult();
Optional<PremiumList> persistedListOpt = PremiumListDao.getLatestRevision("testname");
assertThat(persistedListOpt).isPresent();
PremiumList persistedList = persistedListOpt.get();
assertThat(persistedList.getLabelsToPrices()).containsExactlyEntriesIn(TEST_PRICES);
assertThat(persistedList.getCreationTimestamp())
.isEqualTo(jpaRule.getTxnClock().nowUtc());
@@ -81,26 +77,40 @@ public class PremiumListDaoTest {
@Test
public void update_worksSuccessfully() {
PremiumListDao.saveNew(
PremiumListDao.saveNew(PremiumList.create("testname", CurrencyUnit.USD, TEST_PRICES));
Optional<PremiumList> persistedList = PremiumListDao.getLatestRevision("testname");
assertThat(persistedList).isPresent();
long firstRevisionId = persistedList.get().getRevisionId();
PremiumListDao.update(
PremiumList.create(
"testname", USD, ImmutableMap.of("firstversion", BigDecimal.valueOf(123.45))));
PremiumListDao.update(PremiumList.create("testname", USD, TEST_PRICES));
"testname",
CurrencyUnit.USD,
ImmutableMap.of(
"update",
BigDecimal.valueOf(55343.12),
"new",
BigDecimal.valueOf(0.01),
"silver",
BigDecimal.valueOf(30.03))));
jpaTm()
.transact(
() -> {
List<PremiumList> persistedLists =
jpaTm()
.getEntityManager()
.createQuery(
"SELECT pl FROM PremiumList pl WHERE pl.name = :name ORDER BY"
+ " pl.revisionId",
PremiumList.class)
.setParameter("name", "testname")
.getResultList();
assertThat(persistedLists).hasSize(2);
assertThat(persistedLists.get(1).getLabelsToPrices())
.containsExactlyEntriesIn(TEST_PRICES);
assertThat(persistedLists.get(1).getCreationTimestamp())
Optional<PremiumList> updatedListOpt = PremiumListDao.getLatestRevision("testname");
assertThat(updatedListOpt).isPresent();
PremiumList updatedList = updatedListOpt.get();
assertThat(updatedList.getLabelsToPrices())
.containsExactlyEntriesIn(
ImmutableMap.of(
"update",
BigDecimal.valueOf(55343.12),
"new",
BigDecimal.valueOf(0.01),
"silver",
BigDecimal.valueOf(30.03)));
assertThat(updatedList.getCreationTimestamp())
.isEqualTo(jpaRule.getTxnClock().nowUtc());
assertThat(updatedList.getRevisionId()).isGreaterThan(firstRevisionId);
assertThat(updatedList.getCreationTimestamp())
.isEqualTo(jpaRule.getTxnClock().nowUtc());
});
}
@@ -116,7 +126,7 @@ public class PremiumListDaoTest {
}
@Test
public void update_throwsWhenPremiumListDoesntExist() {
public void update_throwsWhenListDoesntExist() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
@@ -1,4 +1,4 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
// 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.
@@ -12,43 +12,35 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.tools.server;
package google.registry.schema.tld;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static google.registry.schema.tld.PremiumListUtils.parseToPremiumList;
import static google.registry.testing.JUnitBackports.assertThrows;
import google.registry.schema.tld.PremiumList;
import google.registry.model.transaction.JpaTestRules;
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
import google.registry.testing.AppEngineRule;
import google.registry.testing.FakeJsonResponse;
import java.math.BigDecimal;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link CreateOrUpdatePremiumListAction}. */
/** Unit tests for {@link PremiumListUtils}. */
@RunWith(JUnit4.class)
public class CreateOrUpdatePremiumListActionTest {
public class PremiumListUtilsTest {
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
private CreatePremiumListAction action;
private FakeJsonResponse response;
@Before
public void init() {
action = new CreatePremiumListAction();
response = new FakeJsonResponse();
action.response = response;
action.name = "testlist";
}
@Rule
public final JpaIntegrationTestRule jpaRule =
new JpaTestRules.Builder().buildIntegrationTestRule();
@Test
public void parseInputToPremiumList_works() {
action.inputData = "foo,USD 99.50\n" + "bar,USD 30\n" + "baz,USD 10\n";
PremiumList premiumList = action.parseInputToPremiumList();
PremiumList premiumList =
parseToPremiumList("testlist", "foo,USD 99.50\n" + "bar,USD 30\n" + "baz,USD 10\n");
assertThat(premiumList.getName()).isEqualTo("testlist");
assertThat(premiumList.getLabelsToPrices())
.containsExactly("foo", twoDigits(99.50), "bar", twoDigits(30), "baz", twoDigits(10));
@@ -56,9 +48,12 @@ public class CreateOrUpdatePremiumListActionTest {
@Test
public void parseInputToPremiumList_throwsOnInconsistentCurrencies() {
action.inputData = "foo,USD 99.50\n" + "bar,USD 30\n" + "baz,JPY 990\n";
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> action.parseInputToPremiumList());
assertThrows(
IllegalArgumentException.class,
() ->
parseToPremiumList(
"testlist", "foo,USD 99.50\n" + "bar,USD 30\n" + "baz,JPY 990\n"));
assertThat(thrown)
.hasMessageThat()
.isEqualTo("The Cloud SQL schema requires exactly one currency, but got: [JPY, USD]");
@@ -15,13 +15,11 @@
package google.registry.schema.tmch;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.JUnitBackports.assertThrows;
import com.google.common.collect.ImmutableMap;
import google.registry.model.transaction.JpaTestRules;
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
import google.registry.testing.FakeClock;
import javax.persistence.NoResultException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -42,7 +40,7 @@ public class ClaimsListDaoTest {
ClaimsList claimsList =
ClaimsList.create(fakeClock.nowUtc(), ImmutableMap.of("label1", "key1", "label2", "key2"));
ClaimsListDao.trySave(claimsList);
ClaimsList insertedClaimsList = ClaimsListDao.getCurrent();
ClaimsList insertedClaimsList = ClaimsListDao.getLatestRevision().get();
assertClaimsListEquals(claimsList, insertedClaimsList);
assertThat(insertedClaimsList.getCreationTimestamp()).isEqualTo(jpaRule.getTxnClock().nowUtc());
}
@@ -52,7 +50,7 @@ public class ClaimsListDaoTest {
ClaimsList claimsList =
ClaimsList.create(fakeClock.nowUtc(), ImmutableMap.of("label1", "key1", "label2", "key2"));
ClaimsListDao.trySave(claimsList);
ClaimsList insertedClaimsList = ClaimsListDao.getCurrent();
ClaimsList insertedClaimsList = ClaimsListDao.getLatestRevision().get();
assertClaimsListEquals(claimsList, insertedClaimsList);
// Save ClaimsList with existing revisionId should fail because revisionId is the primary key.
ClaimsListDao.trySave(insertedClaimsList);
@@ -62,14 +60,14 @@ public class ClaimsListDaoTest {
public void trySave_claimsListWithNoEntries() {
ClaimsList claimsList = ClaimsList.create(fakeClock.nowUtc(), ImmutableMap.of());
ClaimsListDao.trySave(claimsList);
ClaimsList insertedClaimsList = ClaimsListDao.getCurrent();
ClaimsList insertedClaimsList = ClaimsListDao.getLatestRevision().get();
assertClaimsListEquals(claimsList, insertedClaimsList);
assertThat(insertedClaimsList.getLabelsToKeys()).isEmpty();
}
@Test
public void getCurrent_throwsNoResultExceptionIfTableIsEmpty() {
assertThrows(NoResultException.class, ClaimsListDao::getCurrent);
public void getCurrent_returnsEmptyListIfTableIsEmpty() {
assertThat(ClaimsListDao.getLatestRevision().isPresent()).isFalse();
}
@Test
@@ -80,7 +78,7 @@ public class ClaimsListDaoTest {
ClaimsList.create(fakeClock.nowUtc(), ImmutableMap.of("label3", "key3", "label4", "key4"));
ClaimsListDao.trySave(oldClaimsList);
ClaimsListDao.trySave(newClaimsList);
assertClaimsListEquals(newClaimsList, ClaimsListDao.getCurrent());
assertClaimsListEquals(newClaimsList, ClaimsListDao.getLatestRevision().get());
}
private void assertClaimsListEquals(ClaimsList left, ClaimsList right) {
@@ -16,9 +16,13 @@ package google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.persistPremiumList;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.JUnitBackports.assertThrows;
import com.beust.jcommander.ParameterException;
import google.registry.model.registry.Registry;
import google.registry.model.registry.label.PremiumList;
import google.registry.testing.DeterministicStringGenerator;
import org.junit.Before;
import org.junit.Test;
@@ -91,7 +95,14 @@ public class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomain
}
@Test
public void testSuccess_premiumDomain() throws Exception {
public void testSuccess_premiumJpyDomain() throws Exception {
createTld("baar");
persistPremiumList("baar", "parajiumu,JPY 96083");
persistResource(
Registry.get("baar")
.asBuilder()
.setPremiumList(PremiumList.getUncached("baar").get())
.build());
runCommandForced(
"--client=NewRegistrar",
"--registrant=crr-admin",
@@ -99,10 +110,10 @@ public class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomain
"--techs=crr-tech",
"--period=3",
"--force_premiums",
"parajiumu.tld");
"parajiumu.baar");
eppVerifier.verifySent("domain_create_parajiumu_3yrs.xml");
assertInStdout(
"parajiumu.tld is premium at JPY 96083 per year; "
"parajiumu.baar is premium at JPY 96083 per year; "
+ "sending total cost for 3 year(s) of JPY 288249.");
}
@@ -67,13 +67,7 @@ public class CreatePremiumListCommandTest<C extends CreatePremiumListCommand>
verifySentParams(
connection,
servletPath,
ImmutableMap.of(
"name",
"foo",
"inputData",
generateInputData(premiumTermsPath),
"alsoCloudSql",
"false"));
ImmutableMap.of("name", "foo", "inputData", generateInputData(premiumTermsPath)));
}
@Test
@@ -84,28 +78,7 @@ public class CreatePremiumListCommandTest<C extends CreatePremiumListCommand>
connection,
servletPath,
ImmutableMap.of(
"name",
"example_premium_terms",
"inputData",
generateInputData(premiumTermsPath),
"alsoCloudSql",
"false"));
}
@Test
public void testRun_alsoCloudSql() throws Exception {
runCommandForced("-i=" + premiumTermsPath, "-n=foo", "--also_cloud_sql");
assertInStdout("Successfully");
verifySentParams(
connection,
servletPath,
ImmutableMap.of(
"name",
"foo",
"inputData",
generateInputData(premiumTermsPath),
"alsoCloudSql",
"true"));
"name", "example_premium_terms", "inputData", generateInputData(premiumTermsPath)));
}
@Test
@@ -57,13 +57,7 @@ public class UpdatePremiumListCommandTest<C extends UpdatePremiumListCommand>
verifySentParams(
connection,
servletPath,
ImmutableMap.of(
"name",
"foo",
"inputData",
generateInputData(premiumTermsPath),
"alsoCloudSql",
"false"));
ImmutableMap.of("name", "foo", "inputData", generateInputData(premiumTermsPath)));
}
@Test
@@ -74,11 +68,6 @@ public class UpdatePremiumListCommandTest<C extends UpdatePremiumListCommand>
connection,
servletPath,
ImmutableMap.of(
"name",
"example_premium_terms",
"inputData",
generateInputData(premiumTermsPath),
"alsoCloudSql",
"false"));
"name", "example_premium_terms", "inputData", generateInputData(premiumTermsPath)));
}
}
@@ -24,6 +24,8 @@ import static javax.servlet.http.HttpServletResponse.SC_OK;
import google.registry.model.registry.Registry;
import google.registry.model.registry.label.PremiumList;
import google.registry.model.transaction.JpaTestRules;
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
import google.registry.testing.AppEngineRule;
import google.registry.testing.FakeJsonResponse;
import org.joda.money.Money;
@@ -39,6 +41,10 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class CreatePremiumListActionTest {
@Rule
public final JpaIntegrationTestRule jpaRule =
new JpaTestRules.Builder().buildIntegrationTestRule();
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
CreatePremiumListAction action;
FakeJsonResponse response;
@@ -17,14 +17,22 @@ package google.registry.tools.server;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static google.registry.model.registry.label.PremiumListUtils.getPremiumPrice;
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.schema.tld.PremiumListUtils.parseToPremiumList;
import static google.registry.testing.DatastoreHelper.createTlds;
import static google.registry.testing.DatastoreHelper.loadPremiumListEntries;
import static google.registry.util.ResourceUtils.readResourceUtf8;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import google.registry.model.registry.Registry;
import google.registry.model.registry.label.PremiumList;
import google.registry.model.transaction.JpaTestRules;
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
import google.registry.schema.tld.PremiumListDao;
import google.registry.testing.AppEngineRule;
import google.registry.testing.DatastoreHelper;
import google.registry.testing.FakeJsonResponse;
import java.math.BigDecimal;
import org.joda.money.Money;
import org.junit.Before;
import org.junit.Rule;
@@ -38,10 +46,11 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class UpdatePremiumListActionTest {
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
@Rule
public final AppEngineRule appEngine = AppEngineRule.builder()
.withDatastore()
.build();
public final JpaIntegrationTestRule jpaRule =
new JpaTestRules.Builder().buildIntegrationTestRule();
UpdatePremiumListAction action;
FakeJsonResponse response;
@@ -75,6 +84,9 @@ public class UpdatePremiumListActionTest {
@Test
public void test_success() {
PremiumListDao.saveNew(
parseToPremiumList(
"foo", readResourceUtf8(DatastoreHelper.class, "default_premium_list_testdata.csv")));
action.name = "foo";
action.inputData = "rich,USD 75\nricher,USD 5000\npoor, USD 0.99";
action.run();
@@ -85,5 +97,19 @@ public class UpdatePremiumListActionTest {
assertThat(getPremiumPrice("richer", registry)).hasValue(Money.parse("USD 5000"));
assertThat(getPremiumPrice("poor", registry)).hasValue(Money.parse("USD 0.99"));
assertThat(getPremiumPrice("diamond", registry)).isEmpty();
jpaTm()
.transact(
() -> {
google.registry.schema.tld.PremiumList persistedList =
PremiumListDao.getLatestRevision("foo").get();
assertThat(persistedList.getLabelsToPrices())
.containsEntry("rich", new BigDecimal("75.00"));
assertThat(persistedList.getLabelsToPrices())
.containsEntry("richer", new BigDecimal("5000.00"));
assertThat(persistedList.getLabelsToPrices())
.containsEntry("poor", BigDecimal.valueOf(0.99));
assertThat(persistedList.getLabelsToPrices()).doesNotContainKey("diamond");
});
}
}
@@ -38,7 +38,6 @@ import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.request.auth.UserAuthInfo;
import google.registry.schema.domain.RegistryLock;
import google.registry.schema.domain.RegistryLock.Action;
import google.registry.testing.AppEngineRule;
import google.registry.testing.FakeResponse;
import java.util.Map;
@@ -95,10 +94,9 @@ public final class RegistryLockGetActionTest {
.setRepoId("repoId")
.setDomainName("example.test")
.setRegistrarId("TheRegistrar")
.setAction(Action.LOCK)
.setVerificationCode(UUID.randomUUID().toString())
.setRegistrarPocId("johndoe@theregistrar.com")
.setCompletionTimestamp(jpaRule.getTxnClock().nowUtc())
.setLockCompletionTimestamp(jpaRule.getTxnClock().nowUtc())
.build();
jpaRule.getTxnClock().advanceOneMilli();
RegistryLock adminLock =
@@ -106,24 +104,35 @@ public final class RegistryLockGetActionTest {
.setRepoId("repoId")
.setDomainName("adminexample.test")
.setRegistrarId("TheRegistrar")
.setAction(Action.LOCK)
.setVerificationCode(UUID.randomUUID().toString())
.isSuperuser(true)
.setCompletionTimestamp(jpaRule.getTxnClock().nowUtc())
.setLockCompletionTimestamp(jpaRule.getTxnClock().nowUtc())
.build();
RegistryLock incompleteLock =
new RegistryLock.Builder()
.setRepoId("repoId")
.setDomainName("incomplete.test")
.setRegistrarId("TheRegistrar")
.setAction(Action.LOCK)
.setVerificationCode(UUID.randomUUID().toString())
.setRegistrarPocId("johndoe@theregistrar.com")
.build();
RegistryLock unlockedLock =
new RegistryLock.Builder()
.setRepoId("repoId")
.setDomainName("unlocked.test")
.setRegistrarId("TheRegistrar")
.setRegistrarPocId("johndoe@theregistrar.com")
.setVerificationCode(UUID.randomUUID().toString())
.setLockCompletionTimestamp(jpaRule.getTxnClock().nowUtc())
.setUnlockRequestTimestamp(jpaRule.getTxnClock().nowUtc())
.setUnlockCompletionTimestamp(jpaRule.getTxnClock().nowUtc())
.build();
RegistryLockDao.save(regularLock);
RegistryLockDao.save(adminLock);
RegistryLockDao.save(incompleteLock);
RegistryLockDao.save(unlockedLock);
action.run();
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_OK);
@@ -134,9 +143,12 @@ public final class RegistryLockGetActionTest {
"results",
ImmutableList.of(
ImmutableMap.of(
"lockEnabledForContact", true,
"email", "Marla.Singer@crr.com",
"clientId", "TheRegistrar",
"lockEnabledForContact",
true,
"email",
"Marla.Singer@crr.com",
"clientId",
"TheRegistrar",
"locks",
ImmutableList.of(
ImmutableMap.of(
@@ -10,4 +10,3 @@ palladium,USD 877
aluminum,USD 11
copper,USD 15
brass,USD 20
parajiumu,JPY 96083
1 rich USD 100
10 aluminum USD 11
11 copper USD 15
12 brass USD 20
parajiumu JPY 96083
@@ -4,7 +4,7 @@
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>parajiumu.tld</domain:name>
<domain:name>parajiumu.baar</domain:name>
<domain:period unit="y">3</domain:period>
<domain:registrant>crr-admin</domain:registrant>
<domain:contact type="admin">crr-admin</domain:contact>
@@ -0,0 +1,22 @@
-- 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.
ALTER TABLE "RegistryLock" DROP COLUMN action;
ALTER TABLE "RegistryLock" ADD COLUMN unlock_request_timestamp timestamptz;
ALTER TABLE "RegistryLock" ADD COLUMN unlock_completion_timestamp timestamptz;
ALTER TABLE "RegistryLock" ADD COLUMN last_update_timestamp timestamptz;
ALTER TABLE "RegistryLock" RENAME creation_timestamp TO lock_request_timestamp;
ALTER TABLE "RegistryLock" RENAME completion_timestamp TO lock_completion_timestamp;
@@ -148,14 +148,16 @@
create table "RegistryLock" (
revision_id bigserial not null,
action text not null,
completion_timestamp timestamptz,
creation_timestamp timestamptz not null,
domain_name text not null,
is_superuser boolean not null,
last_update_timestamp timestamptz,
lock_completion_timestamp timestamptz,
lock_request_timestamp timestamptz not null,
registrar_id text not null,
registrar_poc_id text,
repo_id text not null,
unlock_completion_timestamp timestamptz,
unlock_request_timestamp timestamptz,
verification_code text not null,
primary key (revision_id)
);
@@ -122,15 +122,17 @@ ALTER SEQUENCE public."PremiumList_revision_id_seq" OWNED BY public."PremiumList
CREATE TABLE public."RegistryLock" (
revision_id bigint NOT NULL,
action text NOT NULL,
completion_timestamp timestamp with time zone,
creation_timestamp timestamp with time zone NOT NULL,
lock_completion_timestamp timestamp with time zone,
lock_request_timestamp timestamp with time zone NOT NULL,
domain_name text NOT NULL,
is_superuser boolean NOT NULL,
registrar_id text NOT NULL,
registrar_poc_id text,
repo_id text NOT NULL,
verification_code text NOT NULL
verification_code text NOT NULL,
unlock_request_timestamp timestamp with time zone,
unlock_completion_timestamp timestamp with time zone,
last_update_timestamp timestamp with time zone
);
+1
View File
@@ -7,6 +7,7 @@ uploaderMultithreadedUpload=
verboseTestOutput=false
flowDocsFile=
enableDependencyLocking=true
enableCrossReferencing=false
# Comma separated list of test patterns, if specified run only these.
testFilter=
+61
View File
@@ -0,0 +1,61 @@
# To run the build locally, install cloud-build-local first.
# See: https://cloud.google.com/cloud-build/docs/build-debug-locally
# In the root of a nomulus source tree, run:
# cloud-build-local --config=cloudbuild-kythe.yaml --dryrun=false \
# --substitutions _KYTHE_VERSION=[kythe_version],COMMIT_HASH=[hash] .
# This will download kythe version ${kythe_version} (must be higher than
# v0.0.39 and build a ${hash}.kzip file for Kythe to enable cross referencing.
#
# To manually trigger a build on GCB, run:
# gcloud builds submit --config cloudbuild-kythe.yaml --substitutions \
# _KYTHE_VERSION[kythe_version] .
#
# To trigger a build automatically, follow the instructions below and add a trigger:
# https://cloud.google.com/cloud-build/docs/running-builds/automate-builds
steps:
# Download Kythe
- name: 'openjdk:11'
entrypoint: /bin/bash
args:
- -c
- |
wget -q \
https://github.com/kythe/kythe/releases/download/${_KYTHE_VERSION}/kythe-${_KYTHE_VERSION}.tar.gz
tar xvf kythe-${_KYTHE_VERSION}.tar.gz
rm kythe-${_KYTHE_VERSION}.tar.gz
mv kythe-${_KYTHE_VERSION} kythe
# Build Nomulus with the Kythe wrapper
- name: 'openjdk:11'
entrypoint: /bin/bash
args:
- -c
- |
export REAL_JAVAC=$(which javac)
export JAVAC_EXTRACTOR_JAR="$${PWD}/kythe/extractors/javac_extractor.jar"
export KYTHE_VNAMES="$${PWD}/vnames.json"
export KYTHE_ROOT_DIRECTORY="$${PWD}"
export KYTHE_OUTPUT_DIRECTORY="$${PWD}/kythe_output"
mkdir -p $${KYTHE_OUTPUT_DIRECTORY}
mkdir -p $${KYTHE_OUTPUT_DIRECTORY}/merged
./gradlew clean testClasses -x compileProdJS \
-Dno_werror=true -PenableCrossReferencing=true
# Merge kzip files
- name: 'openjdk:11'
entrypoint: /bin/bash
args:
- -c
- |
export KYTHE_OUTPUT_DIRECTORY="$${PWD}/kythe_output"
./kythe/tools/kzip merge \
--output $${KYTHE_OUTPUT_DIRECTORY}/merged/${COMMIT_SHA}.kzip \
$${KYTHE_OUTPUT_DIRECTORY}/*.kzip
artifacts:
objects:
location: 'gs://${PROJECT_ID}-codesearch'
paths:
- 'kythe_output/merged/${COMMIT_SHA}.kzip'
timeout: 3600s
options:
machineType: 'N1_HIGHCPU_8'
@@ -29,7 +29,9 @@ public abstract class EmailMessage {
public abstract String body();
public abstract ImmutableList<InternetAddress> recipients();
public abstract InternetAddress from();
public abstract ImmutableList<InternetAddress> bccs();
public abstract Optional<MediaType> contentType();
public abstract Optional<Attachment> attachment();
@@ -55,11 +57,14 @@ public abstract class EmailMessage {
public abstract Builder setBody(String body);
public abstract Builder setRecipients(Collection<InternetAddress> recipients);
public abstract Builder setFrom(InternetAddress from);
public abstract Builder setBccs(Collection<InternetAddress> bccs);
public abstract Builder setContentType(MediaType contentType);
public abstract Builder setAttachment(Attachment attachment);
abstract ImmutableList.Builder<InternetAddress> recipientsBuilder();
abstract ImmutableList.Builder<InternetAddress> bccsBuilder();
public Builder addRecipient(InternetAddress value) {
+25
View File
@@ -0,0 +1,25 @@
[
{
"pattern": "(build/[^/]+)/(.*)",
"vname": {
"corpus": "github.com/google/nomulus",
"path": "@2@",
"root": "@1@"
}
},
{
"pattern": ".*/.gradle/caches/(.*)",
"vname": {
"corpus": "github.com/google/nomulus",
"path": "@1@",
"root": ".gradle/caches"
}
},
{
"pattern": "(.*)",
"vname": {
"corpus": "github.com/google/nomulus",
"path": "@1@"
}
}
]