mirror of
https://github.com/google/nomulus
synced 2026-06-09 16:33:02 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c844c8e9b1 | |||
| f747610533 | |||
| e1db357fc3 | |||
| ba1915e271 | |||
| 58618a274e | |||
| e4d0571125 | |||
| 4cb88ab6e7 | |||
| 987f390ff7 | |||
| ca756e14e6 | |||
| caa0cd9d61 | |||
| 7806cc7edb | |||
| 0964fdf1dc | |||
| d17ec1fcb1 | |||
| fac5987c13 | |||
| a3319e0026 | |||
| 5578464e06 | |||
| c24a61f813 | |||
| 806f3b2456 | |||
| 333170a724 | |||
| 47eeb8c4e4 | |||
| 391929b518 | |||
| 7f62b7a89c | |||
| a1da32bfde | |||
| 1961a5759d |
@@ -79,6 +79,10 @@ nomulus.iml
|
||||
nomulus.ipr
|
||||
nomulus.iws
|
||||
|
||||
# Auto-generated java classes by Intellij
|
||||
*/src/main/generated/
|
||||
*/src/test/generated_tests/
|
||||
|
||||
# VScode
|
||||
.vscode
|
||||
|
||||
|
||||
+15
-3
@@ -25,7 +25,7 @@ buildscript {
|
||||
|
||||
dependencies {
|
||||
classpath 'com.google.cloud.tools:appengine-gradle-plugin:2.0.1'
|
||||
classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.6.1"
|
||||
classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.6.1'
|
||||
classpath 'org.sonatype.aether:aether-api:1.13.1'
|
||||
classpath 'org.sonatype.aether:aether-impl:1.13.1'
|
||||
}
|
||||
@@ -49,6 +49,7 @@ plugins {
|
||||
id 'com.diffplug.gradle.spotless' version '3.25.0'
|
||||
|
||||
id 'jacoco'
|
||||
id 'com.dorongold.task-tree' version '1.5'
|
||||
}
|
||||
|
||||
wrapper {
|
||||
@@ -443,6 +444,7 @@ task javaIncrementalFormatDryRun {
|
||||
println("${invokeJavaDiffFormatScript("show")}")
|
||||
}
|
||||
}
|
||||
tasks.build.dependsOn(tasks.javaIncrementalFormatCheck)
|
||||
|
||||
// Checks if modified lines in Java source files need reformatting.
|
||||
// Note that this task processes modified Java files in the entire repository.
|
||||
@@ -452,8 +454,6 @@ task javaIncrementalFormatApply {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.build.dependsOn(tasks.javaIncrementalFormatCheck)
|
||||
|
||||
task javadoc(type: Javadoc) {
|
||||
source javadocSource
|
||||
classpath = files(javadocClasspath)
|
||||
@@ -468,4 +468,16 @@ task javadoc(type: Javadoc) {
|
||||
|
||||
tasks.build.dependsOn(tasks.javadoc)
|
||||
|
||||
// Task for doing development on core Nomulus.
|
||||
// This fixes code formatting automatically as necessary, builds and tests the
|
||||
// core Nomulus codebase, and runs all presubmits.
|
||||
task coreDev {
|
||||
dependsOn 'javaIncrementalFormatApply'
|
||||
dependsOn 'javadoc'
|
||||
dependsOn 'checkDependenciesDotGradle'
|
||||
dependsOn 'checkLicense'
|
||||
dependsOn ':core:check'
|
||||
dependsOn 'assemble'
|
||||
}
|
||||
|
||||
javadocDependentTasks.each { tasks.javadoc.dependsOn(it) }
|
||||
|
||||
@@ -61,12 +61,12 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.11.1
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.json:json:20160212
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
org.junit.platform:junit-platform-commons:1.6.2
|
||||
org.junit.platform:junit-platform-engine:1.6.2
|
||||
org.junit.vintage:junit-vintage-engine:5.6.2
|
||||
org.junit:junit-bom:5.6.2
|
||||
org.mockito:mockito-core:3.3.3
|
||||
org.objenesis:objenesis:2.6
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -61,12 +61,12 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.11.1
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.json:json:20160212
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
org.junit.platform:junit-platform-commons:1.6.2
|
||||
org.junit.platform:junit-platform-engine:1.6.2
|
||||
org.junit.vintage:junit-vintage-engine:5.6.2
|
||||
org.junit:junit-bom:5.6.2
|
||||
org.mockito:mockito-core:3.3.3
|
||||
org.objenesis:objenesis:2.6
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -61,12 +61,12 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.11.1
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.json:json:20160212
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
org.junit.platform:junit-platform-commons:1.6.2
|
||||
org.junit.platform:junit-platform-engine:1.6.2
|
||||
org.junit.vintage:junit-vintage-engine:5.6.2
|
||||
org.junit:junit-bom:5.6.2
|
||||
org.mockito:mockito-core:3.3.3
|
||||
org.objenesis:objenesis:2.6
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -61,12 +61,12 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.11.1
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.json:json:20160212
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
org.junit.platform:junit-platform-commons:1.6.2
|
||||
org.junit.platform:junit-platform-engine:1.6.2
|
||||
org.junit.vintage:junit-vintage-engine:5.6.2
|
||||
org.junit:junit-bom:5.6.2
|
||||
org.mockito:mockito-core:3.3.3
|
||||
org.objenesis:objenesis:2.6
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -20,10 +20,10 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.11.1
|
||||
org.eclipse.jgit:org.eclipse.jgit:4.4.1.201607150455-r
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
org.junit.platform:junit-platform-commons:1.6.2
|
||||
org.junit.platform:junit-platform-engine:1.6.2
|
||||
org.junit.vintage:junit-vintage-engine:5.6.2
|
||||
org.junit:junit-bom:5.6.2
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -20,10 +20,10 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.11.1
|
||||
org.eclipse.jgit:org.eclipse.jgit:4.4.1.201607150455-r
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
org.junit.platform:junit-platform-commons:1.6.2
|
||||
org.junit.platform:junit-platform-engine:1.6.2
|
||||
org.junit.vintage:junit-vintage-engine:5.6.2
|
||||
org.junit:junit-bom:5.6.2
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -21,10 +21,10 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.11.1
|
||||
org.eclipse.jgit:org.eclipse.jgit:4.4.1.201607150455-r
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
org.junit.platform:junit-platform-commons:1.6.2
|
||||
org.junit.platform:junit-platform-engine:1.6.2
|
||||
org.junit.vintage:junit-vintage-engine:5.6.2
|
||||
org.junit:junit-bom:5.6.2
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -21,10 +21,10 @@ org.checkerframework:checker-compat-qual:2.5.5
|
||||
org.checkerframework:checker-qual:2.11.1
|
||||
org.eclipse.jgit:org.eclipse.jgit:4.4.1.201607150455-r
|
||||
org.hamcrest:hamcrest-core:1.3
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.1
|
||||
org.junit.platform:junit-platform-commons:1.6.1
|
||||
org.junit.platform:junit-platform-engine:1.6.1
|
||||
org.junit.vintage:junit-vintage-engine:5.6.1
|
||||
org.junit:junit-bom:5.6.1
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
org.junit.platform:junit-platform-commons:1.6.2
|
||||
org.junit.platform:junit-platform-engine:1.6.2
|
||||
org.junit.vintage:junit-vintage-engine:5.6.2
|
||||
org.junit:junit-bom:5.6.2
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
|
||||
@@ -77,9 +77,9 @@ PRESUBMITS = {
|
||||
PresubmitCheck(
|
||||
r".*Copyright 20\d{2} The Nomulus Authors\. All Rights Reserved\.",
|
||||
("java", "js", "soy", "sql", "py", "sh", "gradle"), {
|
||||
".git", "/build/", "/generated/", "node_modules/",
|
||||
"JUnitBackports.java", "registrar_bin.", "registrar_dbg.",
|
||||
"google-java-format-diff.py",
|
||||
".git", "/build/", "/generated/", "/generated_tests/",
|
||||
"node_modules/", "JUnitBackports.java", "registrar_bin.",
|
||||
"registrar_dbg.", "google-java-format-diff.py",
|
||||
"nomulus.golden.sql", "soyutils_usegoog.js"
|
||||
}, REQUIRED):
|
||||
"File did not include the license header.",
|
||||
|
||||
@@ -312,6 +312,7 @@ dependencies {
|
||||
testCompile deps['org.junit.jupiter:junit-jupiter-api']
|
||||
testCompile deps['org.junit.jupiter:junit-jupiter-engine']
|
||||
testCompile deps['org.junit.jupiter:junit-jupiter-migrationsupport']
|
||||
testCompile deps['org.junit.jupiter:junit-jupiter-params']
|
||||
testCompile deps['org.junit.platform:junit-platform-runner']
|
||||
testCompile deps['org.junit.platform:junit-platform-suite-api']
|
||||
testCompile deps['org.junit.vintage:junit-vintage-engine']
|
||||
|
||||
@@ -246,6 +246,7 @@ org.json:json:20160810
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-params:5.6.2
|
||||
org.junit.platform:junit-platform-commons:1.6.2
|
||||
org.junit.platform:junit-platform-engine:1.6.2
|
||||
org.junit.platform:junit-platform-launcher:1.6.2
|
||||
|
||||
@@ -244,6 +244,7 @@ org.json:json:20160810
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-params:5.6.2
|
||||
org.junit.platform:junit-platform-commons:1.6.2
|
||||
org.junit.platform:junit-platform-engine:1.6.2
|
||||
org.junit.platform:junit-platform-launcher:1.6.2
|
||||
|
||||
@@ -249,6 +249,7 @@ org.json:json:20160810
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-params:5.6.2
|
||||
org.junit.platform:junit-platform-commons:1.6.2
|
||||
org.junit.platform:junit-platform-engine:1.6.2
|
||||
org.junit.platform:junit-platform-launcher:1.6.2
|
||||
|
||||
@@ -249,6 +249,7 @@ org.json:json:20160810
|
||||
org.junit.jupiter:junit-jupiter-api:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-engine:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:5.6.2
|
||||
org.junit.jupiter:junit-jupiter-params:5.6.2
|
||||
org.junit.platform:junit-platform-commons:1.6.2
|
||||
org.junit.platform:junit-platform-engine:1.6.2
|
||||
org.junit.platform:junit-platform-launcher:1.6.2
|
||||
|
||||
@@ -23,7 +23,8 @@ import java.lang.reflect.Proxy;
|
||||
|
||||
/**
|
||||
* Sets up a placeholder {@link Environment} on a non-AppEngine platform so that Datastore Entities
|
||||
* can be deserialized. See {@code DatastoreEntityExtension} in test source for more information.
|
||||
* can be converted from/to Objectify entities. See {@code DatastoreEntityExtension} in test source
|
||||
* for more information.
|
||||
*/
|
||||
public class AppEngineEnvironment implements Closeable {
|
||||
|
||||
|
||||
@@ -19,31 +19,26 @@ import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import dagger.Binds;
|
||||
import dagger.Component;
|
||||
import dagger.Lazy;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.beam.initsql.BeamJpaModule.BindModule;
|
||||
import google.registry.config.CredentialModule;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.config.RegistryConfig.ConfigModule;
|
||||
import google.registry.keyring.kms.KmsModule;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
import google.registry.persistence.PersistenceModule.JdbcJpaTm;
|
||||
import google.registry.persistence.PersistenceModule.SocketFactoryJpaTm;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.Sleeper;
|
||||
import google.registry.util.SystemClock;
|
||||
import google.registry.util.SystemSleeper;
|
||||
import google.registry.util.UtilsModule;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import javax.inject.Named;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Singleton;
|
||||
import org.apache.beam.sdk.io.FileSystems;
|
||||
import org.apache.beam.sdk.io.fs.ResourceId;
|
||||
@@ -53,27 +48,31 @@ import org.apache.beam.sdk.io.fs.ResourceId;
|
||||
*
|
||||
* <p>This module is intended for use in BEAM pipelines, and uses a BEAM utility to access GCS like
|
||||
* a regular file system.
|
||||
*
|
||||
* <p>Note that {@link google.registry.config.RegistryConfig.ConfigModule} cannot be used here,
|
||||
* since many bindings, especially KMS-related ones, are different.
|
||||
*/
|
||||
@Module(includes = {BindModule.class})
|
||||
class BeamJpaModule {
|
||||
@Module
|
||||
public class BeamJpaModule {
|
||||
|
||||
private static final String GCS_SCHEME = "gs://";
|
||||
|
||||
private final String credentialFilePath;
|
||||
@Nullable private final String credentialFilePath;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link BeamJpaModule}.
|
||||
*
|
||||
* <p>Note: it is an unfortunately necessary antipattern to check for the validity of
|
||||
* credentialFilePath in {@link #provideCloudSqlAccessInfo} rather than in the constructor.
|
||||
* Unfortunately, this is a restriction imposed upon us by Dagger. Specifically, because we use
|
||||
* this in at least one 1 {@link google.registry.tools.RegistryTool} command(s), it must be
|
||||
* instantiated in {@code google.registry.tools.RegistryToolComponent} for all possible commands;
|
||||
* Dagger doesn't permit it to ever be null. For the vast majority of commands, it will never be
|
||||
* used (so a null credential file path is fine in those cases).
|
||||
*
|
||||
* @param credentialFilePath the path to a Cloud SQL credential file. This must refer to either a
|
||||
* real encrypted file on GCS as returned by {@link
|
||||
* BackupPaths#getCloudSQLCredentialFilePatterns} or an unencrypted file on local filesystem
|
||||
* with credentials to a test database.
|
||||
*/
|
||||
BeamJpaModule(String credentialFilePath) {
|
||||
checkArgument(!isNullOrEmpty(credentialFilePath), "Null or empty credentialFilePath");
|
||||
public BeamJpaModule(@Nullable String credentialFilePath) {
|
||||
this.credentialFilePath = credentialFilePath;
|
||||
}
|
||||
|
||||
@@ -85,6 +84,7 @@ class BeamJpaModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
SqlAccessInfo provideCloudSqlAccessInfo(Lazy<CloudSqlCredentialDecryptor> lazyDecryptor) {
|
||||
checkArgument(!isNullOrEmpty(credentialFilePath), "Null or empty credentialFilePath");
|
||||
String line = readOnlyLineFromCredentialFile();
|
||||
if (isCloudSqlCredential()) {
|
||||
line = lazyDecryptor.get().decrypt(line);
|
||||
@@ -114,13 +114,13 @@ class BeamJpaModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("cloudSqlJdbcUrl")
|
||||
@Config("beamCloudSqlJdbcUrl")
|
||||
String provideJdbcUrl(SqlAccessInfo sqlAccessInfo) {
|
||||
return sqlAccessInfo.jdbcUrl();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("cloudSqlInstanceConnectionName")
|
||||
@Config("beamCloudSqlInstanceConnectionName")
|
||||
String provideSqlInstanceName(SqlAccessInfo sqlAccessInfo) {
|
||||
return sqlAccessInfo
|
||||
.cloudSqlInstanceName()
|
||||
@@ -128,58 +128,45 @@ class BeamJpaModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("cloudSqlUsername")
|
||||
@Config("beamCloudSqlUsername")
|
||||
String provideSqlUsername(SqlAccessInfo sqlAccessInfo) {
|
||||
return sqlAccessInfo.user();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("cloudSqlPassword")
|
||||
@Config("beamCloudSqlPassword")
|
||||
String provideSqlPassword(SqlAccessInfo sqlAccessInfo) {
|
||||
return sqlAccessInfo.password();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("cloudKmsProjectId")
|
||||
@Config("beamCloudKmsProjectId")
|
||||
static String kmsProjectId() {
|
||||
return "domain-registry-dev";
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("cloudKmsKeyRing")
|
||||
@Config("beamCloudKmsKeyRing")
|
||||
static String keyRingName() {
|
||||
return "nomulus-tool-keyring";
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("defaultCredentialOauthScopes")
|
||||
static ImmutableList<String> defaultCredentialOauthScopes() {
|
||||
return ImmutableList.of("https://www.googleapis.com/auth/cloud-platform");
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("transientFailureRetries")
|
||||
static int transientFailureRetries() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
@Module
|
||||
interface BindModule {
|
||||
|
||||
@Binds
|
||||
Sleeper sleeper(SystemSleeper sleeper);
|
||||
|
||||
@Binds
|
||||
Clock clock(SystemClock clock);
|
||||
@Config("beamHibernateHikariMaximumPoolSize")
|
||||
static int getBeamHibernateHikariMaximumPoolSize() {
|
||||
// TODO(weiminyu): make this configurable. Should be equal to number of cores.
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Component(
|
||||
modules = {
|
||||
ConfigModule.class,
|
||||
CredentialModule.class,
|
||||
BeamJpaModule.class,
|
||||
KmsModule.class,
|
||||
PersistenceModule.class
|
||||
PersistenceModule.class,
|
||||
UtilsModule.class
|
||||
})
|
||||
public interface JpaTransactionManagerComponent {
|
||||
@SocketFactoryJpaTm
|
||||
|
||||
@@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.google.api.services.cloudkms.v1.model.DecryptRequest;
|
||||
import com.google.common.base.Strings;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.keyring.kms.KmsConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
@@ -34,7 +35,7 @@ public class CloudSqlCredentialDecryptor {
|
||||
private final KmsConnection kmsConnection;
|
||||
|
||||
@Inject
|
||||
CloudSqlCredentialDecryptor(KmsConnection kmsConnection) {
|
||||
CloudSqlCredentialDecryptor(@Config("beamKmsConnection") KmsConnection kmsConnection) {
|
||||
this.kmsConnection = kmsConnection;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,18 +16,40 @@ package google.registry.beam.initsql;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static google.registry.beam.initsql.BackupPaths.getCommitLogTimestamp;
|
||||
import static google.registry.beam.initsql.BackupPaths.getExportFilePatterns;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.setJpaTm;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
|
||||
import static java.util.Comparator.comparing;
|
||||
import static org.apache.beam.sdk.values.TypeDescriptors.integers;
|
||||
import static org.apache.beam.sdk.values.TypeDescriptors.kvs;
|
||||
import static org.apache.beam.sdk.values.TypeDescriptors.strings;
|
||||
|
||||
import avro.shaded.com.google.common.collect.Iterators;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Streams;
|
||||
import google.registry.backup.AppEngineEnvironment;
|
||||
import google.registry.backup.CommitLogImports;
|
||||
import google.registry.backup.VersionedEntity;
|
||||
import google.registry.model.ofy.ObjectifyService;
|
||||
import google.registry.model.ofy.Ofy;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.tools.LevelDbLogReader;
|
||||
import google.registry.util.SystemSleeper;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.function.Supplier;
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import org.apache.beam.sdk.coders.StringUtf8Coder;
|
||||
import org.apache.beam.sdk.io.Compression;
|
||||
import org.apache.beam.sdk.io.FileIO;
|
||||
@@ -36,12 +58,24 @@ import org.apache.beam.sdk.io.fs.EmptyMatchTreatment;
|
||||
import org.apache.beam.sdk.io.fs.MatchResult.Metadata;
|
||||
import org.apache.beam.sdk.transforms.Create;
|
||||
import org.apache.beam.sdk.transforms.DoFn;
|
||||
import org.apache.beam.sdk.transforms.Flatten;
|
||||
import org.apache.beam.sdk.transforms.GroupByKey;
|
||||
import org.apache.beam.sdk.transforms.GroupIntoBatches;
|
||||
import org.apache.beam.sdk.transforms.MapElements;
|
||||
import org.apache.beam.sdk.transforms.PTransform;
|
||||
import org.apache.beam.sdk.transforms.ParDo;
|
||||
import org.apache.beam.sdk.transforms.ProcessFunction;
|
||||
import org.apache.beam.sdk.values.KV;
|
||||
import org.apache.beam.sdk.values.PBegin;
|
||||
import org.apache.beam.sdk.values.PCollection;
|
||||
import org.apache.beam.sdk.values.PCollectionList;
|
||||
import org.apache.beam.sdk.values.PCollectionTuple;
|
||||
import org.apache.beam.sdk.values.PDone;
|
||||
import org.apache.beam.sdk.values.TupleTag;
|
||||
import org.apache.beam.sdk.values.TupleTagList;
|
||||
import org.apache.beam.sdk.values.TypeDescriptor;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
* {@link PTransform Pipeline transforms} used in pipelines that load from both Datastore export
|
||||
@@ -57,6 +91,110 @@ public final class Transforms {
|
||||
*/
|
||||
@VisibleForTesting static final long EXPORT_ENTITY_TIME_STAMP = START_OF_TIME.getMillis();
|
||||
|
||||
/**
|
||||
* Returns a {@link TupleTag} that can be used to retrieve entities of the given {@code kind} from
|
||||
* the Datastore snapshot returned by {@link #loadDatastoreSnapshot}.
|
||||
*/
|
||||
public static TupleTag<VersionedEntity> createTagForKind(String kind) {
|
||||
// When used with PCollectionTuple the result must retain generic type information.
|
||||
// Both the Generic param and the empty bracket below are important.
|
||||
return new TupleTag<VersionedEntity>(Transforms.class.getSimpleName() + ":" + kind) {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Composite {@link PTransform transform} that loads the Datastore snapshot at {@code
|
||||
* commitLogToTime} for caller specified {@code kinds}.
|
||||
*
|
||||
* <p>Caller must provide the location of a Datastore export that started AFTER {@code
|
||||
* commitLogFromTime} and completed BEFORE {@code commitLogToTime}, as well as the root directory
|
||||
* of all CommitLog files.
|
||||
*
|
||||
* <p>Selection of {@code commitLogFromTime} and {@code commitLogToTime} should follow the
|
||||
* guidelines below to ensure that all incremental changes concurrent with the export are covered:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Two or more CommitLogs should exist between {@code commitLogFromTime} and the starting
|
||||
* time of the Datastore export. This ensures that the earlier CommitLog file was complete
|
||||
* before the export started.
|
||||
* <li>Two or more CommitLogs should exit between the export completion time and {@code
|
||||
* commitLogToTime}.
|
||||
* </ul>
|
||||
*
|
||||
* <p>The output from the returned transform is a {@link PCollectionTuple} consisting of {@link
|
||||
* VersionedEntity VersionedEntities} grouped into {@link PCollection PCollections} by {@code
|
||||
* kind}.
|
||||
*/
|
||||
public static PTransform<PBegin, PCollectionTuple> loadDatastoreSnapshot(
|
||||
String exportDir,
|
||||
String commitLogDir,
|
||||
DateTime commitLogFromTime,
|
||||
DateTime commitLogToTime,
|
||||
Set<String> kinds) {
|
||||
checkArgument(kinds != null && !kinds.isEmpty(), "At least one kind is expected.");
|
||||
|
||||
// Create tags to collect entities by kind in final step.
|
||||
final ImmutableMap<String, TupleTag<VersionedEntity>> outputTags =
|
||||
kinds.stream()
|
||||
.collect(ImmutableMap.toImmutableMap(kind -> kind, Transforms::createTagForKind));
|
||||
// Arbitrarily select one tag as mainOutTag and put the remaining ones in a TupleTagList.
|
||||
// This separation is required by ParDo's config API.
|
||||
Iterator<TupleTag<VersionedEntity>> tagsIt = outputTags.values().iterator();
|
||||
final TupleTag<VersionedEntity> mainOutputTag = tagsIt.next();
|
||||
final TupleTagList additionalTags = TupleTagList.of(ImmutableList.copyOf(tagsIt));
|
||||
|
||||
return new PTransform<PBegin, PCollectionTuple>() {
|
||||
@Override
|
||||
public PCollectionTuple expand(PBegin input) {
|
||||
PCollection<VersionedEntity> exportedEntities =
|
||||
input
|
||||
.apply("Get export file patterns", getDatastoreExportFilePatterns(exportDir, kinds))
|
||||
.apply("Find export files", getFilesByPatterns())
|
||||
.apply("Load export data", loadExportDataFromFiles());
|
||||
PCollection<VersionedEntity> commitLogEntities =
|
||||
input
|
||||
.apply("Get commitlog file patterns", getCommitLogFilePatterns(commitLogDir))
|
||||
.apply("Find commitlog files", getFilesByPatterns())
|
||||
.apply(
|
||||
"Filter commitLog by time",
|
||||
filterCommitLogsByTime(commitLogFromTime, commitLogToTime))
|
||||
.apply("Load commitlog data", loadCommitLogsFromFiles(kinds));
|
||||
return PCollectionList.of(exportedEntities)
|
||||
.and(commitLogEntities)
|
||||
.apply("Merge exports and CommitLogs", Flatten.pCollections())
|
||||
.apply(
|
||||
"Key entities by Datastore Keys",
|
||||
// Converting to KV<String, VE> instead of KV<Key, VE> b/c default coder for Key
|
||||
// (SerializableCoder) is not deterministic and cannot be used with GroupBy.
|
||||
MapElements.into(kvs(strings(), TypeDescriptor.of(VersionedEntity.class)))
|
||||
.via((VersionedEntity e) -> KV.of(e.key().toString(), e)))
|
||||
.apply("Gather entities by key", GroupByKey.create())
|
||||
.apply(
|
||||
"Output latest version per entity",
|
||||
ParDo.of(
|
||||
new DoFn<KV<String, Iterable<VersionedEntity>>, VersionedEntity>() {
|
||||
@ProcessElement
|
||||
public void processElement(
|
||||
@Element KV<String, Iterable<VersionedEntity>> kv,
|
||||
MultiOutputReceiver out) {
|
||||
Optional<VersionedEntity> latest =
|
||||
Streams.stream(kv.getValue())
|
||||
.sorted(comparing(VersionedEntity::commitTimeMills).reversed())
|
||||
.findFirst();
|
||||
// Throw to abort (after default retries). Investigate, fix, and rerun.
|
||||
checkState(
|
||||
latest.isPresent(), "Unexpected key with no data", kv.getKey());
|
||||
if (latest.get().isDelete()) {
|
||||
return;
|
||||
}
|
||||
String kind = latest.get().getEntity().get().getKind();
|
||||
out.get(outputTags.get(kind)).output(latest.get());
|
||||
}
|
||||
})
|
||||
.withOutputTags(mainOutputTag, additionalTags));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link PTransform transform} that can generate a collection of patterns that match
|
||||
* all Datastore CommitLog files.
|
||||
@@ -96,7 +234,7 @@ public final class Transforms {
|
||||
* Returns CommitLog files with timestamps between {@code fromTime} (inclusive) and {@code
|
||||
* endTime} (exclusive).
|
||||
*/
|
||||
public static PTransform<PCollection<? extends String>, PCollection<String>>
|
||||
public static PTransform<PCollection<? extends Metadata>, PCollection<Metadata>>
|
||||
filterCommitLogsByTime(DateTime fromTime, DateTime toTime) {
|
||||
return ParDo.of(new FilterCommitLogFileByTime(fromTime, toTime));
|
||||
}
|
||||
@@ -114,11 +252,47 @@ public final class Transforms {
|
||||
|
||||
/** Returns a {@link PTransform} from file {@link Metadata} to {@link VersionedEntity}. */
|
||||
public static PTransform<PCollection<Metadata>, PCollection<VersionedEntity>>
|
||||
loadCommitLogsFromFiles() {
|
||||
loadCommitLogsFromFiles(Set<String> kinds) {
|
||||
return processFiles(
|
||||
new BackupFileReader(file -> CommitLogImports.loadEntities(file.open()).iterator()));
|
||||
new BackupFileReader(
|
||||
file ->
|
||||
CommitLogImports.loadEntities(file.open()).stream()
|
||||
.filter(e -> kinds.contains(e.key().getKind()))
|
||||
.iterator()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link PTransform} that writes a {@link PCollection} of entities to a SQL database.
|
||||
*
|
||||
* @param transformId a unique ID for an instance of the returned transform
|
||||
* @param maxWriters the max number of concurrent writes to SQL, which also determines the max
|
||||
* number of connection pools created
|
||||
* @param batchSize the number of entities to write in each operation
|
||||
* @param jpaSupplier supplier of a {@link JpaTransactionManager}
|
||||
*/
|
||||
public static PTransform<PCollection<VersionedEntity>, PDone> writeToSql(
|
||||
String transformId,
|
||||
int maxWriters,
|
||||
int batchSize,
|
||||
SerializableSupplier<JpaTransactionManager> jpaSupplier) {
|
||||
return new PTransform<PCollection<VersionedEntity>, PDone>() {
|
||||
@Override
|
||||
public PDone expand(PCollection<VersionedEntity> input) {
|
||||
input
|
||||
.apply(
|
||||
"Shard data for " + transformId,
|
||||
MapElements.into(kvs(integers(), TypeDescriptor.of(VersionedEntity.class)))
|
||||
.via(ve -> KV.of(ThreadLocalRandom.current().nextInt(maxWriters), ve)))
|
||||
.apply("Batch output by shard " + transformId, GroupIntoBatches.ofSize(batchSize))
|
||||
.apply("Write in batch for " + transformId, ParDo.of(new SqlBatchWriter(jpaSupplier)));
|
||||
return PDone.in(input.getPipeline());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Interface for serializable {@link Supplier suppliers}. */
|
||||
public interface SerializableSupplier<T> extends Supplier<T>, Serializable {}
|
||||
|
||||
/**
|
||||
* Returns a {@link PTransform} that produces a {@link PCollection} containing all elements in the
|
||||
* given {@link Iterable}.
|
||||
@@ -139,12 +313,11 @@ public final class Transforms {
|
||||
return input
|
||||
.apply(FileIO.readMatches().withCompression(Compression.UNCOMPRESSED))
|
||||
.apply(transformer.getClass().getSimpleName(), ParDo.of(transformer));
|
||||
// TODO(weiminyu): reshuffle to enable dynamic work rebalance per beam dev guide
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class FilterCommitLogFileByTime extends DoFn<String, String> {
|
||||
private static class FilterCommitLogFileByTime extends DoFn<Metadata, Metadata> {
|
||||
private final DateTime fromTime;
|
||||
private final DateTime toTime;
|
||||
|
||||
@@ -161,10 +334,10 @@ public final class Transforms {
|
||||
}
|
||||
|
||||
@ProcessElement
|
||||
public void processElement(@Element String fileName, OutputReceiver<String> out) {
|
||||
DateTime timestamp = getCommitLogTimestamp(fileName);
|
||||
public void processElement(@Element Metadata fileMeta, OutputReceiver<Metadata> out) {
|
||||
DateTime timestamp = getCommitLogTimestamp(fileMeta.resourceId().toString());
|
||||
if (isBeforeOrAt(fromTime, timestamp) && timestamp.isBefore(toTime)) {
|
||||
out.output(fileName);
|
||||
out.output(fileMeta);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,4 +370,104 @@ public final class Transforms {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a batch of entities to a SQL database.
|
||||
*
|
||||
* <p>Note that an arbitrary number of instances of this class may be created and freed in
|
||||
* arbitrary order in a single JVM. Due to the tech debt that forced us to use a static variable
|
||||
* to hold the {@code JpaTransactionManager} instance, we must ensure that JpaTransactionManager
|
||||
* is not changed or torn down while being used by some instance.
|
||||
*/
|
||||
private static class SqlBatchWriter extends DoFn<KV<Integer, Iterable<VersionedEntity>>, Void> {
|
||||
|
||||
private static int instanceCount = 0;
|
||||
private static JpaTransactionManager originalJpa;
|
||||
|
||||
private final SerializableSupplier<JpaTransactionManager> jpaSupplier;
|
||||
|
||||
private transient Ofy ofy;
|
||||
private transient SystemSleeper sleeper;
|
||||
|
||||
SqlBatchWriter(SerializableSupplier<JpaTransactionManager> jpaSupplier) {
|
||||
this.jpaSupplier = jpaSupplier;
|
||||
}
|
||||
|
||||
@Setup
|
||||
public void setup() {
|
||||
sleeper = new SystemSleeper();
|
||||
|
||||
ObjectifyService.initOfy();
|
||||
ofy = ObjectifyService.ofy();
|
||||
|
||||
synchronized (SqlBatchWriter.class) {
|
||||
if (instanceCount == 0) {
|
||||
originalJpa = jpaTm();
|
||||
setJpaTm(jpaSupplier);
|
||||
}
|
||||
instanceCount++;
|
||||
}
|
||||
}
|
||||
|
||||
@Teardown
|
||||
public void teardown() {
|
||||
synchronized (SqlBatchWriter.class) {
|
||||
instanceCount--;
|
||||
if (instanceCount == 0) {
|
||||
jpaTm().teardown();
|
||||
setJpaTm(() -> originalJpa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ProcessElement
|
||||
public void processElement(@Element KV<Integer, Iterable<VersionedEntity>> kv) {
|
||||
try (AppEngineEnvironment env = new AppEngineEnvironment()) {
|
||||
ImmutableList<Object> ofyEntities =
|
||||
Streams.stream(kv.getValue())
|
||||
.map(VersionedEntity::getEntity)
|
||||
.map(Optional::get)
|
||||
.map(ofy::toPojo)
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
retry(() -> jpaTm().transact(() -> jpaTm().saveNewOrUpdateAll(ofyEntities)));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/160632289): Enhance Retrier and use it here.
|
||||
private void retry(Runnable runnable) {
|
||||
int maxAttempts = 5;
|
||||
int initialDelayMillis = 100;
|
||||
double jitterRatio = 0.2;
|
||||
|
||||
for (int attempt = 0; attempt < maxAttempts; attempt++) {
|
||||
try {
|
||||
runnable.run();
|
||||
return;
|
||||
} catch (Throwable throwable) {
|
||||
throwIfNotCausedBy(throwable, OptimisticLockException.class);
|
||||
int sleepMillis = (1 << attempt) * initialDelayMillis;
|
||||
int jitter =
|
||||
ThreadLocalRandom.current().nextInt((int) (sleepMillis * jitterRatio))
|
||||
- (int) (sleepMillis * jitterRatio / 2);
|
||||
sleeper.sleepUninterruptibly(Duration.millis(sleepMillis + jitter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rethrows {@code throwable} if it is not (and does not have a cause of) {@code causeType};
|
||||
* otherwise returns with no side effects.
|
||||
*/
|
||||
private void throwIfNotCausedBy(Throwable throwable, Class<? extends Throwable> causeType) {
|
||||
Throwable t = throwable;
|
||||
while (t != null) {
|
||||
if (causeType.isInstance(t)) {
|
||||
return;
|
||||
}
|
||||
t = t.getCause();
|
||||
}
|
||||
Throwables.throwIfUnchecked(t);
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,6 +235,7 @@ public abstract class BillingEvent implements Serializable {
|
||||
DATE_TIME_FORMATTER.format(eventTime()),
|
||||
registrarId(),
|
||||
billingId(),
|
||||
poNumber(),
|
||||
tld(),
|
||||
action(),
|
||||
domain(),
|
||||
|
||||
@@ -141,7 +141,7 @@ public class SafeBrowsingTransforms {
|
||||
@ProcessElement
|
||||
public void processElement(ProcessContext context) {
|
||||
Subdomain subdomain = context.element();
|
||||
subdomainBuffer.put(subdomain.fullyQualifiedDomainName(), subdomain);
|
||||
subdomainBuffer.put(subdomain.domainName(), subdomain);
|
||||
if (subdomainBuffer.size() >= BATCH_SIZE) {
|
||||
ImmutableSet<KV<Subdomain, ThreatMatch>> results = evaluateAndFlush();
|
||||
results.forEach(context::output);
|
||||
@@ -239,7 +239,7 @@ public class SafeBrowsingTransforms {
|
||||
String url = match.getJSONObject("threat").getString("url");
|
||||
Subdomain subdomain = subdomainBuffer.get(url);
|
||||
resultBuilder.add(
|
||||
KV.of(subdomain, ThreatMatch.create(match, subdomain.fullyQualifiedDomainName())));
|
||||
KV.of(subdomain, ThreatMatch.create(match, subdomain.domainName())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public class Spec11Pipeline implements Serializable {
|
||||
public static final String REGISTRAR_EMAIL_FIELD = "registrarEmailAddress";
|
||||
/** The JSON object field into which we put the registrar's name for Spec11 reports. */
|
||||
public static final String REGISTRAR_CLIENT_ID_FIELD = "registrarClientId";
|
||||
/** The JSON object field we put the threat match array for Spec11 reports. */
|
||||
/** The JSON object field into which we put the threat match array for Spec11 reports. */
|
||||
public static final String THREAT_MATCHES_FIELD = "threatMatches";
|
||||
|
||||
private final String projectId;
|
||||
@@ -94,8 +94,7 @@ public class Spec11Pipeline implements Serializable {
|
||||
@Config("spec11TemplateUrl") String spec11TemplateUrl,
|
||||
@Config("reportingBucketUrl") String reportingBucketUrl,
|
||||
@LocalCredential GoogleCredentialsBundle googleCredentialsBundle,
|
||||
Retrier retrier
|
||||
) {
|
||||
Retrier retrier) {
|
||||
this.projectId = projectId;
|
||||
this.beamStagingUrl = beamStagingUrl;
|
||||
this.spec11TemplateUrl = spec11TemplateUrl;
|
||||
@@ -177,9 +176,11 @@ public class Spec11Pipeline implements Serializable {
|
||||
PCollection<Subdomain> domains,
|
||||
EvaluateSafeBrowsingFn evaluateSafeBrowsingFn,
|
||||
ValueProvider<String> dateProvider) {
|
||||
PCollection<KV<Subdomain, ThreatMatch>> subdomains =
|
||||
|
||||
/* Store ThreatMatch objects in JSON. */
|
||||
PCollection<KV<Subdomain, ThreatMatch>> subdomainsJson =
|
||||
domains.apply("Run through SafeBrowsingAPI", ParDo.of(evaluateSafeBrowsingFn));
|
||||
subdomains
|
||||
subdomainsJson
|
||||
.apply(
|
||||
"Map registrar client ID to email/ThreatMatch pair",
|
||||
MapElements.into(
|
||||
@@ -188,7 +189,7 @@ public class Spec11Pipeline implements Serializable {
|
||||
.via(
|
||||
(KV<Subdomain, ThreatMatch> kv) ->
|
||||
KV.of(
|
||||
kv.getKey().registrarClientId(),
|
||||
kv.getKey().registrarId(),
|
||||
EmailAndThreatMatch.create(
|
||||
kv.getKey().registrarEmailAddress(), kv.getValue()))))
|
||||
.apply("Group by registrar client ID", GroupByKey.create())
|
||||
|
||||
@@ -36,12 +36,14 @@ import org.apache.beam.sdk.io.gcp.bigquery.SchemaAndRecord;
|
||||
public abstract class Subdomain implements Serializable {
|
||||
|
||||
private static final ImmutableList<String> FIELD_NAMES =
|
||||
ImmutableList.of("fullyQualifiedDomainName", "registrarClientId", "registrarEmailAddress");
|
||||
ImmutableList.of("domainName", "domainRepoId", "registrarId", "registrarEmailAddress");
|
||||
|
||||
/** Returns the fully qualified domain name. */
|
||||
abstract String fullyQualifiedDomainName();
|
||||
/** Returns the client ID of the associated registrar for this domain. */
|
||||
abstract String registrarClientId();
|
||||
abstract String domainName();
|
||||
/** Returns the domain repo ID (the primary key of the domain table). */
|
||||
abstract String domainRepoId();
|
||||
/** Returns the registrar ID of the associated registrar for this domain. */
|
||||
abstract String registrarId();
|
||||
/** Returns the email address of the registrar associated with this domain. */
|
||||
abstract String registrarEmailAddress();
|
||||
|
||||
@@ -56,8 +58,9 @@ public abstract class Subdomain implements Serializable {
|
||||
checkFieldsNotNull(FIELD_NAMES, schemaAndRecord);
|
||||
GenericRecord record = schemaAndRecord.getRecord();
|
||||
return create(
|
||||
extractField(record, "fullyQualifiedDomainName"),
|
||||
extractField(record, "registrarClientId"),
|
||||
extractField(record, "domainName"),
|
||||
extractField(record, "domainRepoId"),
|
||||
extractField(record, "registrarId"),
|
||||
extractField(record, "registrarEmailAddress"));
|
||||
}
|
||||
|
||||
@@ -69,9 +72,11 @@ public abstract class Subdomain implements Serializable {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static Subdomain create(
|
||||
String fullyQualifiedDomainName, String registrarClientId, String registrarEmailAddress) {
|
||||
String domainName,
|
||||
String domainRepoId,
|
||||
String registrarId,
|
||||
String registrarEmailAddress) {
|
||||
return new AutoValue_Subdomain(
|
||||
fullyQualifiedDomainName, registrarClientId, registrarEmailAddress);
|
||||
domainName, domainRepoId, registrarId, registrarEmailAddress);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,11 +19,13 @@
|
||||
-- email address.
|
||||
|
||||
SELECT
|
||||
domain.fullyQualifiedDomainName AS fullyQualifiedDomainName,
|
||||
registrar.clientId AS registrarClientId,
|
||||
domain.fullyQualifiedDomainName AS domainName,
|
||||
domain.__key__.name AS domainRepoId,
|
||||
registrar.clientId AS clientId,
|
||||
COALESCE(registrar.emailAddress, '') AS registrarEmailAddress
|
||||
FROM ( (
|
||||
SELECT
|
||||
__key__,
|
||||
fullyQualifiedDomainName,
|
||||
currentSponsorClientId,
|
||||
creationTime
|
||||
|
||||
@@ -367,6 +367,12 @@
|
||||
<url-pattern>/_dr/task/linkRdeHosts</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Action to automatically re-lock a domain after unlocking it -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>backend-servlet</servlet-name>
|
||||
<url-pattern>/_dr/task/relockDomain</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Security config -->
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
<sessions-enabled>true</sessions-enabled>
|
||||
<instance-class>B4_1G</instance-class>
|
||||
<manual-scaling>
|
||||
<instances>10</instances>
|
||||
<instances>20</instances>
|
||||
</manual-scaling>
|
||||
|
||||
<system-properties>
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
|
||||
package google.registry.flows.poll;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
|
||||
import static google.registry.flows.poll.PollFlowUtils.ackPollMessage;
|
||||
import static google.registry.flows.poll.PollFlowUtils.getPollMessagesQuery;
|
||||
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_NO_MESSAGES;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
@@ -100,27 +100,8 @@ public class PollAckFlow implements TransactionalFlow {
|
||||
// This keeps track of whether we should include the current acked message in the updated
|
||||
// message count that's returned to the user. The only case where we do so is if an autorenew
|
||||
// poll message is acked, but its next event is already ready to be delivered.
|
||||
boolean includeAckedMessageInCount = false;
|
||||
if (pollMessage instanceof PollMessage.OneTime) {
|
||||
// One-time poll messages are deleted once acked.
|
||||
ofy().delete().entity(pollMessage);
|
||||
} else {
|
||||
checkState(pollMessage instanceof PollMessage.Autorenew, "Unknown poll message type");
|
||||
PollMessage.Autorenew autorenewPollMessage = (PollMessage.Autorenew) pollMessage;
|
||||
boolean includeAckedMessageInCount = ackPollMessage(pollMessage);
|
||||
|
||||
// Move the eventTime of this autorenew poll message forward by a year.
|
||||
DateTime nextEventTime = autorenewPollMessage.getEventTime().plusYears(1);
|
||||
|
||||
// If the next event falls within the bounds of the end time, then just update the eventTime
|
||||
// and re-save it for future autorenew poll messages to be delivered. Otherwise, this
|
||||
// autorenew poll message has no more events to deliver and should be deleted.
|
||||
if (nextEventTime.isBefore(autorenewPollMessage.getAutorenewEndTime())) {
|
||||
ofy().save().entity(autorenewPollMessage.asBuilder().setEventTime(nextEventTime).build());
|
||||
includeAckedMessageInCount = isBeforeOrAt(nextEventTime, now);
|
||||
} else {
|
||||
ofy().delete().entity(autorenewPollMessage);
|
||||
}
|
||||
}
|
||||
// We need to return the new queue length. If this was the last message in the queue being
|
||||
// acked, then we return a special status code indicating that. Note that the query will
|
||||
// include the message being acked.
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
|
||||
package google.registry.flows.poll;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
|
||||
|
||||
import com.googlecode.objectify.cmd.Query;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
@@ -33,4 +36,42 @@ public final class PollFlowUtils {
|
||||
.filter("eventTime <=", now.toDate())
|
||||
.order("eventTime");
|
||||
}
|
||||
|
||||
/**
|
||||
* Acknowledges the given {@link PollMessage} and returns whether we should include the current
|
||||
* acked message in the updated message count that's returned to the user.
|
||||
*
|
||||
* <p>The only case where we do so is if an autorenew poll message is acked, but its next event is
|
||||
* already ready to be delivered.
|
||||
*/
|
||||
public static boolean ackPollMessage(PollMessage pollMessage) {
|
||||
checkArgument(
|
||||
isBeforeOrAt(pollMessage.getEventTime(), tm().getTransactionTime()),
|
||||
"Cannot ACK poll message with ID %s because its event time is in the future: %s",
|
||||
pollMessage.getId(),
|
||||
pollMessage.getEventTime());
|
||||
boolean includeAckedMessageInCount = false;
|
||||
if (pollMessage instanceof PollMessage.OneTime) {
|
||||
// One-time poll messages are deleted once acked.
|
||||
tm().delete(pollMessage.createVKey());
|
||||
} else if (pollMessage instanceof PollMessage.Autorenew) {
|
||||
PollMessage.Autorenew autorenewPollMessage = (PollMessage.Autorenew) pollMessage;
|
||||
|
||||
// Move the eventTime of this autorenew poll message forward by a year.
|
||||
DateTime nextEventTime = autorenewPollMessage.getEventTime().plusYears(1);
|
||||
|
||||
// If the next event falls within the bounds of the end time, then just update the eventTime
|
||||
// and re-save it for future autorenew poll messages to be delivered. Otherwise, this
|
||||
// autorenew poll message has no more events to deliver and should be deleted.
|
||||
if (nextEventTime.isBefore(autorenewPollMessage.getAutorenewEndTime())) {
|
||||
tm().saveNewOrUpdate(autorenewPollMessage.asBuilder().setEventTime(nextEventTime).build());
|
||||
includeAckedMessageInCount = isBeforeOrAt(nextEventTime, tm().getTransactionTime());
|
||||
} else {
|
||||
tm().delete(autorenewPollMessage.createVKey());
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown poll message type: " + pollMessage.getClass());
|
||||
}
|
||||
return includeAckedMessageInCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,9 @@ import com.google.api.services.cloudkms.v1.model.DecryptRequest;
|
||||
import com.google.api.services.cloudkms.v1.model.EncryptRequest;
|
||||
import com.google.api.services.cloudkms.v1.model.KeyRing;
|
||||
import com.google.api.services.cloudkms.v1.model.UpdateCryptoKeyPrimaryVersionRequest;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.keyring.api.KeyringException;
|
||||
import google.registry.util.Retrier;
|
||||
import java.io.IOException;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/** The {@link KmsConnection} which talks to Cloud KMS. */
|
||||
class KmsConnectionImpl implements KmsConnection {
|
||||
@@ -44,12 +42,7 @@ class KmsConnectionImpl implements KmsConnection {
|
||||
private final String projectId;
|
||||
private final Retrier retrier;
|
||||
|
||||
@Inject
|
||||
KmsConnectionImpl(
|
||||
@Config("cloudKmsProjectId") String projectId,
|
||||
@Config("cloudKmsKeyRing") String kmsKeyRingName,
|
||||
Retrier retrier,
|
||||
CloudKMS kms) {
|
||||
KmsConnectionImpl(String projectId, String kmsKeyRingName, Retrier retrier, CloudKMS kms) {
|
||||
this.projectId = projectId;
|
||||
this.kmsKeyRingName = kmsKeyRingName;
|
||||
this.retrier = retrier;
|
||||
|
||||
@@ -21,6 +21,7 @@ import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.keyring.api.KeySerializer;
|
||||
import google.registry.keyring.api.Keyring;
|
||||
import google.registry.keyring.api.KeyringException;
|
||||
@@ -86,7 +87,7 @@ public class KmsKeyring implements Keyring {
|
||||
private final KmsConnection kmsConnection;
|
||||
|
||||
@Inject
|
||||
KmsKeyring(KmsConnection kmsConnection) {
|
||||
KmsKeyring(@Config("defaultKmsConnection") KmsConnection kmsConnection) {
|
||||
this.kmsConnection = kmsConnection;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import google.registry.config.CredentialModule.DefaultCredential;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.keyring.api.Keyring;
|
||||
import google.registry.util.GoogleCredentialsBundle;
|
||||
import google.registry.util.Retrier;
|
||||
|
||||
/** Dagger module for Cloud KMS. */
|
||||
@Module
|
||||
@@ -32,9 +33,22 @@ public abstract class KmsModule {
|
||||
public static final String NAME = "KMS";
|
||||
|
||||
@Provides
|
||||
@Config("defaultKms")
|
||||
static CloudKMS provideKms(
|
||||
@DefaultCredential GoogleCredentialsBundle credentialsBundle,
|
||||
@Config("cloudKmsProjectId") String projectId) {
|
||||
return createKms(credentialsBundle, projectId);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("beamKms")
|
||||
static CloudKMS provideBeamKms(
|
||||
@DefaultCredential GoogleCredentialsBundle credentialsBundle,
|
||||
@Config("beamCloudKmsProjectId") String projectId) {
|
||||
return createKms(credentialsBundle, projectId);
|
||||
}
|
||||
|
||||
private static CloudKMS createKms(GoogleCredentialsBundle credentialsBundle, String projectId) {
|
||||
return new CloudKMS.Builder(
|
||||
credentialsBundle.getHttpTransport(),
|
||||
credentialsBundle.getJsonFactory(),
|
||||
@@ -43,11 +57,28 @@ public abstract class KmsModule {
|
||||
.build();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("defaultKmsConnection")
|
||||
static KmsConnection provideKmsConnection(
|
||||
@Config("cloudKmsProjectId") String projectId,
|
||||
@Config("cloudKmsKeyRing") String keyringName,
|
||||
Retrier retrier,
|
||||
@Config("defaultKms") CloudKMS defaultKms) {
|
||||
return new KmsConnectionImpl(projectId, keyringName, retrier, defaultKms);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("beamKmsConnection")
|
||||
static KmsConnection provideBeamKmsConnection(
|
||||
@Config("beamCloudKmsProjectId") String projectId,
|
||||
@Config("beamCloudKmsKeyRing") String keyringName,
|
||||
Retrier retrier,
|
||||
@Config("beamKms") CloudKMS defaultKms) {
|
||||
return new KmsConnectionImpl(projectId, keyringName, retrier, defaultKms);
|
||||
}
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@StringKey(NAME)
|
||||
abstract Keyring provideKeyring(KmsKeyring keyring);
|
||||
|
||||
@Binds
|
||||
abstract KmsConnection provideKmsConnection(KmsConnectionImpl kmsConnectionImpl);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.keyring.api.KeySerializer;
|
||||
import google.registry.keyring.kms.KmsKeyring.PrivateKeyLabel;
|
||||
import google.registry.keyring.kms.KmsKeyring.PublicKeyLabel;
|
||||
@@ -64,7 +65,7 @@ public final class KmsUpdater {
|
||||
private final HashMap<String, byte[]> secretValues;
|
||||
|
||||
@Inject
|
||||
public KmsUpdater(KmsConnection kmsConnection) {
|
||||
public KmsUpdater(@Config("defaultKmsConnection") KmsConnection kmsConnection) {
|
||||
this.kmsConnection = kmsConnection;
|
||||
|
||||
// Use LinkedHashMap to preserve insertion order on update() to simplify testing and debugging
|
||||
|
||||
@@ -0,0 +1,398 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.contact;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.model.EppResourceUtils.projectResourceOntoBuilderAtTime;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.IgnoreSave;
|
||||
import com.googlecode.objectify.annotation.Index;
|
||||
import com.googlecode.objectify.condition.IfNull;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.EppResource.ResourceWithTransferData;
|
||||
import google.registry.model.transfer.ContactTransferData;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.AttributeOverride;
|
||||
import javax.persistence.AttributeOverrides;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* A persistable contact resource including mutable and non-mutable fields.
|
||||
*
|
||||
* @see <a href="https://tools.ietf.org/html/rfc5733">RFC 5733</a>
|
||||
* <p>This class deliberately does not include an {@link javax.persistence.Id} so that any
|
||||
* foreign-keyed fields can refer to the proper parent entity's ID, whether we're storing this
|
||||
* in the DB itself or as part of another entity
|
||||
*/
|
||||
@MappedSuperclass
|
||||
@Embeddable
|
||||
@Access(AccessType.FIELD)
|
||||
public class ContactBase extends EppResource implements ResourceWithTransferData {
|
||||
|
||||
/**
|
||||
* Unique identifier for this contact.
|
||||
*
|
||||
* <p>This is only unique in the sense that for any given lifetime specified as the time range
|
||||
* from (creationTime, deletionTime) there can only be one contact in Datastore with this id.
|
||||
* However, there can be many contacts with the same id and non-overlapping lifetimes.
|
||||
*/
|
||||
String contactId;
|
||||
|
||||
/**
|
||||
* Localized postal info for the contact. All contained values must be representable in the 7-bit
|
||||
* US-ASCII character set. Personal info; cleared by {@link ContactResource.Builder#wipeOut}.
|
||||
*/
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "name", column = @Column(name = "addr_local_name")),
|
||||
@AttributeOverride(name = "org", column = @Column(name = "addr_local_org")),
|
||||
@AttributeOverride(name = "type", column = @Column(name = "addr_local_type")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine1",
|
||||
column = @Column(name = "addr_local_street_line1")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine2",
|
||||
column = @Column(name = "addr_local_street_line2")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine3",
|
||||
column = @Column(name = "addr_local_street_line3")),
|
||||
@AttributeOverride(name = "address.city", column = @Column(name = "addr_local_city")),
|
||||
@AttributeOverride(name = "address.state", column = @Column(name = "addr_local_state")),
|
||||
@AttributeOverride(name = "address.zip", column = @Column(name = "addr_local_zip")),
|
||||
@AttributeOverride(
|
||||
name = "address.countryCode",
|
||||
column = @Column(name = "addr_local_country_code"))
|
||||
})
|
||||
PostalInfo localizedPostalInfo;
|
||||
|
||||
/**
|
||||
* Internationalized postal info for the contact. Personal info; cleared by {@link
|
||||
* ContactResource.Builder#wipeOut}.
|
||||
*/
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "name", column = @Column(name = "addr_i18n_name")),
|
||||
@AttributeOverride(name = "org", column = @Column(name = "addr_i18n_org")),
|
||||
@AttributeOverride(name = "type", column = @Column(name = "addr_i18n_type")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine1",
|
||||
column = @Column(name = "addr_i18n_street_line1")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine2",
|
||||
column = @Column(name = "addr_i18n_street_line2")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine3",
|
||||
column = @Column(name = "addr_i18n_street_line3")),
|
||||
@AttributeOverride(name = "address.city", column = @Column(name = "addr_i18n_city")),
|
||||
@AttributeOverride(name = "address.state", column = @Column(name = "addr_i18n_state")),
|
||||
@AttributeOverride(name = "address.zip", column = @Column(name = "addr_i18n_zip")),
|
||||
@AttributeOverride(
|
||||
name = "address.countryCode",
|
||||
column = @Column(name = "addr_i18n_country_code"))
|
||||
})
|
||||
PostalInfo internationalizedPostalInfo;
|
||||
|
||||
/**
|
||||
* Contact name used for name searches. This is set automatically to be the internationalized
|
||||
* postal name, or if null, the localized postal name, or if that is null as well, null. Personal
|
||||
* info; cleared by {@link ContactResource.Builder#wipeOut}.
|
||||
*/
|
||||
@Index String searchName;
|
||||
|
||||
/** Contact’s voice number. Personal info; cleared by {@link ContactResource.Builder#wipeOut}. */
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "phoneNumber", column = @Column(name = "voice_phone_number")),
|
||||
@AttributeOverride(name = "extension", column = @Column(name = "voice_phone_extension")),
|
||||
})
|
||||
ContactPhoneNumber voice;
|
||||
|
||||
/** Contact’s fax number. Personal info; cleared by {@link ContactResource.Builder#wipeOut}. */
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "phoneNumber", column = @Column(name = "fax_phone_number")),
|
||||
@AttributeOverride(name = "extension", column = @Column(name = "fax_phone_extension")),
|
||||
})
|
||||
ContactPhoneNumber fax;
|
||||
|
||||
/** Contact’s email address. Personal info; cleared by {@link ContactResource.Builder#wipeOut}. */
|
||||
@IgnoreSave(IfNull.class)
|
||||
String email;
|
||||
|
||||
/** Authorization info (aka transfer secret) of the contact. */
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "pw.value", column = @Column(name = "auth_info_value")),
|
||||
@AttributeOverride(name = "pw.repoId", column = @Column(name = "auth_info_repo_id")),
|
||||
})
|
||||
ContactAuthInfo authInfo;
|
||||
|
||||
/** Data about any pending or past transfers on this contact. */
|
||||
ContactTransferData transferData;
|
||||
|
||||
/**
|
||||
* The time that this resource was last transferred.
|
||||
*
|
||||
* <p>Can be null if the resource has never been transferred.
|
||||
*/
|
||||
DateTime lastTransferTime;
|
||||
|
||||
// If any new fields are added which contain personal information, make sure they are cleared by
|
||||
// the wipeOut() function, so that data is not kept around for deleted contacts.
|
||||
|
||||
/** Disclosure policy. */
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "name", column = @Column(name = "disclose_types_name")),
|
||||
@AttributeOverride(name = "org", column = @Column(name = "disclose_types_org")),
|
||||
@AttributeOverride(name = "addr", column = @Column(name = "disclose_types_addr")),
|
||||
@AttributeOverride(name = "flag", column = @Column(name = "disclose_mode_flag")),
|
||||
@AttributeOverride(name = "voice.marked", column = @Column(name = "disclose_show_voice")),
|
||||
@AttributeOverride(name = "fax.marked", column = @Column(name = "disclose_show_fax")),
|
||||
@AttributeOverride(name = "email.marked", column = @Column(name = "disclose_show_email"))
|
||||
})
|
||||
Disclose disclose;
|
||||
|
||||
@Override
|
||||
public VKey<? extends ContactBase> createVKey() {
|
||||
// TODO(mmuller): create symmetric keys if we can ever reload both sides.
|
||||
return VKey.create(ContactBase.class, getRepoId(), Key.create(this));
|
||||
}
|
||||
|
||||
public String getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public PostalInfo getLocalizedPostalInfo() {
|
||||
return localizedPostalInfo;
|
||||
}
|
||||
|
||||
public PostalInfo getInternationalizedPostalInfo() {
|
||||
return internationalizedPostalInfo;
|
||||
}
|
||||
|
||||
public String getSearchName() {
|
||||
return searchName;
|
||||
}
|
||||
|
||||
public ContactPhoneNumber getVoiceNumber() {
|
||||
return voice;
|
||||
}
|
||||
|
||||
public ContactPhoneNumber getFaxNumber() {
|
||||
return fax;
|
||||
}
|
||||
|
||||
public String getEmailAddress() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public ContactAuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
|
||||
public Disclose getDisclose() {
|
||||
return disclose;
|
||||
}
|
||||
|
||||
public final String getCurrentSponsorClientId() {
|
||||
return getPersistedCurrentSponsorClientId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ContactTransferData getTransferData() {
|
||||
return Optional.ofNullable(transferData).orElse(ContactTransferData.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime getLastTransferTime() {
|
||||
return lastTransferTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getForeignKey() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Postal info for the contact.
|
||||
*
|
||||
* <p>The XML marshalling expects the {@link PostalInfo} objects in a list, but we can't actually
|
||||
* persist them to Datastore that way because Objectify can't handle collections of embedded
|
||||
* objects that themselves contain collections, and there's a list of streets inside. This method
|
||||
* transforms the persisted format to the XML format for marshalling.
|
||||
*/
|
||||
@XmlElement(name = "postalInfo")
|
||||
public ImmutableList<PostalInfo> getPostalInfosAsList() {
|
||||
return Stream.of(localizedPostalInfo, internationalizedPostalInfo)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactBase cloneProjectedAtTime(DateTime now) {
|
||||
return cloneContactProjectedAtTime(this, now);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the contact (or subclass). A separate static method so that we can pass in and return a
|
||||
* T without the compiler complaining.
|
||||
*/
|
||||
protected static <T extends ContactBase> T cloneContactProjectedAtTime(T contact, DateTime now) {
|
||||
Builder builder = contact.asBuilder();
|
||||
projectResourceOntoBuilderAtTime(contact, builder, now);
|
||||
return (T) builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder asBuilder() {
|
||||
return new Builder<>(clone(this));
|
||||
}
|
||||
|
||||
/** A builder for constructing {@link ContactResource}, since it is immutable. */
|
||||
public static class Builder<T extends ContactBase, B extends Builder<T, B>>
|
||||
extends EppResource.Builder<T, B> implements BuilderWithTransferData<ContactTransferData, B> {
|
||||
|
||||
public Builder() {}
|
||||
|
||||
protected Builder(T instance) {
|
||||
super(instance);
|
||||
}
|
||||
|
||||
public B setContactId(String contactId) {
|
||||
getInstance().contactId = contactId;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
public B setLocalizedPostalInfo(PostalInfo localizedPostalInfo) {
|
||||
checkArgument(
|
||||
localizedPostalInfo == null
|
||||
|| PostalInfo.Type.LOCALIZED.equals(localizedPostalInfo.getType()));
|
||||
getInstance().localizedPostalInfo = localizedPostalInfo;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
public B setInternationalizedPostalInfo(PostalInfo internationalizedPostalInfo) {
|
||||
checkArgument(
|
||||
internationalizedPostalInfo == null
|
||||
|| PostalInfo.Type.INTERNATIONALIZED.equals(internationalizedPostalInfo.getType()));
|
||||
getInstance().internationalizedPostalInfo = internationalizedPostalInfo;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
public B overlayLocalizedPostalInfo(PostalInfo localizedPostalInfo) {
|
||||
return setLocalizedPostalInfo(
|
||||
getInstance().localizedPostalInfo == null
|
||||
? localizedPostalInfo
|
||||
: getInstance().localizedPostalInfo.overlay(localizedPostalInfo));
|
||||
}
|
||||
|
||||
public B overlayInternationalizedPostalInfo(PostalInfo internationalizedPostalInfo) {
|
||||
return setInternationalizedPostalInfo(
|
||||
getInstance().internationalizedPostalInfo == null
|
||||
? internationalizedPostalInfo
|
||||
: getInstance().internationalizedPostalInfo.overlay(internationalizedPostalInfo));
|
||||
}
|
||||
|
||||
public B setVoiceNumber(ContactPhoneNumber voiceNumber) {
|
||||
getInstance().voice = voiceNumber;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
public B setFaxNumber(ContactPhoneNumber faxNumber) {
|
||||
getInstance().fax = faxNumber;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
public B setEmailAddress(String emailAddress) {
|
||||
getInstance().email = emailAddress;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
public B setAuthInfo(ContactAuthInfo authInfo) {
|
||||
getInstance().authInfo = authInfo;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
public B setDisclose(Disclose disclose) {
|
||||
getInstance().disclose = disclose;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
@Override
|
||||
public B setTransferData(ContactTransferData transferData) {
|
||||
getInstance().transferData = transferData;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
@Override
|
||||
public B setLastTransferTime(DateTime lastTransferTime) {
|
||||
getInstance().lastTransferTime = lastTransferTime;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all personally identifying information about a contact.
|
||||
*
|
||||
* <p>This should be used when deleting a contact so that the soft-deleted entity doesn't
|
||||
* contain information that the registrant requested to be deleted.
|
||||
*/
|
||||
public B wipeOut() {
|
||||
setEmailAddress(null);
|
||||
setFaxNumber(null);
|
||||
setInternationalizedPostalInfo(null);
|
||||
setLocalizedPostalInfo(null);
|
||||
setVoiceNumber(null);
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T build() {
|
||||
T instance = getInstance();
|
||||
// If TransferData is totally empty, set it to null.
|
||||
if (ContactTransferData.EMPTY.equals(instance.transferData)) {
|
||||
setTransferData(null);
|
||||
}
|
||||
// Set the searchName using the internationalized and localized postal info names.
|
||||
if ((instance.internationalizedPostalInfo != null)
|
||||
&& (instance.internationalizedPostalInfo.getName() != null)) {
|
||||
instance.searchName = instance.internationalizedPostalInfo.getName();
|
||||
} else if ((instance.localizedPostalInfo != null)
|
||||
&& (instance.localizedPostalInfo.getName() != null)) {
|
||||
instance.searchName = instance.localizedPostalInfo.getName();
|
||||
} else {
|
||||
instance.searchName = null;
|
||||
}
|
||||
return super.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.contact;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.persistence.VKey;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
|
||||
/**
|
||||
* A persisted history entry representing an EPP modification to a contact.
|
||||
*
|
||||
* <p>In addition to the general history fields (e.g. action time, registrar ID) we also persist a
|
||||
* copy of the host entity at this point in time. We persist a raw {@link ContactBase} so that the
|
||||
* foreign-keyed fields in that class can refer to this object.
|
||||
*/
|
||||
@Entity
|
||||
@javax.persistence.Table(
|
||||
indexes = {
|
||||
@javax.persistence.Index(columnList = "creationTime"),
|
||||
@javax.persistence.Index(columnList = "historyRegistrarId"),
|
||||
@javax.persistence.Index(columnList = "historyType"),
|
||||
@javax.persistence.Index(columnList = "historyModificationTime")
|
||||
})
|
||||
public class ContactHistory extends HistoryEntry {
|
||||
// Store ContactBase instead of ContactResource so we don't pick up its @Id
|
||||
ContactBase contactBase;
|
||||
|
||||
@Column(nullable = false)
|
||||
VKey<ContactResource> contactRepoId;
|
||||
|
||||
/** The state of the {@link ContactBase} object at this point in time. */
|
||||
public ContactBase getContactBase() {
|
||||
return contactBase;
|
||||
}
|
||||
|
||||
/** The key to the {@link ContactResource} this is based off of. */
|
||||
public VKey<ContactResource> getContactRepoId() {
|
||||
return contactRepoId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder asBuilder() {
|
||||
return new Builder(clone(this));
|
||||
}
|
||||
|
||||
public static class Builder extends HistoryEntry.Builder<ContactHistory, ContactHistory.Builder> {
|
||||
|
||||
public Builder() {}
|
||||
|
||||
public Builder(ContactHistory instance) {
|
||||
super(instance);
|
||||
}
|
||||
|
||||
public Builder setContactBase(ContactBase contactBase) {
|
||||
getInstance().contactBase = contactBase;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setContactRepoId(VKey<ContactResource> contactRepoId) {
|
||||
getInstance().contactRepoId = contactRepoId;
|
||||
contactRepoId.maybeGetOfyKey().ifPresent(parent -> getInstance().parent = parent);
|
||||
return this;
|
||||
}
|
||||
|
||||
// We can remove this once all HistoryEntries are converted to History objects
|
||||
@Override
|
||||
public Builder setParent(Key<? extends EppResource> parent) {
|
||||
super.setParent(parent);
|
||||
getInstance().contactRepoId = VKey.create(ContactResource.class, parent.getName(), parent);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,36 +14,16 @@
|
||||
|
||||
package google.registry.model.contact;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.model.EppResourceUtils.projectResourceOntoBuilderAtTime;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.IgnoreSave;
|
||||
import com.googlecode.objectify.annotation.Index;
|
||||
import com.googlecode.objectify.condition.IfNull;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.EppResource.ForeignKeyedEppResource;
|
||||
import google.registry.model.EppResource.ResourceWithTransferData;
|
||||
import google.registry.model.annotations.ExternalMessagingName;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.contact.PostalInfo.Type;
|
||||
import google.registry.model.transfer.ContactTransferData;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.persistence.WithStringVKey;
|
||||
import google.registry.schema.replay.DatastoreAndSqlEntity;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.AttributeOverride;
|
||||
import javax.persistence.AttributeOverrides;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
@@ -66,140 +46,12 @@ import org.joda.time.DateTime;
|
||||
@ExternalMessagingName("contact")
|
||||
@WithStringVKey
|
||||
@Access(AccessType.FIELD)
|
||||
public class ContactResource extends EppResource
|
||||
implements DatastoreAndSqlEntity, ForeignKeyedEppResource, ResourceWithTransferData {
|
||||
|
||||
/**
|
||||
* Unique identifier for this contact.
|
||||
*
|
||||
* <p>This is only unique in the sense that for any given lifetime specified as the time range
|
||||
* from (creationTime, deletionTime) there can only be one contact in Datastore with this id.
|
||||
* However, there can be many contacts with the same id and non-overlapping lifetimes.
|
||||
*/
|
||||
String contactId;
|
||||
|
||||
/**
|
||||
* Localized postal info for the contact. All contained values must be representable in the 7-bit
|
||||
* US-ASCII character set. Personal info; cleared by {@link Builder#wipeOut}.
|
||||
*/
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "name", column = @Column(name = "addr_local_name")),
|
||||
@AttributeOverride(name = "org", column = @Column(name = "addr_local_org")),
|
||||
@AttributeOverride(name = "type", column = @Column(name = "addr_local_type")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine1",
|
||||
column = @Column(name = "addr_local_street_line1")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine2",
|
||||
column = @Column(name = "addr_local_street_line2")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine3",
|
||||
column = @Column(name = "addr_local_street_line3")),
|
||||
@AttributeOverride(name = "address.city", column = @Column(name = "addr_local_city")),
|
||||
@AttributeOverride(name = "address.state", column = @Column(name = "addr_local_state")),
|
||||
@AttributeOverride(name = "address.zip", column = @Column(name = "addr_local_zip")),
|
||||
@AttributeOverride(
|
||||
name = "address.countryCode",
|
||||
column = @Column(name = "addr_local_country_code"))
|
||||
})
|
||||
PostalInfo localizedPostalInfo;
|
||||
|
||||
/**
|
||||
* Internationalized postal info for the contact. Personal info; cleared by {@link
|
||||
* Builder#wipeOut}.
|
||||
*/
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "name", column = @Column(name = "addr_i18n_name")),
|
||||
@AttributeOverride(name = "org", column = @Column(name = "addr_i18n_org")),
|
||||
@AttributeOverride(name = "type", column = @Column(name = "addr_i18n_type")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine1",
|
||||
column = @Column(name = "addr_i18n_street_line1")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine2",
|
||||
column = @Column(name = "addr_i18n_street_line2")),
|
||||
@AttributeOverride(
|
||||
name = "address.streetLine3",
|
||||
column = @Column(name = "addr_i18n_street_line3")),
|
||||
@AttributeOverride(name = "address.city", column = @Column(name = "addr_i18n_city")),
|
||||
@AttributeOverride(name = "address.state", column = @Column(name = "addr_i18n_state")),
|
||||
@AttributeOverride(name = "address.zip", column = @Column(name = "addr_i18n_zip")),
|
||||
@AttributeOverride(
|
||||
name = "address.countryCode",
|
||||
column = @Column(name = "addr_i18n_country_code"))
|
||||
})
|
||||
PostalInfo internationalizedPostalInfo;
|
||||
|
||||
/**
|
||||
* Contact name used for name searches. This is set automatically to be the internationalized
|
||||
* postal name, or if null, the localized postal name, or if that is null as well, null. Personal
|
||||
* info; cleared by {@link Builder#wipeOut}.
|
||||
*/
|
||||
@Index
|
||||
String searchName;
|
||||
|
||||
/** Contact’s voice number. Personal info; cleared by {@link Builder#wipeOut}. */
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "phoneNumber", column = @Column(name = "voice_phone_number")),
|
||||
@AttributeOverride(name = "extension", column = @Column(name = "voice_phone_extension")),
|
||||
})
|
||||
ContactPhoneNumber voice;
|
||||
|
||||
/** Contact’s fax number. Personal info; cleared by {@link Builder#wipeOut}. */
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "phoneNumber", column = @Column(name = "fax_phone_number")),
|
||||
@AttributeOverride(name = "extension", column = @Column(name = "fax_phone_extension")),
|
||||
})
|
||||
ContactPhoneNumber fax;
|
||||
|
||||
/** Contact’s email address. Personal info; cleared by {@link Builder#wipeOut}. */
|
||||
@IgnoreSave(IfNull.class)
|
||||
String email;
|
||||
|
||||
/** Authorization info (aka transfer secret) of the contact. */
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "pw.value", column = @Column(name = "auth_info_value")),
|
||||
@AttributeOverride(name = "pw.repoId", column = @Column(name = "auth_info_repo_id")),
|
||||
})
|
||||
ContactAuthInfo authInfo;
|
||||
|
||||
/** Data about any pending or past transfers on this contact. */
|
||||
ContactTransferData transferData;
|
||||
|
||||
/**
|
||||
* The time that this resource was last transferred.
|
||||
*
|
||||
* <p>Can be null if the resource has never been transferred.
|
||||
*/
|
||||
DateTime lastTransferTime;
|
||||
|
||||
// If any new fields are added which contain personal information, make sure they are cleared by
|
||||
// the wipeOut() function, so that data is not kept around for deleted contacts.
|
||||
|
||||
/** Disclosure policy. */
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "name", column = @Column(name = "disclose_types_name")),
|
||||
@AttributeOverride(name = "org", column = @Column(name = "disclose_types_org")),
|
||||
@AttributeOverride(name = "addr", column = @Column(name = "disclose_types_addr")),
|
||||
@AttributeOverride(name = "flag", column = @Column(name = "disclose_mode_flag")),
|
||||
@AttributeOverride(name = "voice.marked", column = @Column(name = "disclose_show_voice")),
|
||||
@AttributeOverride(name = "fax.marked", column = @Column(name = "disclose_show_fax")),
|
||||
@AttributeOverride(name = "email.marked", column = @Column(name = "disclose_show_email"))
|
||||
})
|
||||
Disclose disclose;
|
||||
public class ContactResource extends ContactBase
|
||||
implements DatastoreAndSqlEntity, ForeignKeyedEppResource {
|
||||
|
||||
@Override
|
||||
public VKey<ContactResource> createVKey() {
|
||||
// TODO(mmuller): create symmetric keys if we can ever reload both sides.
|
||||
return VKey.create(ContactResource.class, getRepoId(), Key.create(this));
|
||||
}
|
||||
|
||||
@@ -210,81 +62,9 @@ public class ContactResource extends EppResource
|
||||
return super.getRepoId();
|
||||
}
|
||||
|
||||
public String getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
public PostalInfo getLocalizedPostalInfo() {
|
||||
return localizedPostalInfo;
|
||||
}
|
||||
|
||||
public PostalInfo getInternationalizedPostalInfo() {
|
||||
return internationalizedPostalInfo;
|
||||
}
|
||||
|
||||
public String getSearchName() {
|
||||
return searchName;
|
||||
}
|
||||
|
||||
public ContactPhoneNumber getVoiceNumber() {
|
||||
return voice;
|
||||
}
|
||||
|
||||
public ContactPhoneNumber getFaxNumber() {
|
||||
return fax;
|
||||
}
|
||||
|
||||
public String getEmailAddress() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public ContactAuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
|
||||
public Disclose getDisclose() {
|
||||
return disclose;
|
||||
}
|
||||
|
||||
public final String getCurrentSponsorClientId() {
|
||||
return getPersistedCurrentSponsorClientId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactTransferData getTransferData() {
|
||||
return Optional.ofNullable(transferData).orElse(ContactTransferData.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime getLastTransferTime() {
|
||||
return lastTransferTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getForeignKey() {
|
||||
return contactId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Postal info for the contact.
|
||||
*
|
||||
* <p>The XML marshalling expects the {@link PostalInfo} objects in a list, but we can't actually
|
||||
* persist them to Datastore that way because Objectify can't handle collections of embedded
|
||||
* objects that themselves contain collections, and there's a list of streets inside. This method
|
||||
* transforms the persisted format to the XML format for marshalling.
|
||||
*/
|
||||
@XmlElement(name = "postalInfo")
|
||||
public ImmutableList<PostalInfo> getPostalInfosAsList() {
|
||||
return Stream.of(localizedPostalInfo, internationalizedPostalInfo)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactResource cloneProjectedAtTime(DateTime now) {
|
||||
Builder builder = this.asBuilder();
|
||||
projectResourceOntoBuilderAtTime(this, builder, now);
|
||||
return builder.build();
|
||||
return ContactBase.cloneContactProjectedAtTime(this, now);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -293,116 +73,12 @@ public class ContactResource extends EppResource
|
||||
}
|
||||
|
||||
/** A builder for constructing {@link ContactResource}, since it is immutable. */
|
||||
public static class Builder extends EppResource.Builder<ContactResource, Builder>
|
||||
implements BuilderWithTransferData<ContactTransferData, Builder> {
|
||||
public static class Builder extends ContactBase.Builder<ContactResource, Builder> {
|
||||
|
||||
public Builder() {}
|
||||
|
||||
private Builder(ContactResource instance) {
|
||||
super(instance);
|
||||
}
|
||||
|
||||
public Builder setContactId(String contactId) {
|
||||
getInstance().contactId = contactId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setLocalizedPostalInfo(PostalInfo localizedPostalInfo) {
|
||||
checkArgument(localizedPostalInfo == null
|
||||
|| Type.LOCALIZED.equals(localizedPostalInfo.getType()));
|
||||
getInstance().localizedPostalInfo = localizedPostalInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setInternationalizedPostalInfo(PostalInfo internationalizedPostalInfo) {
|
||||
checkArgument(internationalizedPostalInfo == null
|
||||
|| Type.INTERNATIONALIZED.equals(internationalizedPostalInfo.getType()));
|
||||
getInstance().internationalizedPostalInfo = internationalizedPostalInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder overlayLocalizedPostalInfo(PostalInfo localizedPostalInfo) {
|
||||
return setLocalizedPostalInfo(getInstance().localizedPostalInfo == null
|
||||
? localizedPostalInfo
|
||||
: getInstance().localizedPostalInfo.overlay(localizedPostalInfo));
|
||||
}
|
||||
|
||||
public Builder overlayInternationalizedPostalInfo(PostalInfo internationalizedPostalInfo) {
|
||||
return setInternationalizedPostalInfo(getInstance().internationalizedPostalInfo == null
|
||||
? internationalizedPostalInfo
|
||||
: getInstance().internationalizedPostalInfo.overlay(internationalizedPostalInfo));
|
||||
}
|
||||
|
||||
public Builder setVoiceNumber(ContactPhoneNumber voiceNumber) {
|
||||
getInstance().voice = voiceNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFaxNumber(ContactPhoneNumber faxNumber) {
|
||||
getInstance().fax = faxNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEmailAddress(String emailAddress) {
|
||||
getInstance().email = emailAddress;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAuthInfo(ContactAuthInfo authInfo) {
|
||||
getInstance().authInfo = authInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDisclose(Disclose disclose) {
|
||||
getInstance().disclose = disclose;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setTransferData(ContactTransferData transferData) {
|
||||
getInstance().transferData = transferData;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setLastTransferTime(DateTime lastTransferTime) {
|
||||
getInstance().lastTransferTime = lastTransferTime;
|
||||
return thisCastToDerived();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all personally identifying information about a contact.
|
||||
*
|
||||
* <p>This should be used when deleting a contact so that the soft-deleted entity doesn't
|
||||
* contain information that the registrant requested to be deleted.
|
||||
*/
|
||||
public Builder wipeOut() {
|
||||
setEmailAddress(null);
|
||||
setFaxNumber(null);
|
||||
setInternationalizedPostalInfo(null);
|
||||
setLocalizedPostalInfo(null);
|
||||
setVoiceNumber(null);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContactResource build() {
|
||||
ContactResource instance = getInstance();
|
||||
// If TransferData is totally empty, set it to null.
|
||||
if (ContactTransferData.EMPTY.equals(instance.transferData)) {
|
||||
setTransferData(null);
|
||||
}
|
||||
// Set the searchName using the internationalized and localized postal info names.
|
||||
if ((instance.internationalizedPostalInfo != null)
|
||||
&& (instance.internationalizedPostalInfo.getName() != null)) {
|
||||
instance.searchName = instance.internationalizedPostalInfo.getName();
|
||||
} else if ((instance.localizedPostalInfo != null)
|
||||
&& (instance.localizedPostalInfo.getName() != null)) {
|
||||
instance.searchName = instance.localizedPostalInfo.getName();
|
||||
} else {
|
||||
instance.searchName = null;
|
||||
}
|
||||
return super.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ public class HostBase extends EppResource {
|
||||
}
|
||||
|
||||
@Override
|
||||
public VKey<? extends EppResource> createVKey() {
|
||||
public VKey<? extends HostBase> createVKey() {
|
||||
return VKey.create(HostBase.class, getRepoId(), Key.create(this));
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ public class HostHistory extends HistoryEntry {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setHostResourceId(VKey<HostResource> hostRepoId) {
|
||||
public Builder setHostRepoId(VKey<HostResource> hostRepoId) {
|
||||
getInstance().hostRepoId = hostRepoId;
|
||||
hostRepoId.maybeGetOfyKey().ifPresent(parent -> getInstance().parent = parent);
|
||||
return this;
|
||||
@@ -83,8 +83,7 @@ public class HostHistory extends HistoryEntry {
|
||||
@Override
|
||||
public Builder setParent(Key<? extends EppResource> parent) {
|
||||
super.setParent(parent);
|
||||
getInstance().hostRepoId =
|
||||
VKey.create(HostResource.class, parent.getName(), (Key<HostResource>) parent);
|
||||
getInstance().hostRepoId = VKey.create(HostResource.class, parent.getName(), parent);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package google.registry.model.registry.label;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
@@ -30,6 +31,7 @@ import com.google.common.collect.Multiset;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import com.googlecode.objectify.annotation.Ignore;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
@@ -42,6 +44,11 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Transient;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
@@ -49,25 +56,46 @@ import org.joda.time.DateTime;
|
||||
*
|
||||
* @param <T> The type of the root value being listed, e.g. {@link ReservationType}.
|
||||
* @param <R> The type of domain label entry being listed, e.g. {@link ReservedListEntry} (note,
|
||||
* must subclass {@link DomainLabelEntry}.
|
||||
* must subclass {@link DomainLabelEntry}.
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public abstract class BaseDomainLabelList<T extends Comparable<?>, R extends DomainLabelEntry<T, ?>>
|
||||
extends ImmutableObject implements Buildable {
|
||||
|
||||
@Ignore
|
||||
@javax.persistence.Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
Long revisionId;
|
||||
|
||||
@Id
|
||||
@Column(nullable = false)
|
||||
String name;
|
||||
|
||||
@Parent
|
||||
Key<EntityGroupRoot> parent = getCrossTldKey();
|
||||
@Parent @Transient Key<EntityGroupRoot> parent = getCrossTldKey();
|
||||
|
||||
DateTime creationTime;
|
||||
@Transient DateTime creationTime;
|
||||
|
||||
// The list in Cloud SQL is immutable, we only have a creation_timestamp field and it should be
|
||||
// set to the timestamp when the list is created. In Datastore, we have two fields and the
|
||||
// lastUpdateTime is set to the current timestamp when creating and updating a list. So, we use
|
||||
// lastUpdateTime as the creation_timestamp column during the dual-write phase for compatibility.
|
||||
@Column(name = "creation_timestamp", nullable = false)
|
||||
DateTime lastUpdateTime;
|
||||
|
||||
/** Returns the ID of this revision, or throws if null. */
|
||||
public long getRevisionId() {
|
||||
checkState(
|
||||
revisionId != null,
|
||||
"revisionId is null because this object has not been persisted to the database yet");
|
||||
return revisionId;
|
||||
}
|
||||
|
||||
/** Returns the name of the reserved list. */
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/** Returns the creation time of this revision of the reserved list. */
|
||||
public DateTime getCreationTime() {
|
||||
return creationTime;
|
||||
}
|
||||
@@ -183,6 +211,9 @@ public abstract class BaseDomainLabelList<T extends Comparable<?>, R extends Dom
|
||||
@Override
|
||||
public T build() {
|
||||
checkArgument(!isNullOrEmpty(getInstance().name), "List must have a name");
|
||||
// The list is immutable in Cloud SQL, so make sure the revision id is not set when the
|
||||
// builder object is created from a list object
|
||||
getInstance().revisionId = null;
|
||||
return super.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,16 +23,20 @@ import com.google.common.net.InternetDomainName;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import google.registry.model.Buildable.GenericBuilder;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
/**
|
||||
* Represents a label entry parsed from a line in a reserved/premium list txt file.
|
||||
*
|
||||
* @param <T> The type of the value stored for the domain label, e.g. {@link ReservationType}.
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public abstract class DomainLabelEntry<T extends Comparable<?>, D extends DomainLabelEntry<?, ?>>
|
||||
extends ImmutableObject implements Comparable<D> {
|
||||
|
||||
@Id
|
||||
@Column(name = "domain_label", insertable = false, updatable = false)
|
||||
String label;
|
||||
|
||||
String comment;
|
||||
|
||||
@@ -16,11 +16,8 @@ package google.registry.model.registry.label;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.config.RegistryConfig.getDomainLabelListCacheDuration;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.model.registry.label.ReservationType.FULLY_BLOCKED;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
@@ -30,12 +27,8 @@ import com.google.common.base.Splitter;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.MapDifference;
|
||||
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.Embed;
|
||||
@@ -45,45 +38,58 @@ import com.googlecode.objectify.mapper.Mapper;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.label.DomainLabelMetrics.MetricsReservedListMatch;
|
||||
import google.registry.schema.replay.DatastoreEntity;
|
||||
import google.registry.schema.replay.SqlEntity;
|
||||
import google.registry.schema.tld.ReservedList.ReservedEntry;
|
||||
import google.registry.schema.tld.ReservedListDao;
|
||||
import google.registry.schema.replay.DatastoreAndSqlEntity;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.MapKeyColumn;
|
||||
import javax.persistence.Table;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* A reserved list entity, persisted to Datastore, that is used to check domain label reservations.
|
||||
* A list of reserved domain labels that are blocked from being registered for various reasons.
|
||||
*
|
||||
* <p>Note that the primary key of this entity is {@link #revisionId}, which is auto-generated by
|
||||
* the database. So, if a retry of insertion happens after the previous attempt unexpectedly
|
||||
* succeeds, we will end up with having two exact same reserved lists that differ only by
|
||||
* revisionId. This is fine though, because we only use the list with the highest revisionId.
|
||||
*/
|
||||
@Entity
|
||||
@javax.persistence.Entity
|
||||
@Table(indexes = {@Index(columnList = "name", name = "reservedlist_name_idx")})
|
||||
public final class ReservedList
|
||||
extends BaseDomainLabelList<ReservationType, ReservedList.ReservedListEntry>
|
||||
implements DatastoreEntity {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
implements DatastoreAndSqlEntity {
|
||||
|
||||
@Mapify(ReservedListEntry.LabelMapper.class)
|
||||
@ElementCollection
|
||||
@CollectionTable(
|
||||
name = "ReservedEntry",
|
||||
joinColumns = @JoinColumn(name = "revisionId", referencedColumnName = "revisionId"))
|
||||
@MapKeyColumn(name = "domain_label")
|
||||
Map<String, ReservedListEntry> reservedListMap;
|
||||
|
||||
@Column(nullable = false)
|
||||
boolean shouldPublish = true;
|
||||
|
||||
@Override
|
||||
public ImmutableList<SqlEntity> toSqlEntities() {
|
||||
return ImmutableList.of(); // ReservedList is dual-written
|
||||
}
|
||||
|
||||
/**
|
||||
* A reserved list entry entity, persisted to Datastore, that represents a single label and its
|
||||
* reservation type.
|
||||
*/
|
||||
@Embed
|
||||
public static class ReservedListEntry
|
||||
extends DomainLabelEntry<ReservationType, ReservedListEntry> implements Buildable {
|
||||
@Embeddable
|
||||
public static class ReservedListEntry extends DomainLabelEntry<ReservationType, ReservedListEntry>
|
||||
implements Buildable {
|
||||
|
||||
@Column(nullable = false)
|
||||
ReservationType reservationType;
|
||||
|
||||
/** Mapper for use with @Mapify */
|
||||
@@ -150,6 +156,7 @@ public final class ReservedList
|
||||
return shouldPublish;
|
||||
}
|
||||
|
||||
/** Returns a {@link Map} of domain labels to {@link ReservedListEntry}. */
|
||||
public ImmutableMap<String, ReservedListEntry> getReservedListEntries() {
|
||||
return ImmutableMap.copyOf(nullToEmpty(reservedListMap));
|
||||
}
|
||||
@@ -239,65 +246,10 @@ public final class ReservedList
|
||||
new CacheLoader<String, ReservedList>() {
|
||||
@Override
|
||||
public ReservedList load(String listName) {
|
||||
ReservedList datastoreList =
|
||||
ofy()
|
||||
.load()
|
||||
.type(ReservedList.class)
|
||||
.parent(getCrossTldKey())
|
||||
.id(listName)
|
||||
.now();
|
||||
// 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;
|
||||
return ReservedListDualWriteDao.getLatestRevision(listName).orElse(null);
|
||||
}
|
||||
});
|
||||
|
||||
private static final void loadAndCompareCloudSqlList(ReservedList datastoreList) {
|
||||
Optional<google.registry.schema.tld.ReservedList> maybeCloudSqlList =
|
||||
ReservedListDao.getLatestRevision(datastoreList.getName());
|
||||
if (maybeCloudSqlList.isPresent()) {
|
||||
Map<String, ReservedEntry> datastoreLabelsToReservations =
|
||||
datastoreList.reservedListMap.entrySet().parallelStream()
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
Map.Entry::getKey,
|
||||
entry ->
|
||||
ReservedEntry.create(
|
||||
entry.getValue().reservationType, entry.getValue().comment)));
|
||||
|
||||
google.registry.schema.tld.ReservedList cloudSqlList = maybeCloudSqlList.get();
|
||||
MapDifference<String, ReservedEntry> diff =
|
||||
Maps.difference(datastoreLabelsToReservations, cloudSqlList.getLabelsToReservations());
|
||||
if (!diff.areEqual()) {
|
||||
if (diff.entriesDiffering().size() > 10) {
|
||||
logger.atWarning().log(
|
||||
String.format(
|
||||
"Unequal reserved 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 reserved lists detected:\n");
|
||||
diff.entriesDiffering()
|
||||
.forEach(
|
||||
(label, valueDiff) ->
|
||||
diffMessage.append(
|
||||
String.format(
|
||||
"Domain label %s has entry %s in Datastore and entry"
|
||||
+ " %s in Cloud SQL.\n",
|
||||
label, valueDiff.leftValue(), valueDiff.rightValue())));
|
||||
logger.atWarning().log(diffMessage.toString());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.atWarning().log("Reserved list in Cloud SQL is empty.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link ReservationType} of a label in a single ReservedList, or returns an absent
|
||||
* Optional if none exists in the list.
|
||||
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.registry.label;
|
||||
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.ofyTm;
|
||||
|
||||
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.googlecode.objectify.Key;
|
||||
import google.registry.model.registry.label.ReservedList.ReservedListEntry;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A {@link ReservedList} DAO that does dual-write and dual-read against Datastore and Cloud SQL. It
|
||||
* still uses Datastore as the primary storage and suppresses any exception thrown by Cloud SQL.
|
||||
*
|
||||
* <p>TODO(b/160993806): Delete this DAO and switch to use the SQL only DAO after migrating to Cloud
|
||||
* SQL.
|
||||
*/
|
||||
public class ReservedListDualWriteDao {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private ReservedListDualWriteDao() {}
|
||||
|
||||
/** Persist a new reserved list to Cloud SQL. */
|
||||
public static void save(ReservedList reservedList) {
|
||||
ofyTm().transact(() -> ofyTm().saveNewOrUpdate(reservedList));
|
||||
try {
|
||||
logger.atInfo().log("Saving reserved list %s to Cloud SQL", reservedList.getName());
|
||||
ReservedListSqlDao.save(reservedList);
|
||||
logger.atInfo().log(
|
||||
"Saved reserved list %s with %d entries to Cloud SQL",
|
||||
reservedList.getName(), reservedList.getReservedListEntries().size());
|
||||
} catch (Throwable t) {
|
||||
logger.atSevere().withCause(t).log("Error saving the reserved list to Cloud SQL.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent revision of the {@link ReservedList} with the specified name, if it
|
||||
* exists.
|
||||
*/
|
||||
public static Optional<ReservedList> getLatestRevision(String reservedListName) {
|
||||
Optional<ReservedList> maybeDatastoreList =
|
||||
ofyTm()
|
||||
.maybeLoad(
|
||||
VKey.createOfy(
|
||||
ReservedList.class,
|
||||
Key.create(getCrossTldKey(), ReservedList.class, reservedListName)));
|
||||
try {
|
||||
// Also load the list from Cloud SQL, compare the two lists, and log if different.
|
||||
maybeDatastoreList.ifPresent(ReservedListDualWriteDao::loadAndCompareCloudSqlList);
|
||||
} catch (Throwable t) {
|
||||
logger.atSevere().withCause(t).log("Error comparing reserved lists.");
|
||||
}
|
||||
return maybeDatastoreList;
|
||||
}
|
||||
|
||||
private static void loadAndCompareCloudSqlList(ReservedList datastoreList) {
|
||||
Optional<ReservedList> maybeCloudSqlList =
|
||||
ReservedListSqlDao.getLatestRevision(datastoreList.getName());
|
||||
if (maybeCloudSqlList.isPresent()) {
|
||||
Map<String, ReservedListEntry> datastoreLabelsToReservations =
|
||||
datastoreList.reservedListMap.entrySet().parallelStream()
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
Map.Entry::getKey,
|
||||
entry ->
|
||||
ReservedListEntry.create(
|
||||
entry.getKey(),
|
||||
entry.getValue().reservationType,
|
||||
entry.getValue().comment)));
|
||||
|
||||
ReservedList cloudSqlList = maybeCloudSqlList.get();
|
||||
MapDifference<String, ReservedListEntry> diff =
|
||||
Maps.difference(datastoreLabelsToReservations, cloudSqlList.reservedListMap);
|
||||
if (!diff.areEqual()) {
|
||||
if (diff.entriesDiffering().size() > 10) {
|
||||
logger.atWarning().log(
|
||||
String.format(
|
||||
"Unequal reserved 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 reserved lists detected:\n");
|
||||
diff.entriesDiffering().entrySet().stream()
|
||||
.forEach(
|
||||
entry -> {
|
||||
String label = entry.getKey();
|
||||
ValueDifference<ReservedListEntry> valueDiff = entry.getValue();
|
||||
diffMessage.append(
|
||||
String.format(
|
||||
"Domain label %s has entry %s in Datastore and entry"
|
||||
+ " %s in Cloud SQL.\n",
|
||||
label, valueDiff.leftValue(), valueDiff.rightValue()));
|
||||
});
|
||||
logger.atWarning().log(diffMessage.toString());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.atWarning().log("Reserved list in Cloud SQL is empty.");
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
-41
@@ -12,20 +12,46 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.schema.tld;
|
||||
package google.registry.model.registry.label;
|
||||
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/** Data access object class for {@link ReservedList} */
|
||||
public class ReservedListDao {
|
||||
/**
|
||||
* A {@link ReservedList} DAO for Cloud SQL.
|
||||
*
|
||||
* <p>TODO(b/160993806): Rename this class to ReservedListDao after migrating to Cloud SQL.
|
||||
*/
|
||||
public class ReservedListSqlDao {
|
||||
|
||||
private ReservedListSqlDao() {}
|
||||
|
||||
/** Persist a new reserved list to Cloud SQL. */
|
||||
public static void save(ReservedList reservedList) {
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(reservedList));
|
||||
checkArgumentNotNull(reservedList, "Must specify reservedList");
|
||||
jpaTm().transact(() -> jpaTm().saveNew(reservedList));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent revision of the {@link ReservedList} with the specified name, if it
|
||||
* exists.
|
||||
*/
|
||||
public static Optional<ReservedList> getLatestRevision(String reservedListName) {
|
||||
return jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery(
|
||||
"FROM ReservedList rl LEFT JOIN FETCH rl.reservedListMap WHERE"
|
||||
+ " rl.revisionId IN (SELECT MAX(revisionId) FROM ReservedList subrl"
|
||||
+ " WHERE subrl.name = :name)",
|
||||
ReservedList.class)
|
||||
.setParameter("name", reservedListName)
|
||||
.getResultStream()
|
||||
.findFirst());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,39 +72,4 @@ public class ReservedListDao {
|
||||
.size()
|
||||
> 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent revision of the {@link ReservedList} with the specified name, if it
|
||||
* exists. TODO(shicong): Change this method to package level access after dual-read phase.
|
||||
*/
|
||||
public static Optional<ReservedList> getLatestRevision(String reservedListName) {
|
||||
return jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery(
|
||||
"FROM ReservedList rl LEFT JOIN FETCH rl.labelsToReservations WHERE"
|
||||
+ " rl.revisionId IN (SELECT MAX(revisionId) FROM ReservedList subrl"
|
||||
+ " WHERE subrl.name = :name)",
|
||||
ReservedList.class)
|
||||
.setParameter("name", reservedListName)
|
||||
.getResultStream()
|
||||
.findFirst());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent revision of the {@link ReservedList} with the specified name, from
|
||||
* cache.
|
||||
*/
|
||||
public static Optional<ReservedList> getLatestRevisionCached(String reservedListName) {
|
||||
try {
|
||||
return ReservedListCache.cacheReservedLists.get(reservedListName);
|
||||
} catch (ExecutionException e) {
|
||||
throw new UncheckedExecutionException(
|
||||
"Could not retrieve reserved list named " + reservedListName, e);
|
||||
}
|
||||
}
|
||||
|
||||
private ReservedListDao() {}
|
||||
}
|
||||
@@ -185,6 +185,10 @@ public class HistoryEntry extends ImmutableObject implements Buildable {
|
||||
@Transient // domain-specific
|
||||
Set<DomainTransactionRecord> domainTransactionRecords;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Key<? extends EppResource> getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@@ -94,6 +94,21 @@ public class PersistenceModule {
|
||||
@Config("cloudSqlJdbcUrl") String jdbcUrl,
|
||||
@Config("cloudSqlInstanceConnectionName") String instanceConnectionName,
|
||||
@DefaultHibernateConfigs ImmutableMap<String, String> defaultConfigs) {
|
||||
return createPartialSqlConfigs(jdbcUrl, instanceConnectionName, defaultConfigs);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@BeamPipelineCloudSqlConfigs
|
||||
static ImmutableMap<String, String> provideBeamPipelineCloudSqlConfigs(
|
||||
@Config("beamCloudSqlJdbcUrl") String jdbcUrl,
|
||||
@Config("beamCloudSqlInstanceConnectionName") String instanceConnectionName,
|
||||
@DefaultHibernateConfigs ImmutableMap<String, String> defaultConfigs) {
|
||||
return createPartialSqlConfigs(jdbcUrl, instanceConnectionName, defaultConfigs);
|
||||
}
|
||||
|
||||
private static ImmutableMap<String, String> createPartialSqlConfigs(
|
||||
String jdbcUrl, String instanceConnectionName, 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");
|
||||
@@ -135,13 +150,15 @@ public class PersistenceModule {
|
||||
@Singleton
|
||||
@SocketFactoryJpaTm
|
||||
static JpaTransactionManager provideSocketFactoryJpaTm(
|
||||
@Config("cloudSqlUsername") String username,
|
||||
@Config("cloudSqlPassword") String password,
|
||||
@PartialCloudSqlConfigs ImmutableMap<String, String> cloudSqlConfigs,
|
||||
@Config("beamCloudSqlUsername") String username,
|
||||
@Config("beamCloudSqlPassword") String password,
|
||||
@Config("beamHibernateHikariMaximumPoolSize") int hikariMaximumPoolSize,
|
||||
@BeamPipelineCloudSqlConfigs ImmutableMap<String, String> cloudSqlConfigs,
|
||||
Clock clock) {
|
||||
HashMap<String, String> overrides = Maps.newHashMap(cloudSqlConfigs);
|
||||
overrides.put(Environment.USER, username);
|
||||
overrides.put(Environment.PASS, password);
|
||||
overrides.put(HIKARI_MAXIMUM_POOL_SIZE, String.valueOf(hikariMaximumPoolSize));
|
||||
return new JpaTransactionManagerImpl(create(overrides), clock);
|
||||
}
|
||||
|
||||
@@ -149,9 +166,9 @@ public class PersistenceModule {
|
||||
@Singleton
|
||||
@JdbcJpaTm
|
||||
static JpaTransactionManager provideLocalJpaTm(
|
||||
@Config("cloudSqlJdbcUrl") String jdbcUrl,
|
||||
@Config("cloudSqlUsername") String username,
|
||||
@Config("cloudSqlPassword") String password,
|
||||
@Config("beamCloudSqlJdbcUrl") String jdbcUrl,
|
||||
@Config("beamCloudSqlUsername") String username,
|
||||
@Config("beamCloudSqlPassword") String password,
|
||||
@DefaultHibernateConfigs ImmutableMap<String, String> defaultConfigs,
|
||||
Clock clock) {
|
||||
HashMap<String, String> overrides = Maps.newHashMap(defaultConfigs);
|
||||
@@ -218,6 +235,11 @@ public class PersistenceModule {
|
||||
@Documented
|
||||
@interface PartialCloudSqlConfigs {}
|
||||
|
||||
/** Dagger qualifier for the Cloud SQL configs used by Beam pipelines. */
|
||||
@Qualifier
|
||||
@Documented
|
||||
@interface BeamPipelineCloudSqlConfigs {}
|
||||
|
||||
/** 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
|
||||
|
||||
@@ -58,6 +58,31 @@ public class VKey<T> extends ImmutableObject implements Serializable {
|
||||
return new VKey(kind, null, sqlKey);
|
||||
}
|
||||
|
||||
/** Creates a {@link VKey} which only contains the ofy primary key. */
|
||||
public static <T> VKey<T> createOfy(
|
||||
Class<? extends T> kind, com.googlecode.objectify.Key<? extends T> ofyKey) {
|
||||
checkArgumentNotNull(kind, "kind must not be null");
|
||||
checkArgumentNotNull(ofyKey, "ofyKey must not be null");
|
||||
return new VKey(kind, ofyKey, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link VKey} which only contains the ofy primary key by specifying the id of the
|
||||
* {@link Key}.
|
||||
*/
|
||||
public static <T> VKey<T> createOfy(Class<? extends T> kind, long id) {
|
||||
return createOfy(kind, Key.create(kind, id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link VKey} which only contains the ofy primary key by specifying the name of the
|
||||
* {@link Key}.
|
||||
*/
|
||||
public static <T> VKey<T> createOfy(Class<? extends T> kind, String name) {
|
||||
checkArgumentNotNull(kind, "name must not be null");
|
||||
return createOfy(kind, Key.create(kind, name));
|
||||
}
|
||||
|
||||
/** Creates a {@link VKey} which only contains both sql and ofy primary key. */
|
||||
public static <T> VKey<T> create(
|
||||
Class<? extends T> kind, Object sqlKey, com.googlecode.objectify.Key ofyKey) {
|
||||
|
||||
@@ -25,4 +25,11 @@ public interface JpaTransactionManager extends TransactionManager {
|
||||
|
||||
/** Deletes the entity by its id, throws exception if the entity is not deleted. */
|
||||
public abstract <T> void assertDelete(VKey<T> key);
|
||||
|
||||
/**
|
||||
* Releases all resources and shuts down.
|
||||
*
|
||||
* <p>The errorprone check forbids injection of {@link java.io.Closeable} resources.
|
||||
*/
|
||||
void teardown();
|
||||
}
|
||||
|
||||
+7
-1
@@ -62,6 +62,11 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void teardown() {
|
||||
emf.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityManager getEntityManager() {
|
||||
if (transactionInfo.get().entityManager == null) {
|
||||
@@ -101,7 +106,8 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
T result = work.get();
|
||||
txn.commit();
|
||||
return result;
|
||||
} catch (RuntimeException e) {
|
||||
} catch (RuntimeException | Error e) {
|
||||
// Error is unchecked!
|
||||
try {
|
||||
txn.rollback();
|
||||
logger.atWarning().log("Error during transaction; transaction rolled back");
|
||||
|
||||
+7
-2
@@ -75,7 +75,12 @@ public class TransactionManagerFactory {
|
||||
return tm;
|
||||
}
|
||||
|
||||
/** Returns {@link JpaTransactionManager} instance. */
|
||||
/**
|
||||
* Returns {@link JpaTransactionManager} instance.
|
||||
*
|
||||
* <p>Between invocations of {@link TransactionManagerFactory#setJpaTm} every call to this method
|
||||
* returns the same instance.
|
||||
*/
|
||||
public static JpaTransactionManager jpaTm() {
|
||||
return jpaTm.get();
|
||||
}
|
||||
@@ -93,7 +98,7 @@ public class TransactionManagerFactory {
|
||||
RegistryEnvironment.get().equals(RegistryEnvironment.UNITTEST)
|
||||
|| RegistryToolEnvironment.get() != null,
|
||||
"setJpamTm() should only be called by tools and tests.");
|
||||
jpaTm = jpaTmSupplier;
|
||||
jpaTm = Suppliers.memoize(jpaTmSupplier::get);
|
||||
}
|
||||
|
||||
/** Sets the return of {@link #tm()} to the given instance of {@link TransactionManager}. */
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.schema.tld;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.ImmutableList.sortedCopyOf;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.util.DomainNameUtils.canonicalizeDomainName;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.CreateAutoTimestamp;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.registry.label.ReservationType;
|
||||
import google.registry.schema.replay.DatastoreEntity;
|
||||
import google.registry.schema.replay.SqlEntity;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.MapKeyColumn;
|
||||
import javax.persistence.Table;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* A list of reserved domain labels that are blocked from being registered for various reasons.
|
||||
*
|
||||
* <p>Note that the primary key of this entity is {@link #revisionId}, which is auto-generated by
|
||||
* the database. So, if a retry of insertion happens after the previous attempt unexpectedly
|
||||
* succeeds, we will end up with having two exact same reserved lists that differ only by
|
||||
* revisionId. This is fine though, because we only use the list with the highest revisionId.
|
||||
*/
|
||||
@Entity
|
||||
@Table(indexes = {@Index(columnList = "name", name = "reservedlist_name_idx")})
|
||||
public class ReservedList extends ImmutableObject implements SqlEntity {
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(nullable = false)
|
||||
private Long revisionId;
|
||||
|
||||
@Column(nullable = false)
|
||||
private CreateAutoTimestamp creationTimestamp = CreateAutoTimestamp.create(null);
|
||||
|
||||
@Column(nullable = false)
|
||||
private Boolean shouldPublish;
|
||||
|
||||
@ElementCollection
|
||||
@CollectionTable(
|
||||
name = "ReservedEntry",
|
||||
joinColumns = @JoinColumn(name = "revisionId", referencedColumnName = "revisionId"))
|
||||
@MapKeyColumn(name = "domainLabel")
|
||||
private Map<String, ReservedEntry> labelsToReservations;
|
||||
|
||||
@Override
|
||||
public ImmutableList<DatastoreEntity> toDatastoreEntities() {
|
||||
return ImmutableList.of(); // ReservedList is dual-written\
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class ReservedEntry extends ImmutableObject {
|
||||
@Column(nullable = false)
|
||||
private ReservationType reservationType;
|
||||
|
||||
@Column(nullable = true)
|
||||
private String comment;
|
||||
|
||||
private ReservedEntry(ReservationType reservationType, @Nullable String comment) {
|
||||
this.reservationType = reservationType;
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
// Hibernate requires this default constructor.
|
||||
private ReservedEntry() {}
|
||||
|
||||
/** Constructs a {@link ReservedEntry} object. */
|
||||
public static ReservedEntry create(ReservationType reservationType, @Nullable String comment) {
|
||||
return new ReservedEntry(reservationType, comment);
|
||||
}
|
||||
|
||||
/** Returns the reservation type for this entry. */
|
||||
public ReservationType getReservationType() {
|
||||
return reservationType;
|
||||
}
|
||||
|
||||
/** Returns the comment for this entry. Retruns null if there is no comment. */
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
}
|
||||
|
||||
private ReservedList(
|
||||
String name, Boolean shouldPublish, Map<String, ReservedEntry> labelsToReservations) {
|
||||
this.name = name;
|
||||
this.shouldPublish = shouldPublish;
|
||||
this.labelsToReservations = labelsToReservations;
|
||||
}
|
||||
|
||||
// Hibernate requires this default constructor.
|
||||
private ReservedList() {}
|
||||
|
||||
/** Constructs a {@link ReservedList} object. */
|
||||
public static ReservedList create(
|
||||
String name, Boolean shouldPublish, Map<String, ReservedEntry> labelsToReservations) {
|
||||
ImmutableList<String> invalidLabels =
|
||||
labelsToReservations.entrySet().parallelStream()
|
||||
.flatMap(
|
||||
entry -> {
|
||||
String label = entry.getKey();
|
||||
if (label.equals(canonicalizeDomainName(label))) {
|
||||
return Stream.empty();
|
||||
} else {
|
||||
return Stream.of(label);
|
||||
}
|
||||
})
|
||||
.collect(toImmutableList());
|
||||
checkArgument(
|
||||
invalidLabels.isEmpty(),
|
||||
"Label(s) [%s] must be in puny-coded, lower-case form",
|
||||
Joiner.on(",").join(sortedCopyOf(invalidLabels)));
|
||||
return new ReservedList(name, shouldPublish, labelsToReservations);
|
||||
}
|
||||
|
||||
/** Returns the name of the reserved list. */
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/** Returns the ID of this revision, or throws if null. */
|
||||
public Long getRevisionId() {
|
||||
checkState(
|
||||
revisionId != null,
|
||||
"revisionId is null because this object has not been persisted to the database yet");
|
||||
return revisionId;
|
||||
}
|
||||
|
||||
/** Returns the creation time of this revision of the reserved list. */
|
||||
public DateTime getCreationTimestamp() {
|
||||
return creationTimestamp.getTimestamp();
|
||||
}
|
||||
|
||||
/** Returns a {@link Map} of domain labels to {@link ReservedEntry}. */
|
||||
public ImmutableMap<String, ReservedEntry> getLabelsToReservations() {
|
||||
return ImmutableMap.copyOf(labelsToReservations);
|
||||
}
|
||||
|
||||
/** Returns true if the reserved list should be published. */
|
||||
public Boolean getShouldPublish() {
|
||||
return shouldPublish;
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright 2019 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.schema.tld;
|
||||
|
||||
import static google.registry.config.RegistryConfig.getDomainLabelListCacheDuration;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import google.registry.util.NonFinalForTesting;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** Caching utils for {@link ReservedList} */
|
||||
public class ReservedListCache {
|
||||
|
||||
/**
|
||||
* In-memory cache for reserved lists.
|
||||
*
|
||||
* <p>This is cached for a shorter duration because we need to periodically reload from the DB to
|
||||
* check if a new revision has been published, and if so, then use that.
|
||||
*/
|
||||
@NonFinalForTesting
|
||||
static LoadingCache<String, Optional<ReservedList>> cacheReservedLists =
|
||||
createCacheReservedLists(getDomainLabelListCacheDuration());
|
||||
|
||||
@VisibleForTesting
|
||||
static LoadingCache<String, Optional<ReservedList>> createCacheReservedLists(
|
||||
Duration cachePersistDuration) {
|
||||
return CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(cachePersistDuration.getMillis(), MILLISECONDS)
|
||||
.build(
|
||||
new CacheLoader<String, Optional<ReservedList>>() {
|
||||
@Override
|
||||
public Optional<ReservedList> load(String reservedListName) {
|
||||
return ReservedListDao.getLatestRevision(reservedListName);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.cmd.QueryKeys;
|
||||
import google.registry.flows.poll.PollFlowUtils;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.poll.PollMessage.Autorenew;
|
||||
import google.registry.model.poll.PollMessage.OneTime;
|
||||
@@ -49,8 +50,7 @@ import javax.inject.Inject;
|
||||
* delete confirmations) and it is desired that the registrar be able to ACK the rest of the poll
|
||||
* messages in-band.
|
||||
*
|
||||
* <p>This command only ACKs {@link OneTime} poll messages because that's our only use case so far,
|
||||
* but it could be extended to ACK {@link Autorenew} poll messages as well if needed. The main
|
||||
* <p>This command ACKs both {@link OneTime} and {@link Autorenew} poll messages. The main
|
||||
* difference is that one-time poll messages are deleted when ACKed whereas Autorenews are sometimes
|
||||
* modified and re-saved instead, if the corresponding domain is still active.
|
||||
*
|
||||
@@ -85,18 +85,17 @@ final class AckPollMessagesCommand implements CommandWithRemoteApi {
|
||||
@Override
|
||||
public void run() {
|
||||
QueryKeys<PollMessage> query = getPollMessagesQuery(clientId, clock.nowUtc()).keys();
|
||||
// TODO(b/160325686): Remove the batch logic after db migration.
|
||||
for (List<Key<PollMessage>> keys : Iterables.partition(query, BATCH_SIZE)) {
|
||||
tm()
|
||||
.transact(
|
||||
tm().transact(
|
||||
() -> {
|
||||
// Load poll messages and filter to just those of interest.
|
||||
ImmutableList<PollMessage> pollMessages =
|
||||
ofy().load().keys(keys).values().stream()
|
||||
.filter(pm -> pm instanceof OneTime)
|
||||
.filter(pm -> isNullOrEmpty(message) || pm.getMsg().contains(message))
|
||||
.collect(toImmutableList());
|
||||
if (!dryRun) {
|
||||
ofy().delete().entities(pollMessages).now();
|
||||
pollMessages.forEach(PollFlowUtils::ackPollMessage);
|
||||
}
|
||||
pollMessages.forEach(
|
||||
pm ->
|
||||
|
||||
@@ -50,7 +50,6 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Qualifier;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
@@ -151,10 +150,10 @@ public class AuthModule {
|
||||
public static String provideLocalCredentialJson(
|
||||
Lazy<GoogleClientSecrets> clientSecrets,
|
||||
@StoredCredential Lazy<Credential> credential,
|
||||
@Nullable @Named("credentialFileName") String credentialFilename) {
|
||||
@Nullable @Config("credentialFilePath") String credentialFilePath) {
|
||||
try {
|
||||
if (credentialFilename != null) {
|
||||
return new String(Files.readAllBytes(Paths.get(credentialFilename)), UTF_8);
|
||||
if (credentialFilePath != null) {
|
||||
return new String(Files.readAllBytes(Paths.get(credentialFilePath)), UTF_8);
|
||||
} else {
|
||||
return new Gson()
|
||||
.toJson(
|
||||
|
||||
@@ -14,23 +14,12 @@
|
||||
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.registry.label.BaseDomainLabelList.splitOnComment;
|
||||
import static google.registry.util.DomainNameUtils.canonicalizeDomainName;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.HashMultiset;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multiset;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.model.registry.label.ReservationType;
|
||||
import google.registry.schema.tld.ReservedList.ReservedEntry;
|
||||
import google.registry.model.registry.label.ReservedList;
|
||||
import google.registry.model.registry.label.ReservedListDualWriteDao;
|
||||
import google.registry.tools.params.PathParameter;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
@@ -62,69 +51,22 @@ public abstract class CreateOrUpdateReservedListCommand extends MutatingCommand
|
||||
arity = 1)
|
||||
Boolean shouldPublish;
|
||||
|
||||
google.registry.schema.tld.ReservedList cloudSqlReservedList;
|
||||
|
||||
abstract void saveToCloudSql();
|
||||
ReservedList reservedList;
|
||||
|
||||
@Override
|
||||
protected String execute() throws Exception {
|
||||
// Save the list to Datastore and output its response.
|
||||
String output = super.execute();
|
||||
logger.atInfo().log(output);
|
||||
|
||||
String cloudSqlMessage =
|
||||
protected String execute() {
|
||||
String message =
|
||||
String.format(
|
||||
"Saved reserved list %s with %d entries",
|
||||
name, cloudSqlReservedList.getLabelsToReservations().size());
|
||||
name, reservedList.getReservedListEntries().size());
|
||||
try {
|
||||
logger.atInfo().log("Saving reserved list to Cloud SQL for TLD %s", name);
|
||||
saveToCloudSql();
|
||||
logger.atInfo().log(cloudSqlMessage);
|
||||
logger.atInfo().log("Saving reserved list for TLD %s", name);
|
||||
ReservedListDualWriteDao.save(reservedList);
|
||||
logger.atInfo().log(message);
|
||||
} catch (Throwable e) {
|
||||
cloudSqlMessage =
|
||||
"Unexpected error saving reserved list to Cloud SQL from nomulus tool command";
|
||||
logger.atSevere().withCause(e).log(cloudSqlMessage);
|
||||
message = "Unexpected error saving reserved list from nomulus tool command";
|
||||
logger.atSevere().withCause(e).log(message);
|
||||
}
|
||||
return cloudSqlMessage;
|
||||
}
|
||||
|
||||
/** Turns the list CSV data into a map of labels to {@link ReservedEntry}. */
|
||||
static ImmutableMap<String, ReservedEntry> parseToReservationsByLabels(Iterable<String> lines) {
|
||||
Map<String, ReservedEntry> labelsToEntries = Maps.newHashMap();
|
||||
Multiset<String> duplicateLabels = HashMultiset.create();
|
||||
for (String originalLine : lines) {
|
||||
List<String> lineAndComment = splitOnComment(originalLine);
|
||||
if (lineAndComment.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
String line = lineAndComment.get(0);
|
||||
String comment = lineAndComment.get(1);
|
||||
List<String> parts = Splitter.on(',').trimResults().splitToList(line);
|
||||
checkArgument(
|
||||
parts.size() == 2 || parts.size() == 3,
|
||||
"Could not parse line in reserved list: %s",
|
||||
originalLine);
|
||||
String label = parts.get(0);
|
||||
checkArgument(
|
||||
label.equals(canonicalizeDomainName(label)),
|
||||
"Label '%s' must be in puny-coded, lower-case form",
|
||||
label);
|
||||
ReservationType reservationType = ReservationType.valueOf(parts.get(1));
|
||||
ReservedEntry reservedEntry = ReservedEntry.create(reservationType, comment);
|
||||
// Check if the label was already processed for this list (which is an error), and if so,
|
||||
// accumulate it so that a list of all duplicates can be thrown.
|
||||
if (labelsToEntries.containsKey(label)) {
|
||||
duplicateLabels.add(label, duplicateLabels.contains(label) ? 1 : 2);
|
||||
} else {
|
||||
labelsToEntries.put(label, reservedEntry);
|
||||
}
|
||||
}
|
||||
if (!duplicateLabels.isEmpty()) {
|
||||
throw new IllegalStateException(
|
||||
String.format(
|
||||
"Reserved list cannot contain duplicate labels. Dupes (with counts) were: %s",
|
||||
duplicateLabels));
|
||||
}
|
||||
return ImmutableMap.copyOf(labelsToEntries);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.registry.Registries.assertTldExists;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.util.ListNamingUtils.convertFilePathToName;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
@@ -27,7 +26,6 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import google.registry.model.registry.label.ReservedList;
|
||||
import google.registry.schema.tld.ReservedListDao;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import org.joda.time.DateTime;
|
||||
@@ -50,15 +48,14 @@ final class CreateReservedListCommand extends CreateOrUpdateReservedListCommand
|
||||
protected void init() throws Exception {
|
||||
name = Strings.isNullOrEmpty(name) ? convertFilePathToName(input) : name;
|
||||
checkArgument(
|
||||
!ReservedList.get(name).isPresent(),
|
||||
"A reserved list already exists by this name");
|
||||
!ReservedList.get(name).isPresent(), "A reserved list already exists by this name");
|
||||
if (!override) {
|
||||
validateListName(name);
|
||||
}
|
||||
DateTime now = DateTime.now(UTC);
|
||||
List<String> allLines = Files.readAllLines(input, UTF_8);
|
||||
boolean shouldPublish = this.shouldPublish == null || this.shouldPublish;
|
||||
ReservedList reservedList =
|
||||
reservedList =
|
||||
new ReservedList.Builder()
|
||||
.setName(name)
|
||||
.setReservedListMapFromLines(allLines)
|
||||
@@ -66,23 +63,6 @@ final class CreateReservedListCommand extends CreateOrUpdateReservedListCommand
|
||||
.setCreationTime(now)
|
||||
.setLastUpdateTime(now)
|
||||
.build();
|
||||
stageEntityChange(null, reservedList);
|
||||
cloudSqlReservedList =
|
||||
google.registry.schema.tld.ReservedList.create(
|
||||
name, shouldPublish, parseToReservationsByLabels(allLines));
|
||||
}
|
||||
|
||||
@Override
|
||||
void saveToCloudSql() {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
checkArgument(
|
||||
!ReservedListDao.checkExists(cloudSqlReservedList.getName()),
|
||||
"A reserved list of this name already exists: %s.",
|
||||
cloudSqlReservedList.getName());
|
||||
ReservedListDao.save(cloudSqlReservedList);
|
||||
});
|
||||
}
|
||||
|
||||
private static void validateListName(String name) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.batch.AsyncTaskEnqueuer;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
@@ -52,13 +53,16 @@ public final class DomainLockUtils {
|
||||
private static final int VERIFICATION_CODE_LENGTH = 32;
|
||||
|
||||
private final StringGenerator stringGenerator;
|
||||
private final String registryAdminRegistrarId;
|
||||
private final AsyncTaskEnqueuer asyncTaskEnqueuer;
|
||||
|
||||
@Inject
|
||||
public DomainLockUtils(
|
||||
@Named("base58StringGenerator") StringGenerator stringGenerator,
|
||||
@Config("registryAdminClientId") String registryAdminRegistrarId,
|
||||
AsyncTaskEnqueuer asyncTaskEnqueuer) {
|
||||
this.stringGenerator = stringGenerator;
|
||||
this.registryAdminRegistrarId = registryAdminRegistrarId;
|
||||
this.asyncTaskEnqueuer = asyncTaskEnqueuer;
|
||||
}
|
||||
|
||||
@@ -217,7 +221,7 @@ public final class DomainLockUtils {
|
||||
private RegistryLock.Builder createLockBuilder(
|
||||
String domainName, String registrarId, @Nullable String registrarPocId, boolean isAdmin) {
|
||||
DateTime now = jpaTm().getTransactionTime();
|
||||
DomainBase domainBase = getDomain(domainName, now);
|
||||
DomainBase domainBase = getDomain(domainName, registrarId, now);
|
||||
verifyDomainNotLocked(domainBase);
|
||||
|
||||
// Multiple pending actions are not allowed
|
||||
@@ -242,7 +246,7 @@ public final class DomainLockUtils {
|
||||
private RegistryLock.Builder createUnlockBuilder(
|
||||
String domainName, String registrarId, boolean isAdmin, Optional<Duration> relockDuration) {
|
||||
DateTime now = jpaTm().getTransactionTime();
|
||||
DomainBase domainBase = getDomain(domainName, now);
|
||||
DomainBase domainBase = getDomain(domainName, registrarId, now);
|
||||
Optional<RegistryLock> lockOptional =
|
||||
RegistryLockDao.getMostRecentVerifiedLockByRepoId(domainBase.getRepoId());
|
||||
|
||||
@@ -303,10 +307,19 @@ public final class DomainLockUtils {
|
||||
domainBase.getDomainName());
|
||||
}
|
||||
|
||||
private static DomainBase getDomain(String domainName, DateTime now) {
|
||||
return loadByForeignKeyCached(DomainBase.class, domainName, now)
|
||||
.orElseThrow(
|
||||
() -> new IllegalArgumentException(String.format("Unknown domain %s", domainName)));
|
||||
private DomainBase getDomain(String domainName, String registrarId, DateTime now) {
|
||||
DomainBase domain =
|
||||
loadByForeignKeyCached(DomainBase.class, domainName, now)
|
||||
.orElseThrow(
|
||||
() -> new IllegalArgumentException(String.format("Unknown domain %s", domainName)));
|
||||
// The user must have specified either the correct registrar ID or the admin registrar ID
|
||||
checkArgument(
|
||||
registryAdminRegistrarId.equals(registrarId)
|
||||
|| domain.getCurrentSponsorClientId().equals(registrarId),
|
||||
"Domain %s is not owned by registrar %s",
|
||||
domainName,
|
||||
registrarId);
|
||||
return domain;
|
||||
}
|
||||
|
||||
private static RegistryLock getByVerificationCode(String verificationCode) {
|
||||
@@ -317,8 +330,8 @@ public final class DomainLockUtils {
|
||||
String.format("Invalid verification code %s", verificationCode)));
|
||||
}
|
||||
|
||||
private static void applyLockStatuses(RegistryLock lock, DateTime lockTime) {
|
||||
DomainBase domain = getDomain(lock.getDomainName(), lockTime);
|
||||
private void applyLockStatuses(RegistryLock lock, DateTime lockTime) {
|
||||
DomainBase domain = getDomain(lock.getDomainName(), lock.getRegistrarId(), lockTime);
|
||||
verifyDomainNotLocked(domain);
|
||||
|
||||
DomainBase newDomain =
|
||||
@@ -330,8 +343,8 @@ public final class DomainLockUtils {
|
||||
saveEntities(newDomain, lock, lockTime, true);
|
||||
}
|
||||
|
||||
private static void removeLockStatuses(RegistryLock lock, boolean isAdmin, DateTime unlockTime) {
|
||||
DomainBase domain = getDomain(lock.getDomainName(), unlockTime);
|
||||
private void removeLockStatuses(RegistryLock lock, boolean isAdmin, DateTime unlockTime) {
|
||||
DomainBase domain = getDomain(lock.getDomainName(), lock.getRegistrarId(), unlockTime);
|
||||
if (!isAdmin) {
|
||||
verifyDomainLocked(domain);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.google.appengine.tools.remoteapi.RemoteApiOptions;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import google.registry.beam.initsql.BeamJpaModule;
|
||||
import google.registry.config.RegistryConfig;
|
||||
import google.registry.model.ofy.ObjectifyService;
|
||||
import google.registry.persistence.transaction.TransactionManagerFactory;
|
||||
@@ -153,11 +154,15 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
|
||||
return;
|
||||
}
|
||||
|
||||
checkState(RegistryToolEnvironment.get() == environment,
|
||||
checkState(
|
||||
RegistryToolEnvironment.get() == environment,
|
||||
"RegistryToolEnvironment argument pre-processing kludge failed.");
|
||||
|
||||
component =
|
||||
DaggerRegistryToolComponent.builder().credentialFilename(credentialJson).build();
|
||||
DaggerRegistryToolComponent.builder()
|
||||
.credentialFilePath(credentialJson)
|
||||
.beamJpaModule(new BeamJpaModule(credentialJson))
|
||||
.build();
|
||||
|
||||
// JCommander stores sub-commands as nested JCommander objects containing a list of user objects
|
||||
// to be populated. Extract the subcommand by getting the JCommander wrapper and then
|
||||
|
||||
@@ -18,8 +18,10 @@ import dagger.BindsInstance;
|
||||
import dagger.Component;
|
||||
import dagger.Lazy;
|
||||
import google.registry.batch.BatchModule;
|
||||
import google.registry.beam.initsql.BeamJpaModule;
|
||||
import google.registry.bigquery.BigqueryModule;
|
||||
import google.registry.config.CredentialModule.LocalCredentialJson;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.config.RegistryConfig.ConfigModule;
|
||||
import google.registry.dns.writer.VoidDnsWriterModule;
|
||||
import google.registry.dns.writer.clouddns.CloudDnsWriterModule;
|
||||
@@ -42,7 +44,6 @@ import google.registry.tools.AuthModule.LocalCredentialModule;
|
||||
import google.registry.util.UtilsModule;
|
||||
import google.registry.whois.WhoisModule;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/**
|
||||
@@ -57,6 +58,7 @@ import javax.inject.Singleton;
|
||||
AppEngineAdminApiModule.class,
|
||||
AuthModule.class,
|
||||
BatchModule.class,
|
||||
BeamJpaModule.class,
|
||||
BigqueryModule.class,
|
||||
ConfigModule.class,
|
||||
CloudDnsWriterModule.class,
|
||||
@@ -130,7 +132,9 @@ interface RegistryToolComponent {
|
||||
@Component.Builder
|
||||
interface Builder {
|
||||
@BindsInstance
|
||||
Builder credentialFilename(@Nullable @Named("credentialFileName") String credentialFilename);
|
||||
Builder credentialFilePath(@Nullable @Config("credentialFilePath") String credentialFilePath);
|
||||
|
||||
Builder beamJpaModule(BeamJpaModule beamJpaModule);
|
||||
|
||||
RegistryToolComponent build();
|
||||
}
|
||||
|
||||
@@ -15,18 +15,17 @@
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.util.ListNamingUtils.convertFilePathToName;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.base.Strings;
|
||||
import google.registry.model.registry.label.ReservedList;
|
||||
import google.registry.schema.tld.ReservedListDao;
|
||||
import google.registry.util.SystemClock;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Command to safely update {@link ReservedList} on Datastore. */
|
||||
@Parameters(separators = " =", commandDescription = "Update a ReservedList in Datastore.")
|
||||
@@ -35,42 +34,20 @@ final class UpdateReservedListCommand extends CreateOrUpdateReservedListCommand
|
||||
@Override
|
||||
protected void init() throws Exception {
|
||||
name = Strings.isNullOrEmpty(name) ? convertFilePathToName(input) : name;
|
||||
// TODO(shicong): Read existing entry from Cloud SQL
|
||||
Optional<ReservedList> existing = ReservedList.get(name);
|
||||
checkArgument(
|
||||
existing.isPresent(), "Could not update reserved list %s because it doesn't exist.", name);
|
||||
boolean shouldPublish =
|
||||
this.shouldPublish == null ? existing.get().getShouldPublish() : this.shouldPublish;
|
||||
List<String> allLines = Files.readAllLines(input, UTF_8);
|
||||
DateTime now = new SystemClock().nowUtc();
|
||||
ReservedList.Builder updated =
|
||||
existing
|
||||
.get()
|
||||
.asBuilder()
|
||||
.setReservedListMapFromLines(allLines)
|
||||
.setLastUpdateTime(new SystemClock().nowUtc())
|
||||
.setLastUpdateTime(now)
|
||||
.setShouldPublish(shouldPublish);
|
||||
stageEntityChange(existing.get(), updated.build());
|
||||
cloudSqlReservedList =
|
||||
google.registry.schema.tld.ReservedList.create(
|
||||
name, shouldPublish, parseToReservationsByLabels(allLines));
|
||||
}
|
||||
|
||||
@Override
|
||||
void saveToCloudSql() {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
// This check is currently disabled because, during the Cloud SQL migration, we need
|
||||
// to be able to update reserved lists in Datastore while simultaneously creating
|
||||
// their first revision in Cloud SQL (i.e. if they haven't been migrated over yet).
|
||||
// TODO(shicong): Re-instate this once all reserved lists are migrated to Cloud SQL,
|
||||
// and add a unit test to verity that an exception will be thrown if
|
||||
// the reserved list doesn't exist.
|
||||
// checkArgument(
|
||||
// ReservedListDao.checkExists(cloudSqlReservedList.getName()),
|
||||
// "A reserved list of this name doesn't exist: %s.",
|
||||
// cloudSqlReservedList.getName());
|
||||
ReservedListDao.save(cloudSqlReservedList);
|
||||
});
|
||||
reservedList = updated.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,7 +454,13 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new FormException(
|
||||
"Not allowed to set registry lock password directly on new contact"));
|
||||
"Cannot set registry lock password directly on new contact"));
|
||||
// Can't modify registry lock email address
|
||||
if (!Objects.equals(
|
||||
updatedContact.getRegistryLockEmailAddress(),
|
||||
existingContact.getRegistryLockEmailAddress())) {
|
||||
throw new FormException("Cannot modify registryLockEmailAddress through the UI");
|
||||
}
|
||||
if (updatedContact.isRegistryLockAllowed()) {
|
||||
// the password must have been set before or the user was allowed to set it now
|
||||
if (!existingContact.isAllowedToSetRegistryLockPassword()
|
||||
@@ -464,7 +470,8 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||
}
|
||||
if (updatedContact.isAllowedToSetRegistryLockPassword()) {
|
||||
if (!existingContact.isAllowedToSetRegistryLockPassword()) {
|
||||
throw new FormException("Cannot set isAllowedToSetRegistryLockPassword through UI");
|
||||
throw new FormException(
|
||||
"Cannot modify isAllowedToSetRegistryLockPassword through the UI");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.security.JsonResponseHelper.Status.ERROR;
|
||||
import static google.registry.security.JsonResponseHelper.Status.SUCCESS;
|
||||
import static google.registry.ui.server.registrar.RegistrarConsoleModule.PARAM_CLIENT_ID;
|
||||
import static google.registry.ui.server.registrar.RegistryLockGetAction.getContactMatchingLogin;
|
||||
import static google.registry.ui.server.registrar.RegistryLockGetAction.getRegistrarAndVerifyLockAccess;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
@@ -116,10 +115,8 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
checkArgumentNotNull(input, "Null JSON");
|
||||
RegistryLockPostInput postInput =
|
||||
GSON.fromJson(GSON.toJsonTree(input), RegistryLockPostInput.class);
|
||||
checkArgument(
|
||||
!Strings.isNullOrEmpty(postInput.clientId),
|
||||
"Missing key for client: %s",
|
||||
PARAM_CLIENT_ID);
|
||||
String registrarId = postInput.registrarId;
|
||||
checkArgument(!Strings.isNullOrEmpty(registrarId), "Missing key for registrarId");
|
||||
checkArgument(!Strings.isNullOrEmpty(postInput.domainName), "Missing key for domainName");
|
||||
checkNotNull(postInput.isLock, "Missing key for isLock");
|
||||
UserAuthInfo userAuthInfo =
|
||||
@@ -135,12 +132,12 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
postInput.isLock
|
||||
? domainLockUtils.saveNewRegistryLockRequest(
|
||||
postInput.domainName,
|
||||
postInput.clientId,
|
||||
registrarId,
|
||||
userEmail,
|
||||
registrarAccessor.isAdmin())
|
||||
: domainLockUtils.saveNewRegistryUnlockRequest(
|
||||
postInput.domainName,
|
||||
postInput.clientId,
|
||||
registrarId,
|
||||
registrarAccessor.isAdmin(),
|
||||
Optional.ofNullable(postInput.relockDurationMillis).map(Duration::new));
|
||||
sendVerificationEmail(registryLock, userEmail, postInput.isLock);
|
||||
@@ -190,9 +187,9 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
return user.getEmail();
|
||||
}
|
||||
// Verify that the user can access the registrar, that the user has
|
||||
// registry lock enabled, and that the user providjed a correct password
|
||||
// registry lock enabled, and that the user provided a correct password
|
||||
Registrar registrar =
|
||||
getRegistrarAndVerifyLockAccess(registrarAccessor, postInput.clientId, false);
|
||||
getRegistrarAndVerifyLockAccess(registrarAccessor, postInput.registrarId, false);
|
||||
RegistrarContact registrarContact =
|
||||
getContactMatchingLogin(user, registrar)
|
||||
.orElseThrow(
|
||||
@@ -215,7 +212,7 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
|
||||
/** Value class that represents the expected input body from the UI request. */
|
||||
private static class RegistryLockPostInput {
|
||||
private String clientId;
|
||||
private String registrarId;
|
||||
private String domainName;
|
||||
private Boolean isLock;
|
||||
private String password;
|
||||
|
||||
@@ -180,7 +180,8 @@ registry.json.RegistrarAddress;
|
||||
* faxNumber: (string?|undefined),
|
||||
* types: (string?|undefined),
|
||||
* allowedToSetRegistryLockPassword: boolean,
|
||||
* registryLockAllowed: boolean
|
||||
* registryLockAllowed: boolean,
|
||||
* registryLockEmailAddress: (string?|undefined)
|
||||
* }}
|
||||
*/
|
||||
registry.json.RegistrarContact;
|
||||
|
||||
@@ -106,6 +106,7 @@ registry.registrar.ContactSettings.prototype.renderItem = function(rspObj) {
|
||||
registryLockAllowedForRegistrar: rspObj.registryLockAllowed
|
||||
});
|
||||
this.setupAppbar();
|
||||
this.setupPasswordElemIfNecessary_(targetContactNdx);
|
||||
} else {
|
||||
var contactsByType = {};
|
||||
for (var c in contacts) {
|
||||
@@ -251,3 +252,26 @@ registry.registrar.ContactSettings.prototype.handleDeleteResponse =
|
||||
}
|
||||
return rsp;
|
||||
};
|
||||
|
||||
// Show or hide the password based on what the user chooses
|
||||
registry.registrar.ContactSettings.prototype.setupPasswordElemIfNecessary_ =
|
||||
function(contactIndex) {
|
||||
var showOrHidePasswordButton = goog.dom.getElement('showOrHideRegistryLockPassword')
|
||||
var showOrHidePassword = function() {
|
||||
var inputElement = goog.dom.getRequiredElement(
|
||||
'contacts[' + contactIndex + '].registryLockPassword')
|
||||
var type = inputElement.getAttribute('type')
|
||||
if (type === 'password') {
|
||||
showOrHidePasswordButton.text = 'Hide password';
|
||||
inputElement.setAttribute('type', 'text');
|
||||
} else {
|
||||
showOrHidePasswordButton.text = 'Show password';
|
||||
inputElement.setAttribute('type', 'password');
|
||||
}
|
||||
};
|
||||
|
||||
if (showOrHidePasswordButton != null) {
|
||||
goog.events.listen(showOrHidePasswordButton,
|
||||
goog.events.EventType.CLICK, showOrHidePassword, false, this);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -172,7 +172,7 @@ registry.registrar.RegistryLock.prototype.lockOrUnlockDomain_ = function(isLock,
|
||||
e => this.fillLocksPage_(e),
|
||||
'POST',
|
||||
goog.json.serialize({
|
||||
'clientId': this.clientId,
|
||||
'registrarId': this.clientId,
|
||||
'domainName': domain,
|
||||
'isLock': isLock,
|
||||
'password': password,
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<class>google.registry.model.billing.BillingEvent$Cancellation</class>
|
||||
<class>google.registry.model.billing.BillingEvent$OneTime</class>
|
||||
<class>google.registry.model.billing.BillingEvent$Recurring</class>
|
||||
<class>google.registry.model.contact.ContactHistory</class>
|
||||
<class>google.registry.model.contact.ContactResource</class>
|
||||
<class>google.registry.model.domain.DomainBase</class>
|
||||
<class>google.registry.model.host.HostHistory</class>
|
||||
@@ -35,12 +36,12 @@
|
||||
<class>google.registry.schema.server.Lock</class>
|
||||
<class>google.registry.schema.tld.PremiumList</class>
|
||||
<class>google.registry.schema.tld.PremiumEntry</class>
|
||||
<class>google.registry.schema.tld.ReservedList</class>
|
||||
<class>google.registry.model.domain.secdns.DelegationSignerData</class>
|
||||
<class>google.registry.model.domain.GracePeriod</class>
|
||||
<class>google.registry.model.poll.PollMessage</class>
|
||||
<class>google.registry.model.poll.PollMessage$OneTime</class>
|
||||
<class>google.registry.model.poll.PollMessage$Autorenew</class>
|
||||
<class>google.registry.model.registry.label.ReservedList</class>
|
||||
|
||||
<!-- Customized type converters -->
|
||||
<class>google.registry.persistence.converter.BillingCostTransitionConverter</class>
|
||||
|
||||
@@ -176,6 +176,10 @@
|
||||
{if isNonnull($item['gaeUserId'])}
|
||||
<input type="hidden" name="{$namePrefix}gaeUserId" value="{$item['gaeUserId']}">
|
||||
{/if}
|
||||
{if isNonnull($item['registryLockEmailAddress'])}
|
||||
<input type="hidden" name="{$namePrefix}registryLockEmailAddress"
|
||||
value="{$item['registryLockEmailAddress']}">
|
||||
{/if}
|
||||
</div>
|
||||
{/template}
|
||||
|
||||
@@ -256,6 +260,15 @@
|
||||
{param isPassword: true /}
|
||||
{param placeholder: $placeholder /}
|
||||
{/call}
|
||||
{if $item['allowedToSetRegistryLockPassword']}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<a id="showOrHideRegistryLockPassword">Show password</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
|
||||
{/if}
|
||||
<input type="hidden" name="{$namePrefix}allowedToSetRegistryLockPassword"
|
||||
{if isNonnull($item['allowedToSetRegistryLockPassword'])}
|
||||
|
||||
@@ -43,7 +43,6 @@ import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeSleeper;
|
||||
import google.registry.testing.InjectRule;
|
||||
import google.registry.testing.ShardableTestCase;
|
||||
import google.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import google.registry.util.AppEngineServiceUtils;
|
||||
import google.registry.util.CapturingLogHandler;
|
||||
@@ -62,7 +61,7 @@ import org.mockito.junit.MockitoRule;
|
||||
|
||||
/** Unit tests for {@link AsyncTaskEnqueuer}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class AsyncTaskEnqueuerTest extends ShardableTestCase {
|
||||
public class AsyncTaskEnqueuerTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine =
|
||||
|
||||
@@ -21,14 +21,13 @@ import static google.registry.batch.AsyncTaskMetrics.OperationType.CONTACT_AND_H
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.ShardableTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link AsyncTaskMetrics}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class AsyncTaskMetricsTest extends ShardableTestCase {
|
||||
public class AsyncTaskMetricsTest {
|
||||
|
||||
private final FakeClock clock = new FakeClock();
|
||||
private final AsyncTaskMetrics asyncTaskMetrics = new AsyncTaskMetrics(clock);
|
||||
|
||||
@@ -63,6 +63,7 @@ public class RelockDomainActionTest {
|
||||
private final DomainLockUtils domainLockUtils =
|
||||
new DomainLockUtils(
|
||||
new DeterministicStringGenerator(Alphabets.BASE_58),
|
||||
"adminreg",
|
||||
AsyncTaskEnqueuerTest.createForTesting(
|
||||
mock(AppEngineServiceUtils.class), clock, Duration.ZERO));
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ import google.registry.request.Response;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.InjectRule;
|
||||
import google.registry.testing.ShardableTestCase;
|
||||
import google.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import google.registry.util.AppEngineServiceUtils;
|
||||
import org.joda.time.DateTime;
|
||||
@@ -61,7 +60,7 @@ import org.mockito.junit.MockitoRule;
|
||||
|
||||
/** Unit tests for {@link ResaveEntityAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class ResaveEntityActionTest extends ShardableTestCase {
|
||||
public class ResaveEntityActionTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine =
|
||||
|
||||
@@ -15,45 +15,48 @@
|
||||
package google.registry.beam.initsql;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assume.assumeThat;
|
||||
|
||||
import google.registry.persistence.NomulusPostgreSql;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.testing.DatastoreEntityExtension;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import org.apache.beam.sdk.io.FileSystems;
|
||||
import org.apache.beam.sdk.options.PipelineOptionsFactory;
|
||||
import org.junit.Before;
|
||||
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.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
/** Unit tests for {@link BeamJpaModule}. */
|
||||
@RunWith(JUnit4.class) // TODO(weiminyu): upgrade to JUnit 5.
|
||||
@Testcontainers
|
||||
public class BeamJpaModuleTest {
|
||||
|
||||
@Rule
|
||||
@Container
|
||||
public PostgreSQLContainer database = new PostgreSQLContainer(NomulusPostgreSql.getDockerTag());
|
||||
|
||||
@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
@RegisterExtension
|
||||
public DatastoreEntityExtension datastoreEntityExtension = new DatastoreEntityExtension();
|
||||
|
||||
@TempDir File tempFolder;
|
||||
|
||||
private File credentialFile;
|
||||
|
||||
@Before
|
||||
@BeforeEach
|
||||
public void beforeEach() throws IOException {
|
||||
credentialFile = temporaryFolder.newFile();
|
||||
credentialFile = new File(tempFolder, "credential");
|
||||
new PrintStream(credentialFile)
|
||||
.printf("%s %s %s", database.getJdbcUrl(), database.getUsername(), database.getPassword())
|
||||
.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getJpaTransactionManager_local() {
|
||||
void getJpaTransactionManager_local() {
|
||||
JpaTransactionManager jpa =
|
||||
DaggerBeamJpaModule_JpaTransactionManagerComponent.builder()
|
||||
.beamJpaModule(new BeamJpaModule(credentialFile.getAbsolutePath()))
|
||||
@@ -76,10 +79,9 @@ public class BeamJpaModuleTest {
|
||||
* information.
|
||||
*/
|
||||
@Test
|
||||
@EnabledIfSystemProperty(named = "test.gcp_integration.env", matches = "\\S+")
|
||||
public void getJpaTransactionManager_cloudSql_authRequired() {
|
||||
String environmentName = System.getProperty("test.gcp_integration.env");
|
||||
assumeThat(environmentName, notNullValue());
|
||||
|
||||
FileSystems.setDefaultPipelineOptions(PipelineOptionsFactory.create());
|
||||
JpaTransactionManager jpa =
|
||||
DaggerBeamJpaModule_JpaTransactionManagerComponent.builder()
|
||||
|
||||
@@ -19,6 +19,7 @@ import static google.registry.testing.DatastoreHelper.newDomainBase;
|
||||
import static google.registry.testing.DatastoreHelper.newRegistry;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.backup.VersionedEntity;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
@@ -27,6 +28,7 @@ import google.registry.model.registry.Registry;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.InjectRule;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import org.apache.beam.sdk.coders.StringUtf8Coder;
|
||||
import org.apache.beam.sdk.io.fs.MatchResult.Metadata;
|
||||
@@ -152,28 +154,45 @@ public class CommitLogTransformsTest implements Serializable {
|
||||
|
||||
@Test
|
||||
@Category(NeedsRunner.class)
|
||||
public void filterCommitLogsByTime() {
|
||||
public void filterCommitLogsByTime() throws IOException {
|
||||
ImmutableList<String> commitLogFilenames =
|
||||
ImmutableList.of(
|
||||
"/commit_diff_until_2000-01-01T00:00:00.000Z",
|
||||
"/commit_diff_until_2000-01-01T00:00:00.001Z",
|
||||
"/commit_diff_until_2000-01-01T00:00:00.002Z",
|
||||
"/commit_diff_until_2000-01-01T00:00:00.003Z",
|
||||
"/commit_diff_until_2000-01-01T00:00:00.004Z");
|
||||
"commit_diff_until_2000-01-01T00:00:00.000Z",
|
||||
"commit_diff_until_2000-01-01T00:00:00.001Z",
|
||||
"commit_diff_until_2000-01-01T00:00:00.002Z",
|
||||
"commit_diff_until_2000-01-01T00:00:00.003Z",
|
||||
"commit_diff_until_2000-01-01T00:00:00.004Z");
|
||||
|
||||
File commitLogDir = temporaryFolder.newFolder();
|
||||
for (String name : commitLogFilenames) {
|
||||
new File(commitLogDir, name).createNewFile();
|
||||
}
|
||||
|
||||
PCollection<String> filteredFilenames =
|
||||
pipeline
|
||||
.apply(
|
||||
"Generate All Filenames",
|
||||
Create.of(commitLogFilenames).withCoder(StringUtf8Coder.of()))
|
||||
"Get commitlog file patterns",
|
||||
Transforms.getCommitLogFilePatterns(commitLogDir.getAbsolutePath()))
|
||||
.apply("Find commitlog files", Transforms.getFilesByPatterns())
|
||||
.apply(
|
||||
"Filtered by Time",
|
||||
Transforms.filterCommitLogsByTime(
|
||||
DateTime.parse("2000-01-01T00:00:00.001Z"),
|
||||
DateTime.parse("2000-01-01T00:00:00.003Z")));
|
||||
DateTime.parse("2000-01-01T00:00:00.003Z")))
|
||||
.apply(
|
||||
"Extract path strings",
|
||||
ParDo.of(
|
||||
new DoFn<Metadata, String>() {
|
||||
@ProcessElement
|
||||
public void processElement(
|
||||
@Element Metadata fileMeta, OutputReceiver<String> out) {
|
||||
out.output(fileMeta.resourceId().getFilename());
|
||||
}
|
||||
}));
|
||||
PAssert.that(filteredFilenames)
|
||||
.containsInAnyOrder(
|
||||
"/commit_diff_until_2000-01-01T00:00:00.001Z",
|
||||
"/commit_diff_until_2000-01-01T00:00:00.002Z");
|
||||
"commit_diff_until_2000-01-01T00:00:00.001Z",
|
||||
"commit_diff_until_2000-01-01T00:00:00.002Z");
|
||||
|
||||
pipeline.run();
|
||||
}
|
||||
@@ -187,7 +206,9 @@ public class CommitLogTransformsTest implements Serializable {
|
||||
"Get CommitLog file patterns",
|
||||
Transforms.getCommitLogFilePatterns(commitLogsDir.getAbsolutePath()))
|
||||
.apply("Find CommitLogs", Transforms.getFilesByPatterns())
|
||||
.apply(Transforms.loadCommitLogsFromFiles());
|
||||
.apply(
|
||||
Transforms.loadCommitLogsFromFiles(
|
||||
ImmutableSet.of("Registry", "ContactResource", "DomainBase")));
|
||||
|
||||
InitSqlTestUtils.assertContainsExactlyElementsIn(
|
||||
entities,
|
||||
@@ -197,4 +218,24 @@ public class CommitLogTransformsTest implements Serializable {
|
||||
|
||||
pipeline.run();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Category(NeedsRunner.class)
|
||||
public void loadOneCommitLogFile_filterByKind() {
|
||||
PCollection<VersionedEntity> entities =
|
||||
pipeline
|
||||
.apply(
|
||||
"Get CommitLog file patterns",
|
||||
Transforms.getCommitLogFilePatterns(commitLogsDir.getAbsolutePath()))
|
||||
.apply("Find CommitLogs", Transforms.getFilesByPatterns())
|
||||
.apply(
|
||||
Transforms.loadCommitLogsFromFiles(ImmutableSet.of("Registry", "ContactResource")));
|
||||
|
||||
InitSqlTestUtils.assertContainsExactlyElementsIn(
|
||||
entities,
|
||||
KV.of(fakeClock.nowUtc().getMillis() - 2, store.loadAsDatastoreEntity(registry)),
|
||||
KV.of(fakeClock.nowUtc().getMillis() - 1, store.loadAsDatastoreEntity(contact)));
|
||||
|
||||
pipeline.run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import static google.registry.testing.DatastoreHelper.newDomainBase;
|
||||
import static google.registry.testing.DatastoreHelper.newRegistry;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.backup.VersionedEntity;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
@@ -63,8 +64,8 @@ public class ExportloadingTransformsTest implements Serializable {
|
||||
|
||||
private static final ImmutableList<Class<?>> ALL_KINDS =
|
||||
ImmutableList.of(Registry.class, ContactResource.class, DomainBase.class);
|
||||
private static final ImmutableList<String> ALL_KIND_STRS =
|
||||
ALL_KINDS.stream().map(Key::getKind).collect(ImmutableList.toImmutableList());
|
||||
private static final ImmutableSet<String> ALL_KIND_STRS =
|
||||
ALL_KINDS.stream().map(Key::getKind).collect(ImmutableSet.toImmutableSet());
|
||||
|
||||
@Rule public final transient TemporaryFolder exportRootDir = new TemporaryFolder();
|
||||
|
||||
@@ -172,6 +173,7 @@ public class ExportloadingTransformsTest implements Serializable {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Category(NeedsRunner.class)
|
||||
public void loadDataFromFiles() {
|
||||
PCollection<VersionedEntity> entities =
|
||||
pipeline
|
||||
|
||||
@@ -30,6 +30,7 @@ import google.registry.backup.AppEngineEnvironment;
|
||||
import google.registry.backup.VersionedEntity;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
import org.apache.beam.sdk.testing.PAssert;
|
||||
import org.apache.beam.sdk.transforms.DoFn;
|
||||
@@ -43,6 +44,9 @@ import org.apache.beam.sdk.values.TypeDescriptor;
|
||||
/** Test helpers for populating SQL with Datastore backups. */
|
||||
public final class InitSqlTestUtils {
|
||||
|
||||
// Generates unique ids to distinguish reused transforms.
|
||||
private static final AtomicInteger TRANSFORM_ID_GEN = new AtomicInteger(0);
|
||||
|
||||
/** Converts a Datastore {@link Entity} to an Objectify entity. */
|
||||
public static Object datastoreToOfyEntity(Entity entity) {
|
||||
return ofy().load().fromEntity(entity);
|
||||
@@ -114,11 +118,12 @@ public final class InitSqlTestUtils {
|
||||
PCollection<String> errMsgs =
|
||||
actual
|
||||
.apply(
|
||||
"MapElements_" + TRANSFORM_ID_GEN.getAndIncrement(),
|
||||
MapElements.into(kvs(strings(), TypeDescriptor.of(VersionedEntity.class)))
|
||||
.via(rawEntity -> KV.of("The One Key", rawEntity)))
|
||||
.apply(GroupByKey.create())
|
||||
.apply("GroupByKey_" + TRANSFORM_ID_GEN.getAndIncrement(), GroupByKey.create())
|
||||
.apply(
|
||||
"assertContainsExactlyElementsIn",
|
||||
"assertContainsExactlyElementsIn_" + TRANSFORM_ID_GEN.getAndIncrement(),
|
||||
ParDo.of(
|
||||
new DoFn<KV<String, Iterable<VersionedEntity>>, String>() {
|
||||
@ProcessElement
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.beam.initsql;
|
||||
|
||||
import static google.registry.testing.DatastoreHelper.newContactResource;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainBase;
|
||||
import static google.registry.testing.DatastoreHelper.newRegistry;
|
||||
|
||||
import com.google.appengine.api.datastore.Entity;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DomainAuthInfo;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import google.registry.model.ofy.Ofy;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.InjectRule;
|
||||
import java.io.File;
|
||||
import org.apache.beam.sdk.testing.NeedsRunner;
|
||||
import org.apache.beam.sdk.testing.TestPipeline;
|
||||
import org.apache.beam.sdk.values.KV;
|
||||
import org.apache.beam.sdk.values.PCollectionTuple;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/**
|
||||
* Unit test for {@link Transforms#loadDatastoreSnapshot}.
|
||||
*
|
||||
* <p>The test setup involves three entities, one Registry, one Domain, and two Contacts. Events
|
||||
* happen in the following order:
|
||||
*
|
||||
* <ol>
|
||||
* <li>Registry and a filler Contact are inserted to Datastore.
|
||||
* <li>A CommitLog is persisted.
|
||||
* <li>Registry is updated.
|
||||
* <li>Another Contact and Domain are inserted into Datastore.
|
||||
* <li>Datastore is exported, but misses the newly inserted Contact.
|
||||
* <li>Filler Contact is deleted.
|
||||
* <li>A second CommitLog is persisted.
|
||||
* <li>Domain is updated in the Datastore.
|
||||
* <li>The third and last CommitLog is persisted.
|
||||
* </ol>
|
||||
*
|
||||
* The final snapshot includes Registry, Domain, and Contact. This scenario verifies that:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Incremental changes committed before an export does not override the exported valie.
|
||||
* <li>Entity missed by an export can be recovered from later CommitLogs.
|
||||
* <li>Multiple changes to an entity is applied in order.
|
||||
* <li>Deletes are properly handled.
|
||||
* </ul>
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class LoadDatastoreSnapshotTest {
|
||||
private static final DateTime START_TIME = DateTime.parse("2000-01-01T00:00:00.0Z");
|
||||
|
||||
private static final ImmutableList<Class<?>> ALL_KINDS =
|
||||
ImmutableList.of(Registry.class, ContactResource.class, DomainBase.class);
|
||||
private static final ImmutableSet<String> ALL_KIND_STRS =
|
||||
ALL_KINDS.stream().map(Key::getKind).collect(ImmutableSet.toImmutableSet());
|
||||
|
||||
@Rule public final transient TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
@Rule public final transient InjectRule injectRule = new InjectRule();
|
||||
|
||||
@Rule
|
||||
public final transient TestPipeline pipeline =
|
||||
TestPipeline.create().enableAbandonedNodeEnforcement(true);
|
||||
|
||||
private FakeClock fakeClock;
|
||||
private File exportRootDir;
|
||||
private File exportDir;
|
||||
private File commitLogsDir;
|
||||
|
||||
// Canned data:
|
||||
private transient Entity dsRegistry;
|
||||
private transient Entity dsContact;
|
||||
private transient Entity dsDomain;
|
||||
|
||||
private transient DateTime registryLastUpdateTime;
|
||||
private transient DateTime contactLastUpdateTime;
|
||||
private transient DateTime domainLastUpdateTime;
|
||||
|
||||
@Before
|
||||
public void beforeEach() throws Exception {
|
||||
fakeClock = new FakeClock(START_TIME);
|
||||
try (BackupTestStore store = new BackupTestStore(fakeClock)) {
|
||||
injectRule.setStaticField(Ofy.class, "clock", fakeClock);
|
||||
|
||||
exportRootDir = temporaryFolder.newFolder();
|
||||
commitLogsDir = temporaryFolder.newFolder();
|
||||
|
||||
Registry registry = newRegistry("tld1", "TLD1");
|
||||
ContactResource fillerContact = newContactResource("contact_filler");
|
||||
store.insertOrUpdate(registry, fillerContact);
|
||||
store.saveCommitLogs(commitLogsDir.getAbsolutePath());
|
||||
|
||||
registry =
|
||||
registry
|
||||
.asBuilder()
|
||||
.setCreateBillingCost(registry.getStandardCreateCost().plus(1.0d))
|
||||
.build();
|
||||
registryLastUpdateTime = fakeClock.nowUtc();
|
||||
store.insertOrUpdate(registry);
|
||||
|
||||
ContactResource contact = newContactResource("contact");
|
||||
DomainBase domain = newDomainBase("domain1.tld1", contact);
|
||||
contactLastUpdateTime = fakeClock.nowUtc();
|
||||
store.insertOrUpdate(contact, domain);
|
||||
exportDir =
|
||||
store.export(
|
||||
exportRootDir.getAbsolutePath(), ALL_KINDS, ImmutableSet.of(Key.create(contact)));
|
||||
|
||||
store.delete(fillerContact);
|
||||
store.saveCommitLogs(commitLogsDir.getAbsolutePath());
|
||||
|
||||
domain =
|
||||
domain
|
||||
.asBuilder()
|
||||
.setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("NewPass")))
|
||||
.build();
|
||||
domainLastUpdateTime = fakeClock.nowUtc();
|
||||
store.insertOrUpdate(domain);
|
||||
store.saveCommitLogs(commitLogsDir.getAbsolutePath());
|
||||
|
||||
fakeClock.advanceOneMilli();
|
||||
|
||||
// Save persisted data for assertions.
|
||||
dsRegistry = store.loadAsDatastoreEntity(registry);
|
||||
dsContact = store.loadAsDatastoreEntity(contact);
|
||||
dsDomain = store.loadAsDatastoreEntity(domain);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Category(NeedsRunner.class)
|
||||
public void loadDatastoreSnapshot() {
|
||||
PCollectionTuple snapshot =
|
||||
pipeline.apply(
|
||||
Transforms.loadDatastoreSnapshot(
|
||||
exportDir.getAbsolutePath(),
|
||||
commitLogsDir.getAbsolutePath(),
|
||||
START_TIME,
|
||||
fakeClock.nowUtc(),
|
||||
ALL_KIND_STRS));
|
||||
InitSqlTestUtils.assertContainsExactlyElementsIn(
|
||||
snapshot.get(Transforms.createTagForKind("DomainBase")),
|
||||
KV.of(domainLastUpdateTime.getMillis(), dsDomain));
|
||||
InitSqlTestUtils.assertContainsExactlyElementsIn(
|
||||
snapshot.get(Transforms.createTagForKind("Registry")),
|
||||
KV.of(registryLastUpdateTime.getMillis(), dsRegistry));
|
||||
InitSqlTestUtils.assertContainsExactlyElementsIn(
|
||||
snapshot.get(Transforms.createTagForKind("ContactResource")),
|
||||
KV.of(contactLastUpdateTime.getMillis(), dsContact));
|
||||
pipeline.run();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.beam.initsql;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import com.google.appengine.api.datastore.Entity;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.backup.VersionedEntity;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.ofy.Ofy;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationTestRule;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.DatastoreHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.InjectRule;
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.beam.sdk.testing.NeedsRunner;
|
||||
import org.apache.beam.sdk.testing.TestPipeline;
|
||||
import org.apache.beam.sdk.transforms.Create;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit test for {@link Transforms#writeToSql}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class WriteToSqlTest implements Serializable {
|
||||
private static final DateTime START_TIME = DateTime.parse("2000-01-01T00:00:00.0Z");
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock(START_TIME);
|
||||
|
||||
@Rule public final transient InjectRule injectRule = new InjectRule();
|
||||
|
||||
@Rule
|
||||
public transient JpaIntegrationTestRule jpaRule =
|
||||
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationTestRule();
|
||||
|
||||
@Rule public transient TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||
|
||||
@Rule
|
||||
public final transient TestPipeline pipeline =
|
||||
TestPipeline.create().enableAbandonedNodeEnforcement(true);
|
||||
|
||||
private ImmutableList<Entity> contacts;
|
||||
|
||||
private File credentialFile;
|
||||
|
||||
@Before
|
||||
public void beforeEach() throws Exception {
|
||||
try (BackupTestStore store = new BackupTestStore(fakeClock)) {
|
||||
injectRule.setStaticField(Ofy.class, "clock", fakeClock);
|
||||
|
||||
// Required for contacts created below.
|
||||
Registrar ofyRegistrar = AppEngineRule.makeRegistrar2();
|
||||
store.insertOrUpdate(ofyRegistrar);
|
||||
jpaTm().transact(() -> jpaTm().saveNewOrUpdate(store.loadAsOfyEntity(ofyRegistrar)));
|
||||
|
||||
ImmutableList.Builder<Entity> builder = new ImmutableList.Builder<>();
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ContactResource contact = DatastoreHelper.newContactResource("contact_" + i);
|
||||
store.insertOrUpdate(contact);
|
||||
builder.add(store.loadAsDatastoreEntity(contact));
|
||||
}
|
||||
contacts = builder.build();
|
||||
}
|
||||
credentialFile = temporaryFolder.newFile();
|
||||
new PrintStream(credentialFile)
|
||||
.printf(
|
||||
"%s %s %s",
|
||||
jpaRule.getDatabaseUrl(), jpaRule.getDatabaseUsername(), jpaRule.getDatabasePassword())
|
||||
.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Category(NeedsRunner.class)
|
||||
public void writeToSql_twoWriters() {
|
||||
pipeline
|
||||
.apply(
|
||||
Create.of(
|
||||
contacts.stream()
|
||||
.map(InitSqlTestUtils::entityToBytes)
|
||||
.map(bytes -> VersionedEntity.from(0L, bytes))
|
||||
.collect(Collectors.toList())))
|
||||
.apply(
|
||||
Transforms.writeToSql(
|
||||
"ContactResource",
|
||||
2,
|
||||
4,
|
||||
() ->
|
||||
DaggerBeamJpaModule_JpaTransactionManagerComponent.builder()
|
||||
.beamJpaModule(new BeamJpaModule(credentialFile.getAbsolutePath()))
|
||||
.build()
|
||||
.localDbJpaTransactionManager()));
|
||||
pipeline.run().waitUntilFinish();
|
||||
|
||||
ImmutableList<?> sqlContacts = jpaTm().transact(() -> jpaTm().loadAll(ContactResource.class));
|
||||
// TODO(weiminyu): compare load entities with originals. Note: lastUpdateTimes won't match by
|
||||
// design. Need an elegant way to deal with this.bbq
|
||||
assertThat(sqlContacts).hasSize(3);
|
||||
}
|
||||
}
|
||||
@@ -132,8 +132,20 @@ public class BillingEventTest {
|
||||
public void testConvertBillingEvent_toCsv() {
|
||||
BillingEvent event = BillingEvent.parseFromRecord(schemaAndRecord);
|
||||
assertThat(event.toCsv())
|
||||
.isEqualTo("1,2017-10-24 09:06:03 UTC,2017-01-19 23:59:43 UTC,myRegistrar,"
|
||||
+ "12345-CRRHELLO,test,RENEW,example.test,123456,5,USD,20.50,AUTO_RENEW");
|
||||
.isEqualTo(
|
||||
"1,2017-10-24 09:06:03 UTC,2017-01-19 23:59:43 UTC,myRegistrar,"
|
||||
+ "12345-CRRHELLO,,test,RENEW,example.test,123456,5,USD,20.50,AUTO_RENEW");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertBillingEvent_nonNullPoNumber_toCsv() {
|
||||
GenericRecord record = createRecord();
|
||||
record.put("poNumber", "905610");
|
||||
BillingEvent event = BillingEvent.parseFromRecord(new SchemaAndRecord(record, null));
|
||||
assertThat(event.toCsv())
|
||||
.isEqualTo(
|
||||
"1,2017-10-24 09:06:03 UTC,2017-01-19 23:59:43 UTC,myRegistrar,"
|
||||
+ "12345-CRRHELLO,905610,test,RENEW,example.test,123456,5,USD,20.50,AUTO_RENEW");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -157,21 +157,21 @@ public class InvoicingPipelineTest {
|
||||
return ImmutableMap.of(
|
||||
"invoice_details_2017-10_theRegistrar_test.csv",
|
||||
ImmutableList.of(
|
||||
"1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,theRegistrar,234,"
|
||||
"1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,theRegistrar,234,,"
|
||||
+ "test,RENEW,mydomain2.test,REPO-ID,3,USD,20.50,",
|
||||
"1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,theRegistrar,234,"
|
||||
"1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,theRegistrar,234,,"
|
||||
+ "test,RENEW,mydomain.test,REPO-ID,3,USD,20.50,"),
|
||||
"invoice_details_2017-10_theRegistrar_hello.csv",
|
||||
ImmutableList.of(
|
||||
"1,2017-10-02 00:00:00 UTC,2017-09-29 00:00:00 UTC,theRegistrar,234,"
|
||||
"1,2017-10-02 00:00:00 UTC,2017-09-29 00:00:00 UTC,theRegistrar,234,,"
|
||||
+ "hello,CREATE,mydomain3.hello,REPO-ID,5,JPY,70.75,"),
|
||||
"invoice_details_2017-10_bestdomains_test.csv",
|
||||
ImmutableList.of(
|
||||
"1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,bestdomains,456,"
|
||||
"1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,bestdomains,456,116688,"
|
||||
+ "test,RENEW,mydomain4.test,REPO-ID,1,USD,20.50,"),
|
||||
"invoice_details_2017-10_anotherRegistrar_test.csv",
|
||||
ImmutableList.of(
|
||||
"1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,anotherRegistrar,789,"
|
||||
"1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,anotherRegistrar,789,,"
|
||||
+ "test,CREATE,mydomain5.test,REPO-ID,1,USD,0.00,SUNRISE ANCHOR_TENANT"));
|
||||
}
|
||||
|
||||
|
||||
@@ -81,21 +81,21 @@ public class Spec11PipelineTest {
|
||||
@Rule public final transient TestPipeline p = TestPipeline.fromOptions(pipelineOptions);
|
||||
@Rule public final TemporaryFolder tempFolder = new TemporaryFolder();
|
||||
|
||||
private final Retrier retrier = new Retrier(
|
||||
new FakeSleeper(new FakeClock(DateTime.parse("2019-07-15TZ"))), 1);
|
||||
private final Retrier retrier =
|
||||
new Retrier(new FakeSleeper(new FakeClock(DateTime.parse("2019-07-15TZ"))), 1);
|
||||
private Spec11Pipeline spec11Pipeline;
|
||||
|
||||
@Before
|
||||
public void initializePipeline() throws IOException {
|
||||
File beamTempFolder = tempFolder.newFolder();
|
||||
spec11Pipeline = new Spec11Pipeline(
|
||||
"test-project",
|
||||
beamTempFolder.getAbsolutePath() + "/staging",
|
||||
beamTempFolder.getAbsolutePath() + "/templates/invoicing",
|
||||
tempFolder.getRoot().getAbsolutePath(),
|
||||
GoogleCredentialsBundle.create(GoogleCredentials.create(null)),
|
||||
retrier
|
||||
);
|
||||
spec11Pipeline =
|
||||
new Spec11Pipeline(
|
||||
"test-project",
|
||||
beamTempFolder.getAbsolutePath() + "/staging",
|
||||
beamTempFolder.getAbsolutePath() + "/templates/invoicing",
|
||||
tempFolder.getRoot().getAbsolutePath(),
|
||||
GoogleCredentialsBundle.create(GoogleCredentials.create(null)),
|
||||
retrier);
|
||||
}
|
||||
|
||||
private static final ImmutableList<String> BAD_DOMAINS =
|
||||
@@ -107,13 +107,15 @@ public class Spec11PipelineTest {
|
||||
// Put in half for theRegistrar and half for someRegistrar
|
||||
for (int i = 0; i < 255; i++) {
|
||||
subdomainsBuilder.add(
|
||||
Subdomain.create(String.format("%s.com", i), "theRegistrar", "fake@theRegistrar.com"));
|
||||
Subdomain.create(
|
||||
String.format("%s.com", i), "theDomain", "theRegistrar", "fake@theRegistrar.com"));
|
||||
}
|
||||
for (int i = 255; i < 510; i++) {
|
||||
subdomainsBuilder.add(
|
||||
Subdomain.create(String.format("%s.com", i), "someRegistrar", "fake@someRegistrar.com"));
|
||||
Subdomain.create(
|
||||
String.format("%s.com", i), "someDomain", "someRegistrar", "fake@someRegistrar.com"));
|
||||
}
|
||||
subdomainsBuilder.add(Subdomain.create("no-email.com", "noEmailRegistrar", ""));
|
||||
subdomainsBuilder.add(Subdomain.create("no-email.com", "fakeDomain", "noEmailRegistrar", ""));
|
||||
return subdomainsBuilder.build();
|
||||
}
|
||||
|
||||
@@ -165,8 +167,7 @@ public class Spec11PipelineTest {
|
||||
assertThat(noEmailThreatMatch.length()).isEqualTo(1);
|
||||
assertThat(noEmailThreatMatch.getJSONObject(0).get("fullyQualifiedDomainName"))
|
||||
.isEqualTo("no-email.com");
|
||||
assertThat(noEmailThreatMatch.getJSONObject(0).get("threatType"))
|
||||
.isEqualTo("MALWARE");
|
||||
assertThat(noEmailThreatMatch.getJSONObject(0).get("threatType")).isEqualTo("MALWARE");
|
||||
|
||||
JSONObject someRegistrarJSON = new JSONObject(sortedLines.get(1));
|
||||
assertThat(someRegistrarJSON.get("registrarEmailAddress")).isEqualTo("fake@someRegistrar.com");
|
||||
@@ -176,8 +177,7 @@ public class Spec11PipelineTest {
|
||||
assertThat(someThreatMatch.length()).isEqualTo(1);
|
||||
assertThat(someThreatMatch.getJSONObject(0).get("fullyQualifiedDomainName"))
|
||||
.isEqualTo("444.com");
|
||||
assertThat(someThreatMatch.getJSONObject(0).get("threatType"))
|
||||
.isEqualTo("MALWARE");
|
||||
assertThat(someThreatMatch.getJSONObject(0).get("threatType")).isEqualTo("MALWARE");
|
||||
|
||||
// theRegistrar has two ThreatMatches, we have to parse it explicitly
|
||||
JSONObject theRegistrarJSON = new JSONObject(sortedLines.get(2));
|
||||
@@ -228,10 +228,8 @@ public class Spec11PipelineTest {
|
||||
CloseableHttpResponse httpResponse =
|
||||
mock(CloseableHttpResponse.class, withSettings().serializable());
|
||||
when(httpResponse.getStatusLine())
|
||||
.thenReturn(
|
||||
new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "Done"));
|
||||
when(httpResponse.getEntity())
|
||||
.thenReturn(new FakeHttpEntity(getAPIResponse(badUrls)));
|
||||
.thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "Done"));
|
||||
when(httpResponse.getEntity()).thenReturn(new FakeHttpEntity(getAPIResponse(badUrls)));
|
||||
return httpResponse;
|
||||
}
|
||||
|
||||
@@ -298,5 +296,4 @@ public class Spec11PipelineTest {
|
||||
return ImmutableList.copyOf(
|
||||
ResourceUtils.readResourceUtf8(resultFile.toURI().toURL()).split("\n"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import google.registry.testing.EppLoader;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeHttpSession;
|
||||
import google.registry.testing.InjectRule;
|
||||
import google.registry.testing.ShardableTestCase;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
@@ -45,7 +44,7 @@ import org.junit.runners.JUnit4;
|
||||
|
||||
/** Test that domain flows create the commit logs needed to reload at points in the past. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class EppCommitLogsTest extends ShardableTestCase {
|
||||
public class EppCommitLogsTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine =
|
||||
|
||||
@@ -42,7 +42,6 @@ import google.registry.model.eppoutput.Result.Code;
|
||||
import google.registry.monitoring.whitebox.EppMetric;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.ShardableTestCase;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.xml.ValidationMode;
|
||||
import java.util.List;
|
||||
@@ -64,7 +63,7 @@ import org.mockito.junit.MockitoRule;
|
||||
|
||||
/** Unit tests for {@link EppController}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class EppControllerTest extends ShardableTestCase {
|
||||
public class EppControllerTest {
|
||||
|
||||
@Rule
|
||||
public AppEngineRule appEngineRule =
|
||||
|
||||
@@ -46,7 +46,6 @@ import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeHttpSession;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.InjectRule;
|
||||
import google.registry.testing.ShardableTestCase;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@@ -56,7 +55,7 @@ import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
||||
public class EppTestCase extends ShardableTestCase {
|
||||
public class EppTestCase {
|
||||
|
||||
private static final MediaType APPLICATION_EPP_XML_UTF8 =
|
||||
MediaType.create("application", "epp+xml").withCharset(UTF_8);
|
||||
|
||||
@@ -23,7 +23,6 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import google.registry.testing.FakeHttpSession;
|
||||
import google.registry.testing.ShardableTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
@@ -31,7 +30,7 @@ import org.mockito.ArgumentCaptor;
|
||||
|
||||
/** Tests for {@link EppTlsAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class EppTlsActionTest extends ShardableTestCase {
|
||||
public class EppTlsActionTest {
|
||||
|
||||
private static final byte[] INPUT_XML_BYTES = "<xml>".getBytes(UTF_8);
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppOutput.ResponseOrGreeting;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.testing.ShardableTestCase;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.json.simple.JSONValue;
|
||||
@@ -40,7 +39,7 @@ import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link FlowReporter}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class FlowReporterTest extends ShardableTestCase {
|
||||
public class FlowReporterTest {
|
||||
|
||||
static class TestCommandFlow implements Flow {
|
||||
@Override
|
||||
|
||||
@@ -36,7 +36,6 @@ import google.registry.monitoring.whitebox.EppMetric;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeHttpSession;
|
||||
import google.registry.testing.ShardableTestCase;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.junit.Before;
|
||||
@@ -48,7 +47,7 @@ import org.mockito.Mockito;
|
||||
|
||||
/** Unit tests for {@link FlowRunner}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class FlowRunnerTest extends ShardableTestCase {
|
||||
public class FlowRunnerTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngineRule = new AppEngineRule.Builder().build();
|
||||
|
||||
@@ -52,7 +52,6 @@ import google.registry.testing.EppLoader;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeHttpSession;
|
||||
import google.registry.testing.InjectRule;
|
||||
import google.registry.testing.ShardableTestCase;
|
||||
import google.registry.testing.TestDataHelper;
|
||||
import google.registry.tmch.TmchCertificateAuthority;
|
||||
import google.registry.tmch.TmchXmlSignature;
|
||||
@@ -63,18 +62,15 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/**
|
||||
* Base class for resource flow unit tests.
|
||||
*
|
||||
* @param <F> the flow type
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public abstract class FlowTestCase<F extends Flow> extends ShardableTestCase {
|
||||
public abstract class FlowTestCase<F extends Flow> {
|
||||
|
||||
/** Whether to actually write to Datastore or just simulate. */
|
||||
public enum CommitMode { LIVE, DRY_RUN }
|
||||
@@ -82,23 +78,22 @@ public abstract class FlowTestCase<F extends Flow> extends ShardableTestCase {
|
||||
/** Whether to run in normal or superuser mode. */
|
||||
public enum UserPrivileges { NORMAL, SUPERUSER }
|
||||
|
||||
@Rule
|
||||
@RegisterExtension
|
||||
public final AppEngineRule appEngine =
|
||||
AppEngineRule.builder().withDatastoreAndCloudSql().withTaskQueue().build();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
@RegisterExtension public final InjectRule inject = new InjectRule();
|
||||
|
||||
protected EppLoader eppLoader;
|
||||
protected SessionMetadata sessionMetadata;
|
||||
protected FakeClock clock = new FakeClock(DateTime.now(UTC));
|
||||
protected TransportCredentials credentials = new PasswordOnlyTransportCredentials();
|
||||
protected EppRequestSource eppRequestSource = EppRequestSource.UNIT_TEST;
|
||||
protected TmchXmlSignature testTmchXmlSignature = null;
|
||||
private TmchXmlSignature testTmchXmlSignature = null;
|
||||
|
||||
private EppMetric.Builder eppMetricBuilder;
|
||||
|
||||
@Before
|
||||
@BeforeEach
|
||||
public void init() {
|
||||
sessionMetadata = new HttpSessionMetadata(new FakeHttpSession());
|
||||
sessionMetadata.setClientId("TheRegistrar");
|
||||
@@ -204,29 +199,26 @@ public abstract class FlowTestCase<F extends Flow> extends ShardableTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the actual grace periods and the corresponding billing events referenced from
|
||||
* their keys match the expected map of grace periods to billing events. For the expected map,
|
||||
* the keys on the grace periods and IDs on the billing events are ignored.
|
||||
* Assert that the actual grace periods and the corresponding billing events referenced from their
|
||||
* keys match the expected map of grace periods to billing events. For the expected map, the keys
|
||||
* on the grace periods and IDs on the billing events are ignored.
|
||||
*/
|
||||
public void assertGracePeriods(
|
||||
Iterable<GracePeriod> actual,
|
||||
ImmutableMap<GracePeriod, ? extends BillingEvent> expected) {
|
||||
protected void assertGracePeriods(
|
||||
Iterable<GracePeriod> actual, ImmutableMap<GracePeriod, ? extends BillingEvent> expected) {
|
||||
assertThat(canonicalizeGracePeriods(Maps.toMap(actual, FlowTestCase::expandGracePeriod)))
|
||||
.isEqualTo(canonicalizeGracePeriods(expected));
|
||||
}
|
||||
|
||||
public void assertPollMessages(
|
||||
String clientId,
|
||||
PollMessage... expected) {
|
||||
protected void assertPollMessages(String clientId, PollMessage... expected) {
|
||||
assertPollMessagesHelper(getPollMessages(clientId), expected);
|
||||
}
|
||||
|
||||
public void assertPollMessages(PollMessage... expected) {
|
||||
protected void assertPollMessages(PollMessage... expected) {
|
||||
assertPollMessagesHelper(getPollMessages(), expected);
|
||||
}
|
||||
|
||||
/** Assert that the list matches all the poll messages in the fake Datastore. */
|
||||
public void assertPollMessagesHelper(
|
||||
private void assertPollMessagesHelper(
|
||||
Iterable<PollMessage> pollMessages, PollMessage... expected) {
|
||||
// Ordering is irrelevant but duplicates should be considered independently.
|
||||
assertThat(
|
||||
@@ -279,7 +271,7 @@ public abstract class FlowTestCase<F extends Flow> extends ShardableTestCase {
|
||||
}
|
||||
|
||||
/** Shortcut to call {@link #runFlow(CommitMode, UserPrivileges)} as super user and live run. */
|
||||
public EppOutput runFlowAsSuperuser() throws Exception {
|
||||
protected EppOutput runFlowAsSuperuser() throws Exception {
|
||||
return runFlow(CommitMode.LIVE, UserPrivileges.SUPERUSER);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Base class for resource flow unit tests.
|
||||
@@ -60,8 +60,8 @@ public abstract class ResourceFlowTestCase<F extends Flow, R extends EppResource
|
||||
|
||||
private final TestLogHandler logHandler = new TestLogHandler();
|
||||
|
||||
@Before
|
||||
public void beforeResourceFlowTestCase() {
|
||||
@BeforeEach
|
||||
void beforeResourceFlowTestCase() {
|
||||
// Attach TestLogHandler to the root logger so it has access to all log messages.
|
||||
// Note that in theory for assertIcannReportingActivityFieldLogged() below it would suffice to
|
||||
// attach it only to the FlowRunner logger, but for some reason this doesn't work for all flows.
|
||||
@@ -89,7 +89,7 @@ public abstract class ResourceFlowTestCase<F extends Flow, R extends EppResource
|
||||
return refreshedResource;
|
||||
}
|
||||
|
||||
protected ResourceCommand.SingleResourceCommand getResourceCommand() throws Exception {
|
||||
private ResourceCommand.SingleResourceCommand getResourceCommand() throws Exception {
|
||||
return (ResourceCommand.SingleResourceCommand)
|
||||
((ResourceCommandWrapper) eppLoader.getEpp().getCommandWrapper().getCommand())
|
||||
.getResourceCommand();
|
||||
@@ -99,7 +99,7 @@ public abstract class ResourceFlowTestCase<F extends Flow, R extends EppResource
|
||||
return getResourceCommand().getTargetId();
|
||||
}
|
||||
|
||||
protected Class<R> getResourceClass() {
|
||||
private Class<R> getResourceClass() {
|
||||
return new TypeInstantiator<R>(getClass()){}.getExactType();
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public abstract class ResourceFlowTestCase<F extends Flow, R extends EppResource
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiresLogin() {
|
||||
void testRequiresLogin() {
|
||||
sessionMetadata.setClientId(null);
|
||||
EppException thrown = assertThrows(NotLoggedInException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
|
||||
@@ -25,7 +25,6 @@ import static org.mockito.Mockito.when;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.request.HttpException.BadRequestException;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.ShardableTestCase;
|
||||
import java.util.Optional;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.joda.time.DateTime;
|
||||
@@ -36,7 +35,7 @@ import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link TlsCredentials}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public final class TlsCredentialsTest extends ShardableTestCase {
|
||||
public final class TlsCredentialsTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder().withDatastoreAndCloudSql().build();
|
||||
|
||||
@@ -24,18 +24,17 @@ import google.registry.flows.EppException;
|
||||
import google.registry.flows.ResourceCheckFlowTestCase;
|
||||
import google.registry.flows.exceptions.TooManyResourceChecksException;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ContactCheckFlow}. */
|
||||
public class ContactCheckFlowTest
|
||||
extends ResourceCheckFlowTestCase<ContactCheckFlow, ContactResource> {
|
||||
class ContactCheckFlowTest extends ResourceCheckFlowTestCase<ContactCheckFlow, ContactResource> {
|
||||
|
||||
public ContactCheckFlowTest() {
|
||||
ContactCheckFlowTest() {
|
||||
setEppInput("contact_check.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNothingExists() throws Exception {
|
||||
void testNothingExists() throws Exception {
|
||||
// These ids come from the check xml.
|
||||
doCheckTest(
|
||||
create(true, "sh8013", null),
|
||||
@@ -44,7 +43,7 @@ public class ContactCheckFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneExists() throws Exception {
|
||||
void testOneExists() throws Exception {
|
||||
persistActiveContact("sh8013");
|
||||
// These ids come from the check xml.
|
||||
doCheckTest(
|
||||
@@ -54,7 +53,7 @@ public class ContactCheckFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneExistsButWasDeleted() throws Exception {
|
||||
void testOneExistsButWasDeleted() throws Exception {
|
||||
persistDeletedContact("sh8013", clock.nowUtc().minusDays(1));
|
||||
// These ids come from the check xml.
|
||||
doCheckTest(
|
||||
@@ -64,27 +63,27 @@ public class ContactCheckFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXmlMatches() throws Exception {
|
||||
void testXmlMatches() throws Exception {
|
||||
persistActiveContact("sah8013");
|
||||
runFlowAssertResponse(loadFile("contact_check_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test50IdsAllowed() throws Exception {
|
||||
void test50IdsAllowed() throws Exception {
|
||||
// Make sure we don't have a regression that reduces the number of allowed checks.
|
||||
setEppInput("contact_check_50.xml");
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTooManyIds() {
|
||||
void testTooManyIds() {
|
||||
setEppInput("contact_check_51.xml");
|
||||
EppException thrown = assertThrows(TooManyResourceChecksException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
runFlow();
|
||||
assertIcannReportingActivityFieldLogged("srs-cont-check");
|
||||
}
|
||||
|
||||
@@ -32,13 +32,12 @@ import google.registry.flows.exceptions.ResourceAlreadyExistsForThisClientExcept
|
||||
import google.registry.flows.exceptions.ResourceCreateContentionException;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ContactCreateFlow}. */
|
||||
public class ContactCreateFlowTest
|
||||
extends ResourceFlowTestCase<ContactCreateFlow, ContactResource> {
|
||||
class ContactCreateFlowTest extends ResourceFlowTestCase<ContactCreateFlow, ContactResource> {
|
||||
|
||||
public ContactCreateFlowTest() {
|
||||
ContactCreateFlowTest() {
|
||||
setEppInput("contact_create.xml");
|
||||
clock.setTo(DateTime.parse("1999-04-03T22:00:00.0Z"));
|
||||
}
|
||||
@@ -56,24 +55,24 @@ public class ContactCreateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
void testDryRun() throws Exception {
|
||||
dryRunFlowAssertResponse(loadFile("contact_create_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_neverExisted() throws Exception {
|
||||
void testSuccess_neverExisted() throws Exception {
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_existedButWasDeleted() throws Exception {
|
||||
void testSuccess_existedButWasDeleted() throws Exception {
|
||||
persistDeletedContact(getUniqueIdFromCommand(), clock.nowUtc().minusDays(1));
|
||||
clock.advanceOneMilli();
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_alreadyExists() throws Exception {
|
||||
void testFailure_alreadyExists() throws Exception {
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
ResourceAlreadyExistsForThisClientException thrown =
|
||||
assertThrows(ResourceAlreadyExistsForThisClientException.class, this::runFlow);
|
||||
@@ -85,7 +84,7 @@ public class ContactCreateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_resourceContention() throws Exception {
|
||||
void testFailure_resourceContention() throws Exception {
|
||||
String targetId = getUniqueIdFromCommand();
|
||||
persistResource(
|
||||
newContactResource(targetId)
|
||||
@@ -101,13 +100,13 @@ public class ContactCreateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_nonAsciiInLocAddress() throws Exception {
|
||||
void testSuccess_nonAsciiInLocAddress() throws Exception {
|
||||
setEppInput("contact_create_hebrew_loc.xml");
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonAsciiInIntAddress() {
|
||||
void testFailure_nonAsciiInIntAddress() {
|
||||
setEppInput("contact_create_hebrew_int.xml");
|
||||
EppException thrown =
|
||||
assertThrows(BadInternationalizedPostalInfoException.class, this::runFlow);
|
||||
@@ -115,7 +114,7 @@ public class ContactCreateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_declineDisclosure() {
|
||||
void testFailure_declineDisclosure() {
|
||||
setEppInput("contact_create_decline_disclosure.xml");
|
||||
EppException thrown =
|
||||
assertThrows(DeclineContactDisclosureFieldDisallowedPolicyException.class, this::runFlow);
|
||||
@@ -123,7 +122,7 @@ public class ContactCreateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
runFlow();
|
||||
assertIcannReportingActivityFieldLogged("srs-cont-create");
|
||||
}
|
||||
|
||||
@@ -37,26 +37,25 @@ import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ContactDeleteFlow}. */
|
||||
public class ContactDeleteFlowTest
|
||||
extends ResourceFlowTestCase<ContactDeleteFlow, ContactResource> {
|
||||
class ContactDeleteFlowTest extends ResourceFlowTestCase<ContactDeleteFlow, ContactResource> {
|
||||
|
||||
@Before
|
||||
public void initFlowTest() {
|
||||
@BeforeEach
|
||||
void initFlowTest() {
|
||||
setEppInput("contact_delete.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
void testDryRun() throws Exception {
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
dryRunFlowAssertResponse(loadFile("contact_delete_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
void testSuccess() throws Exception {
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
clock.advanceOneMilli();
|
||||
assertTransactionalFlow(true);
|
||||
@@ -73,7 +72,7 @@ public class ContactDeleteFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clTridNotSpecified() throws Exception {
|
||||
void testSuccess_clTridNotSpecified() throws Exception {
|
||||
setEppInput("contact_delete_no_cltrid.xml");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
clock.advanceOneMilli();
|
||||
@@ -91,7 +90,7 @@ public class ContactDeleteFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverExisted() throws Exception {
|
||||
void testFailure_neverExisted() throws Exception {
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(ResourceDoesNotExistException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains(String.format("(%s)", getUniqueIdFromCommand()));
|
||||
@@ -99,7 +98,7 @@ public class ContactDeleteFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasDeleted() throws Exception {
|
||||
void testFailure_existedButWasDeleted() throws Exception {
|
||||
persistDeletedContact(getUniqueIdFromCommand(), clock.nowUtc().minusDays(1));
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(ResourceDoesNotExistException.class, this::runFlow);
|
||||
@@ -108,19 +107,19 @@ public class ContactDeleteFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasClientDeleteProhibited() throws Exception {
|
||||
void testFailure_existedButWasClientDeleteProhibited() throws Exception {
|
||||
doFailingStatusTest(
|
||||
StatusValue.CLIENT_DELETE_PROHIBITED, ResourceStatusProhibitsOperationException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasServerDeleteProhibited() throws Exception {
|
||||
void testFailure_existedButWasServerDeleteProhibited() throws Exception {
|
||||
doFailingStatusTest(
|
||||
StatusValue.SERVER_DELETE_PROHIBITED, ResourceStatusProhibitsOperationException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasPendingDelete() throws Exception {
|
||||
void testFailure_existedButWasPendingDelete() throws Exception {
|
||||
doFailingStatusTest(
|
||||
StatusValue.PENDING_DELETE, ResourceStatusProhibitsOperationException.class);
|
||||
}
|
||||
@@ -137,7 +136,7 @@ public class ContactDeleteFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unauthorizedClient() throws Exception {
|
||||
void testFailure_unauthorizedClient() throws Exception {
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
EppException thrown = assertThrows(ResourceNotOwnedException.class, this::runFlow);
|
||||
@@ -145,7 +144,7 @@ public class ContactDeleteFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserUnauthorizedClient() throws Exception {
|
||||
void testSuccess_superuserUnauthorizedClient() throws Exception {
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
clock.advanceOneMilli();
|
||||
@@ -163,7 +162,7 @@ public class ContactDeleteFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_failfastWhenLinkedToDomain() throws Exception {
|
||||
void testFailure_failfastWhenLinkedToDomain() throws Exception {
|
||||
createTld("tld");
|
||||
persistResource(
|
||||
newDomainBase("example.tld", persistActiveContact(getUniqueIdFromCommand())));
|
||||
@@ -172,7 +171,7 @@ public class ContactDeleteFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_failfastWhenLinkedToApplication() throws Exception {
|
||||
void testFailure_failfastWhenLinkedToApplication() throws Exception {
|
||||
createTld("tld");
|
||||
persistResource(
|
||||
newDomainBase("example.tld", persistActiveContact(getUniqueIdFromCommand())));
|
||||
@@ -181,7 +180,7 @@ public class ContactDeleteFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
clock.advanceOneMilli();
|
||||
runFlow();
|
||||
|
||||
@@ -39,12 +39,12 @@ import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import google.registry.model.eppcommon.PresenceMarker;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ContactInfoFlow}. */
|
||||
public class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, ContactResource> {
|
||||
class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, ContactResource> {
|
||||
|
||||
public ContactInfoFlowTest() {
|
||||
ContactInfoFlowTest() {
|
||||
setEppInput("contact_info.xml");
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, C
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
void testSuccess() throws Exception {
|
||||
persistContactResource(true);
|
||||
// Check that the persisted contact info was returned.
|
||||
assertTransactionalFlow(false);
|
||||
@@ -108,7 +108,7 @@ public class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, C
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_linked() throws Exception {
|
||||
void testSuccess_linked() throws Exception {
|
||||
createTld("foobar");
|
||||
persistResource(newDomainBase("example.foobar", persistContactResource(true)));
|
||||
// Check that the persisted contact info was returned.
|
||||
@@ -122,7 +122,7 @@ public class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, C
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_owningRegistrarWithoutAuthInfo_seesAuthInfo() throws Exception {
|
||||
void testSuccess_owningRegistrarWithoutAuthInfo_seesAuthInfo() throws Exception {
|
||||
setEppInput("contact_info_no_authinfo.xml");
|
||||
persistContactResource(true);
|
||||
// Check that the persisted contact info was returned.
|
||||
@@ -136,7 +136,7 @@ public class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, C
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_otherRegistrar_notAuthorized() throws Exception {
|
||||
void testFailure_otherRegistrar_notAuthorized() throws Exception {
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
persistContactResource(true);
|
||||
// Check that the persisted contact info was returned.
|
||||
@@ -146,8 +146,7 @@ public class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, C
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_otherRegistrarWithoutAuthInfoAsSuperuser_doesNotSeeAuthInfo()
|
||||
throws Exception {
|
||||
void testSuccess_otherRegistrarWithoutAuthInfoAsSuperuser_doesNotSeeAuthInfo() throws Exception {
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
setEppInput("contact_info_no_authinfo.xml");
|
||||
persistContactResource(true);
|
||||
@@ -164,7 +163,7 @@ public class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, C
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_otherRegistrarWithAuthInfoAsSuperuser_seesAuthInfo() throws Exception {
|
||||
void testSuccess_otherRegistrarWithAuthInfoAsSuperuser_seesAuthInfo() throws Exception {
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
persistContactResource(true);
|
||||
// Check that the persisted contact info was returned.
|
||||
@@ -180,7 +179,7 @@ public class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, C
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverExisted() throws Exception {
|
||||
void testFailure_neverExisted() throws Exception {
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(ResourceDoesNotExistException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains(String.format("(%s)", getUniqueIdFromCommand()));
|
||||
@@ -188,7 +187,7 @@ public class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, C
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasDeleted() throws Exception {
|
||||
void testFailure_existedButWasDeleted() throws Exception {
|
||||
persistContactResource(false);
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(ResourceDoesNotExistException.class, this::runFlow);
|
||||
@@ -197,7 +196,7 @@ public class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, C
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
persistContactResource(true);
|
||||
runFlow();
|
||||
assertIcannReportingActivityFieldLogged("srs-cont-info");
|
||||
|
||||
+20
-20
@@ -41,15 +41,15 @@ import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.transfer.TransferData;
|
||||
import google.registry.model.transfer.TransferResponse;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ContactTransferApproveFlow}. */
|
||||
public class ContactTransferApproveFlowTest
|
||||
class ContactTransferApproveFlowTest
|
||||
extends ContactTransferFlowTestCase<ContactTransferApproveFlow, ContactResource> {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
setEppInput("contact_transfer_approve.xml");
|
||||
setClientIdForFlow("TheRegistrar");
|
||||
setupContactWithPendingTransfer();
|
||||
@@ -122,24 +122,24 @@ public class ContactTransferApproveFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
void testDryRun() throws Exception {
|
||||
setEppInput("contact_transfer_approve.xml");
|
||||
dryRunFlowAssertResponse(loadFile("contact_transfer_approve_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
void testSuccess() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_approve.xml", "contact_transfer_approve_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_withAuthinfo() throws Exception {
|
||||
void testSuccess_withAuthinfo() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_approve_with_authinfo.xml",
|
||||
"contact_transfer_approve_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badContactPassword() {
|
||||
void testFailure_badContactPassword() {
|
||||
// Change the contact's password so it does not match the password in the file.
|
||||
contact = persistResource(
|
||||
contact.asBuilder()
|
||||
@@ -153,7 +153,7 @@ public class ContactTransferApproveFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverBeenTransferred() {
|
||||
void testFailure_neverBeenTransferred() {
|
||||
changeTransferStatus(null);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -162,7 +162,7 @@ public class ContactTransferApproveFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientApproved() {
|
||||
void testFailure_clientApproved() {
|
||||
changeTransferStatus(TransferStatus.CLIENT_APPROVED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -171,7 +171,7 @@ public class ContactTransferApproveFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientRejected() {
|
||||
void testFailure_clientRejected() {
|
||||
changeTransferStatus(TransferStatus.CLIENT_REJECTED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -180,7 +180,7 @@ public class ContactTransferApproveFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientCancelled() {
|
||||
void testFailure_clientCancelled() {
|
||||
changeTransferStatus(TransferStatus.CLIENT_CANCELLED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -189,7 +189,7 @@ public class ContactTransferApproveFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverApproved() {
|
||||
void testFailure_serverApproved() {
|
||||
changeTransferStatus(TransferStatus.SERVER_APPROVED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -198,7 +198,7 @@ public class ContactTransferApproveFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverCancelled() {
|
||||
void testFailure_serverCancelled() {
|
||||
changeTransferStatus(TransferStatus.SERVER_CANCELLED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -207,7 +207,7 @@ public class ContactTransferApproveFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_gainingClient() {
|
||||
void testFailure_gainingClient() {
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -216,7 +216,7 @@ public class ContactTransferApproveFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unrelatedClient() {
|
||||
void testFailure_unrelatedClient() {
|
||||
setClientIdForFlow("ClientZ");
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -225,7 +225,7 @@ public class ContactTransferApproveFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_deletedContact() throws Exception {
|
||||
void testFailure_deletedContact() throws Exception {
|
||||
contact = persistResource(
|
||||
contact.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
ResourceDoesNotExistException thrown =
|
||||
@@ -237,7 +237,7 @@ public class ContactTransferApproveFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonexistentContact() throws Exception {
|
||||
void testFailure_nonexistentContact() throws Exception {
|
||||
deleteResource(contact);
|
||||
contact = persistResource(
|
||||
contact.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
@@ -250,7 +250,7 @@ public class ContactTransferApproveFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
runFlow();
|
||||
assertIcannReportingActivityFieldLogged("srs-cont-transfer-approve");
|
||||
}
|
||||
|
||||
+20
-20
@@ -38,15 +38,15 @@ import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.transfer.TransferData;
|
||||
import google.registry.model.transfer.TransferResponse;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ContactTransferCancelFlow}. */
|
||||
public class ContactTransferCancelFlowTest
|
||||
class ContactTransferCancelFlowTest
|
||||
extends ContactTransferFlowTestCase<ContactTransferCancelFlow, ContactResource> {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.setEppInput("contact_transfer_cancel.xml");
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
setupContactWithPendingTransfer();
|
||||
@@ -106,24 +106,24 @@ public class ContactTransferCancelFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
void testDryRun() throws Exception {
|
||||
setEppInput("contact_transfer_cancel.xml");
|
||||
dryRunFlowAssertResponse(loadFile("contact_transfer_cancel_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
void testSuccess() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_cancel.xml", "contact_transfer_cancel_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_withAuthinfo() throws Exception {
|
||||
void testSuccess_withAuthinfo() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_cancel_with_authinfo.xml",
|
||||
"contact_transfer_cancel_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badContactPassword() {
|
||||
void testFailure_badContactPassword() {
|
||||
// Change the contact's password so it does not match the password in the file.
|
||||
contact =
|
||||
persistResource(
|
||||
@@ -139,7 +139,7 @@ public class ContactTransferCancelFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverBeenTransferred() {
|
||||
void testFailure_neverBeenTransferred() {
|
||||
changeTransferStatus(null);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -148,7 +148,7 @@ public class ContactTransferCancelFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientApproved() {
|
||||
void testFailure_clientApproved() {
|
||||
changeTransferStatus(TransferStatus.CLIENT_APPROVED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -157,7 +157,7 @@ public class ContactTransferCancelFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientRejected() {
|
||||
void testFailure_clientRejected() {
|
||||
changeTransferStatus(TransferStatus.CLIENT_REJECTED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -166,7 +166,7 @@ public class ContactTransferCancelFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientCancelled() {
|
||||
void testFailure_clientCancelled() {
|
||||
changeTransferStatus(TransferStatus.CLIENT_CANCELLED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -175,7 +175,7 @@ public class ContactTransferCancelFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverApproved() {
|
||||
void testFailure_serverApproved() {
|
||||
changeTransferStatus(TransferStatus.SERVER_APPROVED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -184,7 +184,7 @@ public class ContactTransferCancelFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverCancelled() {
|
||||
void testFailure_serverCancelled() {
|
||||
changeTransferStatus(TransferStatus.SERVER_CANCELLED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -193,7 +193,7 @@ public class ContactTransferCancelFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_sponsoringClient() {
|
||||
void testFailure_sponsoringClient() {
|
||||
setClientIdForFlow("TheRegistrar");
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -203,7 +203,7 @@ public class ContactTransferCancelFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unrelatedClient() {
|
||||
void testFailure_unrelatedClient() {
|
||||
setClientIdForFlow("ClientZ");
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -213,7 +213,7 @@ public class ContactTransferCancelFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_deletedContact() throws Exception {
|
||||
void testFailure_deletedContact() throws Exception {
|
||||
contact =
|
||||
persistResource(contact.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
ResourceDoesNotExistException thrown =
|
||||
@@ -225,7 +225,7 @@ public class ContactTransferCancelFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonexistentContact() throws Exception {
|
||||
void testFailure_nonexistentContact() throws Exception {
|
||||
deleteResource(contact);
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(
|
||||
@@ -236,7 +236,7 @@ public class ContactTransferCancelFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
runFlow();
|
||||
assertIcannReportingActivityFieldLogged("srs-cont-transfer-cancel");
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
/**
|
||||
* Base class for contact transfer flow unit tests.
|
||||
@@ -49,13 +49,13 @@ public class ContactTransferFlowTestCase<F extends Flow, R extends EppResource>
|
||||
|
||||
protected ContactResource contact;
|
||||
|
||||
public ContactTransferFlowTestCase() {
|
||||
ContactTransferFlowTestCase() {
|
||||
checkState(!Registry.DEFAULT_TRANSFER_GRACE_PERIOD.isShorterThan(TIME_SINCE_REQUEST));
|
||||
clock.setTo(TRANSFER_REQUEST_TIME.plus(TIME_SINCE_REQUEST));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void initContactTest() {
|
||||
@BeforeEach
|
||||
void initContactTest() {
|
||||
// Registrar ClientZ is used in tests that need another registrar that definitely doesn't own
|
||||
// the resources in question.
|
||||
persistResource(
|
||||
@@ -63,7 +63,7 @@ public class ContactTransferFlowTestCase<F extends Flow, R extends EppResource>
|
||||
}
|
||||
|
||||
/** Adds a contact that has a pending transfer on it from TheRegistrar to NewRegistrar. */
|
||||
protected void setupContactWithPendingTransfer() {
|
||||
void setupContactWithPendingTransfer() {
|
||||
contact = persistContactWithPendingTransfer(
|
||||
newContactResource("sh8013"),
|
||||
TRANSFER_REQUEST_TIME,
|
||||
|
||||
+24
-24
@@ -33,15 +33,15 @@ import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ContactTransferQueryFlow}. */
|
||||
public class ContactTransferQueryFlowTest
|
||||
class ContactTransferQueryFlowTest
|
||||
extends ContactTransferFlowTestCase<ContactTransferQueryFlow, ContactResource> {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
setEppInput("contact_transfer_query.xml");
|
||||
clock.setTo(DateTime.parse("2000-06-10T22:00:00.0Z"));
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
@@ -69,65 +69,65 @@ public class ContactTransferQueryFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
void testSuccess() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_query.xml", "contact_transfer_query_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_withContactRoid() throws Exception {
|
||||
void testSuccess_withContactRoid() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_query_with_roid.xml", "contact_transfer_query_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_sponsoringClient() throws Exception {
|
||||
void testSuccess_sponsoringClient() throws Exception {
|
||||
setClientIdForFlow("TheRegistrar");
|
||||
doSuccessfulTest("contact_transfer_query.xml", "contact_transfer_query_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_withAuthinfo() throws Exception {
|
||||
void testSuccess_withAuthinfo() throws Exception {
|
||||
setClientIdForFlow("ClientZ");
|
||||
doSuccessfulTest("contact_transfer_query_with_authinfo.xml",
|
||||
"contact_transfer_query_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientApproved() throws Exception {
|
||||
void testSuccess_clientApproved() throws Exception {
|
||||
changeTransferStatus(TransferStatus.CLIENT_APPROVED);
|
||||
doSuccessfulTest("contact_transfer_query.xml",
|
||||
"contact_transfer_query_response_client_approved.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientRejected() throws Exception {
|
||||
@Test
|
||||
void testSuccess_clientRejected() throws Exception {
|
||||
changeTransferStatus(TransferStatus.CLIENT_REJECTED);
|
||||
doSuccessfulTest("contact_transfer_query.xml",
|
||||
"contact_transfer_query_response_client_rejected.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientCancelled() throws Exception {
|
||||
@Test
|
||||
void testSuccess_clientCancelled() throws Exception {
|
||||
changeTransferStatus(TransferStatus.CLIENT_CANCELLED);
|
||||
doSuccessfulTest("contact_transfer_query.xml",
|
||||
"contact_transfer_query_response_client_cancelled.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_serverApproved() throws Exception {
|
||||
void testSuccess_serverApproved() throws Exception {
|
||||
changeTransferStatus(TransferStatus.SERVER_APPROVED);
|
||||
doSuccessfulTest("contact_transfer_query.xml",
|
||||
"contact_transfer_query_response_server_approved.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_serverCancelled() throws Exception {
|
||||
void testSuccess_serverCancelled() throws Exception {
|
||||
changeTransferStatus(TransferStatus.SERVER_CANCELLED);
|
||||
doSuccessfulTest("contact_transfer_query.xml",
|
||||
"contact_transfer_query_response_server_cancelled.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_pendingDeleteContact() throws Exception {
|
||||
void testFailure_pendingDeleteContact() throws Exception {
|
||||
changeTransferStatus(TransferStatus.SERVER_CANCELLED);
|
||||
contact = persistResource(
|
||||
contact.asBuilder().setDeletionTime(clock.nowUtc().plusDays(1)).build());
|
||||
@@ -136,7 +136,7 @@ public class ContactTransferQueryFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badContactPassword() {
|
||||
void testFailure_badContactPassword() {
|
||||
// Change the contact's password so it does not match the password in the file.
|
||||
contact =
|
||||
persistResource(
|
||||
@@ -152,7 +152,7 @@ public class ContactTransferQueryFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badContactRoid() {
|
||||
void testFailure_badContactRoid() {
|
||||
// Set the contact to a different ROID, but don't persist it; this is just so the substitution
|
||||
// code above will write the wrong ROID into the file.
|
||||
contact = contact.asBuilder().setRepoId("DEADBEEF_TLD-ROID").build();
|
||||
@@ -164,7 +164,7 @@ public class ContactTransferQueryFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverBeenTransferred() {
|
||||
void testFailure_neverBeenTransferred() {
|
||||
changeTransferStatus(null);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -174,7 +174,7 @@ public class ContactTransferQueryFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unrelatedClient() {
|
||||
void testFailure_unrelatedClient() {
|
||||
setClientIdForFlow("ClientZ");
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -184,7 +184,7 @@ public class ContactTransferQueryFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_deletedContact() throws Exception {
|
||||
void testFailure_deletedContact() throws Exception {
|
||||
contact =
|
||||
persistResource(contact.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
ResourceDoesNotExistException thrown =
|
||||
@@ -195,7 +195,7 @@ public class ContactTransferQueryFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonexistentContact() throws Exception {
|
||||
void testFailure_nonexistentContact() throws Exception {
|
||||
deleteResource(contact);
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(
|
||||
@@ -205,7 +205,7 @@ public class ContactTransferQueryFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
runFlow();
|
||||
assertIcannReportingActivityFieldLogged("srs-cont-transfer-query");
|
||||
}
|
||||
|
||||
+20
-20
@@ -40,15 +40,15 @@ import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.transfer.TransferData;
|
||||
import google.registry.model.transfer.TransferResponse;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ContactTransferRejectFlow}. */
|
||||
public class ContactTransferRejectFlowTest
|
||||
class ContactTransferRejectFlowTest
|
||||
extends ContactTransferFlowTestCase<ContactTransferRejectFlow, ContactResource> {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
setEppInput("contact_transfer_reject.xml");
|
||||
setClientIdForFlow("TheRegistrar");
|
||||
setupContactWithPendingTransfer();
|
||||
@@ -121,24 +121,24 @@ public class ContactTransferRejectFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
void testDryRun() throws Exception {
|
||||
setEppInput("contact_transfer_reject.xml");
|
||||
dryRunFlowAssertResponse(loadFile("contact_transfer_reject_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
void testSuccess() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_reject.xml", "contact_transfer_reject_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_domainAuthInfo() throws Exception {
|
||||
void testSuccess_domainAuthInfo() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_reject_with_authinfo.xml",
|
||||
"contact_transfer_reject_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badPassword() {
|
||||
void testFailure_badPassword() {
|
||||
// Change the contact's password so it does not match the password in the file.
|
||||
contact =
|
||||
persistResource(
|
||||
@@ -154,7 +154,7 @@ public class ContactTransferRejectFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverBeenTransferred() {
|
||||
void testFailure_neverBeenTransferred() {
|
||||
changeTransferStatus(null);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -163,7 +163,7 @@ public class ContactTransferRejectFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientApproved() {
|
||||
void testFailure_clientApproved() {
|
||||
changeTransferStatus(TransferStatus.CLIENT_APPROVED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -172,7 +172,7 @@ public class ContactTransferRejectFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientRejected() {
|
||||
void testFailure_clientRejected() {
|
||||
changeTransferStatus(TransferStatus.CLIENT_REJECTED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -181,7 +181,7 @@ public class ContactTransferRejectFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientCancelled() {
|
||||
void testFailure_clientCancelled() {
|
||||
changeTransferStatus(TransferStatus.CLIENT_CANCELLED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -190,7 +190,7 @@ public class ContactTransferRejectFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverApproved() {
|
||||
void testFailure_serverApproved() {
|
||||
changeTransferStatus(TransferStatus.SERVER_APPROVED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -199,7 +199,7 @@ public class ContactTransferRejectFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverCancelled() {
|
||||
void testFailure_serverCancelled() {
|
||||
changeTransferStatus(TransferStatus.SERVER_CANCELLED);
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -208,7 +208,7 @@ public class ContactTransferRejectFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_gainingClient() {
|
||||
void testFailure_gainingClient() {
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -217,7 +217,7 @@ public class ContactTransferRejectFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unrelatedClient() {
|
||||
void testFailure_unrelatedClient() {
|
||||
setClientIdForFlow("ClientZ");
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -226,7 +226,7 @@ public class ContactTransferRejectFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_deletedContact() throws Exception {
|
||||
void testFailure_deletedContact() throws Exception {
|
||||
contact =
|
||||
persistResource(contact.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
ResourceDoesNotExistException thrown =
|
||||
@@ -238,7 +238,7 @@ public class ContactTransferRejectFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonexistentContact() throws Exception {
|
||||
void testFailure_nonexistentContact() throws Exception {
|
||||
deleteResource(contact);
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(
|
||||
@@ -249,7 +249,7 @@ public class ContactTransferRejectFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
runFlow();
|
||||
assertIcannReportingActivityFieldLogged("srs-cont-transfer-reject");
|
||||
}
|
||||
|
||||
+23
-23
@@ -52,20 +52,20 @@ import google.registry.model.transfer.ContactTransferData;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.persistence.VKey;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ContactTransferRequestFlow}. */
|
||||
public class ContactTransferRequestFlowTest
|
||||
class ContactTransferRequestFlowTest
|
||||
extends ContactTransferFlowTestCase<ContactTransferRequestFlow, ContactResource> {
|
||||
|
||||
public ContactTransferRequestFlowTest() {
|
||||
ContactTransferRequestFlowTest() {
|
||||
// We need the transfer to happen at exactly this time in order for the response to match up.
|
||||
clock.setTo(DateTime.parse("2000-06-08T22:00:00.0Z"));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
setEppInput("contact_transfer_request.xml");
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
contact = persistActiveContact("sh8013");
|
||||
@@ -146,18 +146,18 @@ public class ContactTransferRequestFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
void testDryRun() throws Exception {
|
||||
setEppInput("contact_transfer_request.xml");
|
||||
dryRunFlowAssertResponse(loadFile("contact_transfer_request_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
void testSuccess() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_request.xml", "contact_transfer_request_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_noAuthInfo() {
|
||||
void testFailure_noAuthInfo() {
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
MissingTransferRequestAuthInfoException.class,
|
||||
@@ -166,7 +166,7 @@ public class ContactTransferRequestFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badPassword() {
|
||||
void testFailure_badPassword() {
|
||||
// Change the contact's password so it does not match the password in the file.
|
||||
contact =
|
||||
persistResource(
|
||||
@@ -182,37 +182,37 @@ public class ContactTransferRequestFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientApproved() throws Exception {
|
||||
void testSuccess_clientApproved() throws Exception {
|
||||
changeTransferStatus(TransferStatus.CLIENT_APPROVED);
|
||||
doSuccessfulTest("contact_transfer_request.xml", "contact_transfer_request_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientRejected() throws Exception {
|
||||
void testSuccess_clientRejected() throws Exception {
|
||||
changeTransferStatus(TransferStatus.CLIENT_REJECTED);
|
||||
doSuccessfulTest("contact_transfer_request.xml", "contact_transfer_request_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientCancelled() throws Exception {
|
||||
void testSuccess_clientCancelled() throws Exception {
|
||||
changeTransferStatus(TransferStatus.CLIENT_CANCELLED);
|
||||
doSuccessfulTest("contact_transfer_request.xml", "contact_transfer_request_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_serverApproved() throws Exception {
|
||||
void testSuccess_serverApproved() throws Exception {
|
||||
changeTransferStatus(TransferStatus.SERVER_APPROVED);
|
||||
doSuccessfulTest("contact_transfer_request.xml", "contact_transfer_request_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_serverCancelled() throws Exception {
|
||||
void testSuccess_serverCancelled() throws Exception {
|
||||
changeTransferStatus(TransferStatus.SERVER_CANCELLED);
|
||||
doSuccessfulTest("contact_transfer_request.xml", "contact_transfer_request_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_pending() {
|
||||
void testFailure_pending() {
|
||||
contact =
|
||||
persistResource(
|
||||
contact
|
||||
@@ -233,7 +233,7 @@ public class ContactTransferRequestFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_sponsoringClient() {
|
||||
void testFailure_sponsoringClient() {
|
||||
setClientIdForFlow("TheRegistrar");
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
@@ -243,7 +243,7 @@ public class ContactTransferRequestFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_deletedContact() throws Exception {
|
||||
void testFailure_deletedContact() throws Exception {
|
||||
contact =
|
||||
persistResource(contact.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
ResourceDoesNotExistException thrown =
|
||||
@@ -255,7 +255,7 @@ public class ContactTransferRequestFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonexistentContact() throws Exception {
|
||||
void testFailure_nonexistentContact() throws Exception {
|
||||
deleteResource(contact);
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(
|
||||
@@ -266,7 +266,7 @@ public class ContactTransferRequestFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientTransferProhibited() {
|
||||
void testFailure_clientTransferProhibited() {
|
||||
contact =
|
||||
persistResource(
|
||||
contact.asBuilder().addStatusValue(StatusValue.CLIENT_TRANSFER_PROHIBITED).build());
|
||||
@@ -279,7 +279,7 @@ public class ContactTransferRequestFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverTransferProhibited() {
|
||||
void testFailure_serverTransferProhibited() {
|
||||
contact =
|
||||
persistResource(
|
||||
contact.asBuilder().addStatusValue(StatusValue.SERVER_TRANSFER_PROHIBITED).build());
|
||||
@@ -292,7 +292,7 @@ public class ContactTransferRequestFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_pendingDelete() {
|
||||
void testFailure_pendingDelete() {
|
||||
contact =
|
||||
persistResource(contact.asBuilder().addStatusValue(StatusValue.PENDING_DELETE).build());
|
||||
ResourceStatusProhibitsOperationException thrown =
|
||||
@@ -304,7 +304,7 @@ public class ContactTransferRequestFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
runFlow();
|
||||
assertIcannReportingActivityFieldLogged("srs-cont-transfer-request");
|
||||
}
|
||||
|
||||
@@ -41,13 +41,12 @@ import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.contact.PostalInfo;
|
||||
import google.registry.model.contact.PostalInfo.Type;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ContactUpdateFlow}. */
|
||||
public class ContactUpdateFlowTest
|
||||
extends ResourceFlowTestCase<ContactUpdateFlow, ContactResource> {
|
||||
class ContactUpdateFlowTest extends ResourceFlowTestCase<ContactUpdateFlow, ContactResource> {
|
||||
|
||||
public ContactUpdateFlowTest() {
|
||||
ContactUpdateFlowTest() {
|
||||
setEppInput("contact_update.xml");
|
||||
}
|
||||
|
||||
@@ -65,18 +64,18 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
void testDryRun() throws Exception {
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
dryRunFlowAssertResponse(loadFile("generic_success_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
void testSuccess() throws Exception {
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_updatingInternationalizedPostalInfoDeletesLocalized() throws Exception {
|
||||
void testSuccess_updatingInternationalizedPostalInfoDeletesLocalized() throws Exception {
|
||||
ContactResource contact =
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand()).asBuilder()
|
||||
@@ -114,7 +113,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_updatingLocalizedPostalInfoDeletesInternationalized() throws Exception {
|
||||
void testSuccess_updatingLocalizedPostalInfoDeletesInternationalized() throws Exception {
|
||||
setEppInput("contact_update_localized.xml");
|
||||
ContactResource contact =
|
||||
persistResource(
|
||||
@@ -153,7 +152,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_partialPostalInfoUpdate() throws Exception {
|
||||
void testSuccess_partialPostalInfoUpdate() throws Exception {
|
||||
setEppInput("contact_update_partial_postalinfo.xml");
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand()).asBuilder()
|
||||
@@ -188,9 +187,8 @@ public class ContactUpdateFlowTest
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSuccess_updateOnePostalInfo_touchOtherPostalInfoPreservesIt() throws Exception {
|
||||
void testSuccess_updateOnePostalInfo_touchOtherPostalInfoPreservesIt() throws Exception {
|
||||
setEppInput("contact_update_partial_postalinfo_preserve_int.xml");
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand()).asBuilder()
|
||||
@@ -256,7 +254,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverExisted() throws Exception {
|
||||
void testFailure_neverExisted() throws Exception {
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(ResourceDoesNotExistException.class, this::runFlow);
|
||||
assertThat(thrown).hasMessageThat().contains(String.format("(%s)", getUniqueIdFromCommand()));
|
||||
@@ -264,7 +262,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasDeleted() throws Exception {
|
||||
void testFailure_existedButWasDeleted() throws Exception {
|
||||
persistDeletedContact(getUniqueIdFromCommand(), clock.nowUtc().minusDays(1));
|
||||
ResourceDoesNotExistException thrown =
|
||||
assertThrows(ResourceDoesNotExistException.class, this::runFlow);
|
||||
@@ -273,7 +271,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_statusValueNotClientSettable() throws Exception {
|
||||
void testFailure_statusValueNotClientSettable() throws Exception {
|
||||
setEppInput("contact_update_prohibited_status.xml");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
EppException thrown = assertThrows(StatusNotClientSettableException.class, this::runFlow);
|
||||
@@ -281,7 +279,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserStatusValueNotClientSettable() throws Exception {
|
||||
void testSuccess_superuserStatusValueNotClientSettable() throws Exception {
|
||||
setEppInput("contact_update_prohibited_status.xml");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
clock.advanceOneMilli();
|
||||
@@ -290,7 +288,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unauthorizedClient() throws Exception {
|
||||
void testFailure_unauthorizedClient() throws Exception {
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
EppException thrown = assertThrows(ResourceNotOwnedException.class, this::runFlow);
|
||||
@@ -298,7 +296,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserUnauthorizedClient() throws Exception {
|
||||
void testSuccess_superuserUnauthorizedClient() throws Exception {
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
clock.advanceOneMilli();
|
||||
@@ -307,7 +305,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientUpdateProhibited_removed() throws Exception {
|
||||
void testSuccess_clientUpdateProhibited_removed() throws Exception {
|
||||
setEppInput("contact_update_remove_client_update_prohibited.xml");
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand())
|
||||
@@ -321,7 +319,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserClientUpdateProhibited_notRemoved() throws Exception {
|
||||
void testSuccess_superuserClientUpdateProhibited_notRemoved() throws Exception {
|
||||
setEppInput("contact_update_prohibited_status.xml");
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand())
|
||||
@@ -339,7 +337,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientUpdateProhibited_notRemoved() throws Exception {
|
||||
void testFailure_clientUpdateProhibited_notRemoved() throws Exception {
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand())
|
||||
.asBuilder()
|
||||
@@ -351,7 +349,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverUpdateProhibited() throws Exception {
|
||||
void testFailure_serverUpdateProhibited() throws Exception {
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand())
|
||||
.asBuilder()
|
||||
@@ -364,7 +362,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_pendingDeleteProhibited() throws Exception {
|
||||
void testFailure_pendingDeleteProhibited() throws Exception {
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand())
|
||||
.asBuilder()
|
||||
@@ -377,13 +375,13 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_nonAsciiInLocAddress() throws Exception {
|
||||
void testSuccess_nonAsciiInLocAddress() throws Exception {
|
||||
setEppInput("contact_update_hebrew_loc.xml");
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonAsciiInIntAddress() throws Exception {
|
||||
void testFailure_nonAsciiInIntAddress() throws Exception {
|
||||
setEppInput("contact_update_hebrew_int.xml");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
EppException thrown =
|
||||
@@ -392,7 +390,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_declineDisclosure() throws Exception {
|
||||
void testFailure_declineDisclosure() throws Exception {
|
||||
setEppInput("contact_update_decline_disclosure.xml");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
EppException thrown =
|
||||
@@ -401,7 +399,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_addRemoveSameValue() throws Exception {
|
||||
void testFailure_addRemoveSameValue() throws Exception {
|
||||
setEppInput("contact_update_add_remove_same.xml");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
EppException thrown = assertThrows(AddRemoveSameValueException.class, this::runFlow);
|
||||
@@ -409,7 +407,7 @@ public class ContactUpdateFlowTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
clock.advanceOneMilli();
|
||||
runFlow();
|
||||
|
||||
@@ -74,14 +74,14 @@ import google.registry.model.reporting.HistoryEntry;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link DomainCheckFlow}. */
|
||||
public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, DomainBase> {
|
||||
class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, DomainBase> {
|
||||
|
||||
public DomainCheckFlowTest() {
|
||||
DomainCheckFlowTest() {
|
||||
setEppInput("domain_check_one_tld.xml");
|
||||
}
|
||||
|
||||
@@ -102,14 +102,14 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
"specificuse,RESERVED_FOR_SPECIFIC_USE");
|
||||
}
|
||||
|
||||
@Before
|
||||
public void initCheckTest() {
|
||||
@BeforeEach
|
||||
void initCheckTest() {
|
||||
createTld("tld", TldState.QUIET_PERIOD);
|
||||
persistResource(Registry.get("tld").asBuilder().setReservedLists(createReservedList()).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_nothingExists() throws Exception {
|
||||
void testSuccess_nothingExists() throws Exception {
|
||||
doCheckTest(
|
||||
create(true, "example1.tld", null),
|
||||
create(true, "example2.tld", null),
|
||||
@@ -117,7 +117,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_oneExists() throws Exception {
|
||||
void testSuccess_oneExists() throws Exception {
|
||||
persistActiveDomain("example1.tld");
|
||||
doCheckTest(
|
||||
create(false, "example1.tld", "In use"),
|
||||
@@ -126,7 +126,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clTridNotSpecified() throws Exception {
|
||||
void testSuccess_clTridNotSpecified() throws Exception {
|
||||
setEppInput("domain_check_no_cltrid.xml");
|
||||
persistActiveDomain("example1.tld");
|
||||
doCheckTest(
|
||||
@@ -136,7 +136,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_oneExists_allocationTokenIsInvalid() throws Exception {
|
||||
void testSuccess_oneExists_allocationTokenIsInvalid() throws Exception {
|
||||
setEppInput("domain_check_allocationtoken.xml");
|
||||
persistActiveDomain("example1.tld");
|
||||
doCheckTest(
|
||||
@@ -147,7 +147,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_oneExists_allocationTokenIsValid() throws Exception {
|
||||
void testSuccess_oneExists_allocationTokenIsValid() throws Exception {
|
||||
setEppInput("domain_check_allocationtoken.xml");
|
||||
persistActiveDomain("example1.tld");
|
||||
persistResource(
|
||||
@@ -160,7 +160,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_oneExists_allocationTokenIsRedeemed() throws Exception {
|
||||
void testSuccess_oneExists_allocationTokenIsRedeemed() throws Exception {
|
||||
setEppInput("domain_check_allocationtoken.xml");
|
||||
persistActiveDomain("example1.tld");
|
||||
persistResource(
|
||||
@@ -177,7 +177,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_oneExists_allocationTokenForReservedDomain() throws Exception {
|
||||
void testSuccess_oneExists_allocationTokenForReservedDomain() throws Exception {
|
||||
setEppInput("domain_check_allocationtoken.xml");
|
||||
persistActiveDomain("example1.tld");
|
||||
persistResource(
|
||||
@@ -194,7 +194,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_allocationTokenForReservedDomain_showsFee() throws Exception {
|
||||
void testSuccess_allocationTokenForReservedDomain_showsFee() throws Exception {
|
||||
setEppInput("domain_check_allocationtoken_fee_specificuse.xml");
|
||||
createTld("example");
|
||||
persistResource(
|
||||
@@ -209,7 +209,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_oneExists_allocationTokenForWrongDomain() throws Exception {
|
||||
void testSuccess_oneExists_allocationTokenForWrongDomain() throws Exception {
|
||||
setEppInput("domain_check_allocationtoken.xml");
|
||||
persistActiveDomain("example1.tld");
|
||||
persistResource(
|
||||
@@ -226,7 +226,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_notOutOfDateToken_forSpecificDomain() throws Exception {
|
||||
void testSuccess_notOutOfDateToken_forSpecificDomain() throws Exception {
|
||||
setEppInput("domain_check_allocationtoken.xml");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
@@ -248,7 +248,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_outOfDateToken_forSpecificDomain() throws Exception {
|
||||
void testSuccess_outOfDateToken_forSpecificDomain() throws Exception {
|
||||
setEppInput("domain_check_allocationtoken.xml");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
@@ -270,8 +270,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_nothingExists_reservationsOverrideInvalidAllocationTokens()
|
||||
throws Exception {
|
||||
void testSuccess_nothingExists_reservationsOverrideInvalidAllocationTokens() throws Exception {
|
||||
setEppInput("domain_check_reserved_allocationtoken.xml");
|
||||
// Fill out these reasons
|
||||
doCheckTest(
|
||||
@@ -283,7 +282,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_allocationTokenPromotion() throws Exception {
|
||||
void testSuccess_allocationTokenPromotion() throws Exception {
|
||||
createTld("example");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
@@ -302,7 +301,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_promotionNotActive() throws Exception {
|
||||
void testSuccess_promotionNotActive() throws Exception {
|
||||
createTld("example");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
@@ -324,7 +323,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_promoTokenNotValidForTld() throws Exception {
|
||||
void testSuccess_promoTokenNotValidForTld() throws Exception {
|
||||
createTld("example");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
@@ -347,7 +346,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_promoTokenNotValidForRegistrar() throws Exception {
|
||||
void testSuccess_promoTokenNotValidForRegistrar() throws Exception {
|
||||
createTld("example");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
@@ -370,7 +369,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_oneReservedInSunrise() throws Exception {
|
||||
void testSuccess_oneReservedInSunrise() throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(Registry.get("tld").asBuilder().setReservedLists(createReservedList()).build());
|
||||
setEppInput("domain_check_one_tld_reserved.xml");
|
||||
@@ -382,7 +381,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_twoReservedOutsideSunrise() throws Exception {
|
||||
void testSuccess_twoReservedOutsideSunrise() throws Exception {
|
||||
setEppInput("domain_check_one_tld_reserved.xml");
|
||||
doCheckTest(
|
||||
create(false, "reserved.tld", "Reserved"),
|
||||
@@ -392,8 +391,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_domainWithMultipleReservationType_useMostSevereMessage()
|
||||
throws Exception {
|
||||
void testSuccess_domainWithMultipleReservationType_useMostSevereMessage() throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
@@ -410,13 +408,13 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_anchorTenantReserved() throws Exception {
|
||||
void testSuccess_anchorTenantReserved() throws Exception {
|
||||
setEppInput("domain_check_anchor.xml");
|
||||
doCheckTest(create(false, "anchor.tld", "Allocation token required"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_anchorTenantWithToken() throws Exception {
|
||||
void testSuccess_anchorTenantWithToken() throws Exception {
|
||||
setEppInput("domain_check_anchor_allocationtoken.xml");
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
@@ -428,7 +426,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_multipartTld_oneReserved() throws Exception {
|
||||
void testSuccess_multipartTld_oneReserved() throws Exception {
|
||||
createTld("tld.foo");
|
||||
persistResource(
|
||||
Registry.get("tld.foo")
|
||||
@@ -446,7 +444,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_oneExistsButWasDeleted() throws Exception {
|
||||
void testSuccess_oneExistsButWasDeleted() throws Exception {
|
||||
persistDeletedDomain("example1.tld", clock.nowUtc().minusDays(1));
|
||||
doCheckTest(
|
||||
create(true, "example1.tld", null),
|
||||
@@ -455,7 +453,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_duplicatesAllowed() throws Exception {
|
||||
void testSuccess_duplicatesAllowed() throws Exception {
|
||||
setEppInput("domain_check_duplicates.xml");
|
||||
doCheckTest(
|
||||
create(true, "example1.tld", null),
|
||||
@@ -464,40 +462,40 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_xmlMatches() throws Exception {
|
||||
void testSuccess_xmlMatches() throws Exception {
|
||||
persistActiveDomain("example2.tld");
|
||||
runFlowAssertResponse(loadFile("domain_check_one_tld_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_50IdsAllowed() throws Exception {
|
||||
void testSuccess_50IdsAllowed() throws Exception {
|
||||
// Make sure we don't have a regression that reduces the number of allowed checks.
|
||||
setEppInput("domain_check_50.xml");
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_50IdsAllowed_withAllocationToken() throws Exception {
|
||||
void testSuccess_50IdsAllowed_withAllocationToken() throws Exception {
|
||||
setEppInput("domain_check_50_allocationtoken.xml");
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_tooManyIds() {
|
||||
void testFailure_tooManyIds() {
|
||||
setEppInput("domain_check_51.xml");
|
||||
EppException thrown = assertThrows(TooManyResourceChecksException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_wrongTld() {
|
||||
void testFailure_wrongTld() {
|
||||
setEppInput("domain_check.xml");
|
||||
EppException thrown = assertThrows(TldDoesNotExistException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_notAuthorizedForTld() {
|
||||
void testFailure_notAuthorizedForTld() {
|
||||
persistResource(
|
||||
loadRegistrar("TheRegistrar").asBuilder().setAllowedTlds(ImmutableSet.of()).build());
|
||||
EppException thrown = assertThrows(NotAuthorizedForTldException.class, this::runFlow);
|
||||
@@ -505,7 +503,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserNotAuthorizedForTld() throws Exception {
|
||||
void testSuccess_superuserNotAuthorizedForTld() throws Exception {
|
||||
persistActiveDomain("example2.tld");
|
||||
persistResource(
|
||||
loadRegistrar("TheRegistrar").asBuilder().setAllowedTlds(ImmutableSet.of()).build());
|
||||
@@ -521,92 +519,92 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_uppercase() {
|
||||
void testFailure_uppercase() {
|
||||
doFailingBadLabelTest("FOO.tld", BadDomainNameCharacterException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badCharacter() {
|
||||
void testFailure_badCharacter() {
|
||||
doFailingBadLabelTest("test_example.tld", BadDomainNameCharacterException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_leadingDash() {
|
||||
void testFailure_leadingDash() {
|
||||
doFailingBadLabelTest("-example.tld", LeadingDashException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_trailingDash() {
|
||||
void testFailure_trailingDash() {
|
||||
doFailingBadLabelTest("example-.tld", TrailingDashException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_tooLong() {
|
||||
void testFailure_tooLong() {
|
||||
doFailingBadLabelTest(Strings.repeat("a", 64) + ".tld", DomainLabelTooLongException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_leadingDot() {
|
||||
void testFailure_leadingDot() {
|
||||
doFailingBadLabelTest(".example.tld", EmptyDomainNamePartException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_leadingDotTld() {
|
||||
void testFailure_leadingDotTld() {
|
||||
doFailingBadLabelTest("foo..tld", EmptyDomainNamePartException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_tooManyParts() {
|
||||
void testFailure_tooManyParts() {
|
||||
doFailingBadLabelTest("foo.example.tld", BadDomainNamePartsCountException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_tooFewParts() {
|
||||
void testFailure_tooFewParts() {
|
||||
doFailingBadLabelTest("tld", BadDomainNamePartsCountException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainNameExistsAsTld_lowercase() {
|
||||
void testFailure_domainNameExistsAsTld_lowercase() {
|
||||
createTlds("foo.tld", "tld");
|
||||
doFailingBadLabelTest("foo.tld", DomainNameExistsAsTldException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainNameExistsAsTld_uppercase() {
|
||||
void testFailure_domainNameExistsAsTld_uppercase() {
|
||||
createTlds("foo.tld", "tld");
|
||||
doFailingBadLabelTest("FOO.TLD", BadDomainNameCharacterException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_invalidPunycode() {
|
||||
void testFailure_invalidPunycode() {
|
||||
doFailingBadLabelTest("xn--abcdefg.tld", InvalidPunycodeException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_dashesInThirdAndFourthPosition() {
|
||||
void testFailure_dashesInThirdAndFourthPosition() {
|
||||
doFailingBadLabelTest("ab--cdefg.tld", DashesInThirdAndFourthException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_tldDoesNotExist() {
|
||||
void testFailure_tldDoesNotExist() {
|
||||
doFailingBadLabelTest("foo.nosuchtld", TldDoesNotExistException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_invalidIdnCodePoints() {
|
||||
void testFailure_invalidIdnCodePoints() {
|
||||
// ❤☀☆☂☻♞☯.tld
|
||||
doFailingBadLabelTest("xn--k3hel9n7bxlu1e.tld", InvalidIdnDomainLabelException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_predelegation() {
|
||||
void testFailure_predelegation() {
|
||||
createTld("tld", PREDELEGATION);
|
||||
EppException thrown = assertThrows(BadCommandForRegistryPhaseException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAvailExtension() throws Exception {
|
||||
void testAvailExtension() throws Exception {
|
||||
persistActiveDomain("example1.tld");
|
||||
setEppInput("domain_check_avail.xml");
|
||||
doCheckTest(
|
||||
@@ -617,7 +615,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
|
||||
/** Test that premium names are shown as available even if the fee extension is not used. */
|
||||
@Test
|
||||
public void testAvailExtension_premiumDomainsAreAvailableWithoutExtension() throws Exception {
|
||||
void testAvailExtension_premiumDomainsAreAvailableWithoutExtension() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_premium.xml");
|
||||
doCheckTest(create(true, "rich.example", null));
|
||||
@@ -625,14 +623,14 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
|
||||
/** Test multiyear periods and explicitly correct currency and that the avail extension is ok. */
|
||||
@Test
|
||||
public void testFeeExtension_v06() throws Exception {
|
||||
void testFeeExtension_v06() throws Exception {
|
||||
persistActiveDomain("example1.tld");
|
||||
setEppInput("domain_check_fee_v06.xml", ImmutableMap.of("CURRENCY", "USD"));
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_v06.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_multipleReservations() throws Exception {
|
||||
void testFeeExtension_multipleReservations() throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
@@ -645,21 +643,21 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_v11() throws Exception {
|
||||
void testFeeExtension_v11() throws Exception {
|
||||
persistActiveDomain("example1.tld");
|
||||
setEppInput("domain_check_fee_v11.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_v11.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_v12() throws Exception {
|
||||
void testFeeExtension_v12() throws Exception {
|
||||
persistActiveDomain("example1.tld");
|
||||
setEppInput("domain_check_fee_v12.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_v12.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_thirtyDomains_restoreFees() throws Exception {
|
||||
void testSuccess_thirtyDomains_restoreFees() throws Exception {
|
||||
// Note that 30 is more than 25, which is the maximum # of entity groups you can enlist in a
|
||||
// single Datastore transaction (each DomainBase entity is in a separate entity group).
|
||||
// It's also pretty common for registrars to send large domain checks.
|
||||
@@ -676,7 +674,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
* currency.
|
||||
*/
|
||||
@Test
|
||||
public void testFeeExtension_multipleCommands_v06() throws Exception {
|
||||
void testFeeExtension_multipleCommands_v06() throws Exception {
|
||||
setEppInput("domain_check_fee_multiple_commands_v06.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_multiple_commands_response_v06.xml"));
|
||||
}
|
||||
@@ -684,21 +682,21 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
// Version 11 cannot have multiple commands.
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_multipleCommands_v12() throws Exception {
|
||||
void testFeeExtension_multipleCommands_v12() throws Exception {
|
||||
setEppInput("domain_check_fee_multiple_commands_v12.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_multiple_commands_response_v12.xml"));
|
||||
}
|
||||
|
||||
/** Test the same as {@link #testFeeExtension_multipleCommands_v06} with premium labels. */
|
||||
@Test
|
||||
public void testFeeExtension_premiumLabels_v06() throws Exception {
|
||||
void testFeeExtension_premiumLabels_v06() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_v06.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v06.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_premium_eap_v06() throws Exception {
|
||||
void testFeeExtension_premium_eap_v06() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_v06.xml");
|
||||
clock.setTo(DateTime.parse("2010-01-01T10:00:00Z"));
|
||||
@@ -718,7 +716,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_premium_eap_v06_withRenewalOnRestore() throws Exception {
|
||||
void testFeeExtension_premium_eap_v06_withRenewalOnRestore() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_v06.xml");
|
||||
clock.setTo(DateTime.parse("2010-01-01T10:00:00Z"));
|
||||
@@ -739,35 +737,35 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_premiumLabels_v11_create() throws Exception {
|
||||
void testFeeExtension_premiumLabels_v11_create() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_v11_create.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_create.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_premiumLabels_v11_renew() throws Exception {
|
||||
void testFeeExtension_premiumLabels_v11_renew() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_v11_renew.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_renew.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_premiumLabels_v11_transfer() throws Exception {
|
||||
void testFeeExtension_premiumLabels_v11_transfer() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_v11_transfer.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_transfer.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_premiumLabels_v11_restore() throws Exception {
|
||||
void testFeeExtension_premiumLabels_v11_restore() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_v11_restore.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_restore.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_premiumLabels_v11_restore_withRenewal() throws Exception {
|
||||
void testFeeExtension_premiumLabels_v11_restore_withRenewal() throws Exception {
|
||||
setEppInput("domain_check_fee_premium_v11_restore.xml");
|
||||
createTld("example");
|
||||
persistPendingDeleteDomain("rich.example");
|
||||
@@ -776,21 +774,21 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_premiumLabels_v11_update() throws Exception {
|
||||
void testFeeExtension_premiumLabels_v11_update() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_v11_update.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_update.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_premiumLabels_v12() throws Exception {
|
||||
void testFeeExtension_premiumLabels_v12() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_v12.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v12.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_premiumLabels_v12_withRenewalOnRestore() throws Exception {
|
||||
void testFeeExtension_premiumLabels_v12_withRenewalOnRestore() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_v12.xml");
|
||||
persistPendingDeleteDomain("rich.example");
|
||||
@@ -798,7 +796,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_fractionalCost() throws Exception {
|
||||
void testFeeExtension_fractionalCost() throws Exception {
|
||||
// Note that the response xml expects to see "11.10" with two digits after the decimal point.
|
||||
// This works because Money.getAmount(), used in the flow, returns a BigDecimal that is set to
|
||||
// display the number of digits that is conventional for the given currency.
|
||||
@@ -813,7 +811,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
|
||||
/** Test that create fees are properly omitted/classed on names on reserved lists. */
|
||||
@Test
|
||||
public void testFeeExtension_reservedName_v06() throws Exception {
|
||||
void testFeeExtension_reservedName_v06() throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
@@ -826,7 +824,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
|
||||
/** The tests must be split up for version 11, which allows only one command at a time. */
|
||||
@Test
|
||||
public void testFeeExtension_reservedName_v11_create() throws Exception {
|
||||
void testFeeExtension_reservedName_v11_create() throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
@@ -838,7 +836,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_reservedName_v11_renew() throws Exception {
|
||||
void testFeeExtension_reservedName_v11_renew() throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
@@ -850,7 +848,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_reservedName_v11_transfer() throws Exception {
|
||||
void testFeeExtension_reservedName_v11_transfer() throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
@@ -862,7 +860,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_reservedName_v11_restore() throws Exception {
|
||||
void testFeeExtension_reservedName_v11_restore() throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
@@ -874,7 +872,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_reservedName_v11_restore_withRenewals() throws Exception {
|
||||
void testFeeExtension_reservedName_v11_restore_withRenewals() throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
@@ -891,7 +889,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_reservedName_v12() throws Exception {
|
||||
void testFeeExtension_reservedName_v12() throws Exception {
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
.asBuilder()
|
||||
@@ -903,7 +901,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v06() throws Exception {
|
||||
void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v06() throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
@@ -916,7 +914,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v06_withRestoreRenewals()
|
||||
void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v06_withRestoreRenewals()
|
||||
throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
@@ -935,8 +933,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_create()
|
||||
throws Exception {
|
||||
void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_create() throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
@@ -949,7 +946,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_renew() throws Exception {
|
||||
void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_renew() throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
@@ -962,8 +959,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_transfer()
|
||||
throws Exception {
|
||||
void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_transfer() throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
@@ -976,8 +972,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_restore()
|
||||
throws Exception {
|
||||
void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v11_restore() throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
@@ -990,7 +985,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v12() throws Exception {
|
||||
void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v12() throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Registry.get("tld")
|
||||
@@ -1003,91 +998,91 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_wrongCurrency_v06() {
|
||||
void testFeeExtension_wrongCurrency_v06() {
|
||||
setEppInput("domain_check_fee_euro_v06.xml");
|
||||
EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_wrongCurrency_v11() {
|
||||
void testFeeExtension_wrongCurrency_v11() {
|
||||
setEppInput("domain_check_fee_euro_v11.xml");
|
||||
EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_wrongCurrency_v12() {
|
||||
void testFeeExtension_wrongCurrency_v12() {
|
||||
setEppInput("domain_check_fee_euro_v12.xml");
|
||||
EppException thrown = assertThrows(CurrencyUnitMismatchException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_badCurrencyType() {
|
||||
void testFeeExtension_badCurrencyType() {
|
||||
setEppInput("domain_check_fee_v06.xml", ImmutableMap.of("CURRENCY", "BAD"));
|
||||
EppException thrown = assertThrows(UnknownCurrencyEppException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_periodNotInYears_v06() {
|
||||
void testFeeExtension_periodNotInYears_v06() {
|
||||
setEppInput("domain_check_fee_bad_period_v06.xml");
|
||||
EppException thrown = assertThrows(BadPeriodUnitException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_periodNotInYears_v11() {
|
||||
void testFeeExtension_periodNotInYears_v11() {
|
||||
setEppInput("domain_check_fee_bad_period_v11.xml");
|
||||
EppException thrown = assertThrows(BadPeriodUnitException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_periodNotInYears_v12() {
|
||||
void testFeeExtension_periodNotInYears_v12() {
|
||||
setEppInput("domain_check_fee_bad_period_v12.xml");
|
||||
EppException thrown = assertThrows(BadPeriodUnitException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_commandWithPhase_v06() {
|
||||
void testFeeExtension_commandWithPhase_v06() {
|
||||
setEppInput("domain_check_fee_command_phase_v06.xml");
|
||||
EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_commandWithPhase_v11() {
|
||||
void testFeeExtension_commandWithPhase_v11() {
|
||||
setEppInput("domain_check_fee_command_phase_v11.xml");
|
||||
EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_commandWithPhase_v12() {
|
||||
void testFeeExtension_commandWithPhase_v12() {
|
||||
setEppInput("domain_check_fee_command_phase_v12.xml");
|
||||
EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_commandSubphase_v06() {
|
||||
void testFeeExtension_commandSubphase_v06() {
|
||||
setEppInput("domain_check_fee_command_subphase_v06.xml");
|
||||
EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_commandSubphase_v11() {
|
||||
void testFeeExtension_commandSubphase_v11() {
|
||||
setEppInput("domain_check_fee_command_subphase_v11.xml");
|
||||
EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_commandSubphase_v12() {
|
||||
void testFeeExtension_commandSubphase_v12() {
|
||||
setEppInput("domain_check_fee_command_subphase_v12.xml");
|
||||
EppException thrown = assertThrows(FeeChecksDontSupportPhasesException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
@@ -1095,7 +1090,7 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
|
||||
// This test is only relevant for v06, since domain names are not specified in v11 or v12.
|
||||
@Test
|
||||
public void testFeeExtension_feeCheckNotInAvailabilityCheck() {
|
||||
void testFeeExtension_feeCheckNotInAvailabilityCheck() {
|
||||
setEppInput("domain_check_fee_not_in_avail.xml");
|
||||
EppException thrown =
|
||||
assertThrows(OnlyCheckedNamesCanBeFeeCheckedException.class, this::runFlow);
|
||||
@@ -1103,84 +1098,84 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_multiyearRestore_v06() {
|
||||
void testFeeExtension_multiyearRestore_v06() {
|
||||
setEppInput("domain_check_fee_multiyear_restore_v06.xml");
|
||||
EppException thrown = assertThrows(RestoresAreAlwaysForOneYearException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_multiyearRestore_v11() {
|
||||
void testFeeExtension_multiyearRestore_v11() {
|
||||
setEppInput("domain_check_fee_multiyear_restore_v11.xml");
|
||||
EppException thrown = assertThrows(RestoresAreAlwaysForOneYearException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_multiyearRestore_v12() {
|
||||
void testFeeExtension_multiyearRestore_v12() {
|
||||
setEppInput("domain_check_fee_multiyear_restore_v12.xml");
|
||||
EppException thrown = assertThrows(RestoresAreAlwaysForOneYearException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_multiyearTransfer_v06() {
|
||||
void testFeeExtension_multiyearTransfer_v06() {
|
||||
setEppInput("domain_check_fee_multiyear_transfer_v06.xml");
|
||||
EppException thrown = assertThrows(TransfersAreAlwaysForOneYearException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_multiyearTransfer_v11() {
|
||||
void testFeeExtension_multiyearTransfer_v11() {
|
||||
setEppInput("domain_check_fee_multiyear_transfer_v11.xml");
|
||||
EppException thrown = assertThrows(TransfersAreAlwaysForOneYearException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_multiyearTransfer_v12() {
|
||||
void testFeeExtension_multiyearTransfer_v12() {
|
||||
setEppInput("domain_check_fee_multiyear_transfer_v12.xml");
|
||||
EppException thrown = assertThrows(TransfersAreAlwaysForOneYearException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_unknownCommand_v06() {
|
||||
void testFeeExtension_unknownCommand_v06() {
|
||||
setEppInput("domain_check_fee_unknown_command_v06.xml");
|
||||
EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_unknownCommand_v11() {
|
||||
void testFeeExtension_unknownCommand_v11() {
|
||||
setEppInput("domain_check_fee_unknown_command_v11.xml");
|
||||
EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_unknownCommand_v12() {
|
||||
void testFeeExtension_unknownCommand_v12() {
|
||||
setEppInput("domain_check_fee_unknown_command_v12.xml");
|
||||
EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_invalidCommand_v06() {
|
||||
void testFeeExtension_invalidCommand_v06() {
|
||||
setEppInput("domain_check_fee_invalid_command_v06.xml");
|
||||
EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_invalidCommand_v11() {
|
||||
void testFeeExtension_invalidCommand_v11() {
|
||||
setEppInput("domain_check_fee_invalid_command_v11.xml");
|
||||
EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeeExtension_invalidCommand_v12() {
|
||||
void testFeeExtension_invalidCommand_v12() {
|
||||
setEppInput("domain_check_fee_invalid_command_v12.xml");
|
||||
EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
@@ -1205,35 +1200,35 @@ public class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFl
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_eapFeeCheck_v06() throws Exception {
|
||||
void testSuccess_eapFeeCheck_v06() throws Exception {
|
||||
runEapFeeCheckTest("domain_check_fee_v06.xml", "domain_check_eap_fee_response_v06.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_eapFeeCheck_v11() throws Exception {
|
||||
void testSuccess_eapFeeCheck_v11() throws Exception {
|
||||
runEapFeeCheckTest("domain_check_fee_v11.xml", "domain_check_eap_fee_response_v11.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_eapFeeCheck_v12() throws Exception {
|
||||
void testSuccess_eapFeeCheck_v12() throws Exception {
|
||||
runEapFeeCheckTest("domain_check_fee_v12.xml", "domain_check_eap_fee_response_v12.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_eapFeeCheck_date_v12() throws Exception {
|
||||
void testSuccess_eapFeeCheck_date_v12() throws Exception {
|
||||
runEapFeeCheckTest(
|
||||
"domain_check_fee_date_v12.xml", "domain_check_eap_fee_response_date_v12.xml");
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Disabled
|
||||
@Test
|
||||
public void testSuccess_feeCheck_multipleRanges() {
|
||||
void testSuccess_feeCheck_multipleRanges() {
|
||||
// TODO: If at some point we have more than one type of fees that are time dependent, populate
|
||||
// this test to test if the notAfter date is the earliest of the end points of the ranges.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
createTlds("com", "net", "org");
|
||||
setEppInput("domain_check.xml");
|
||||
runFlow();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user