mirror of
https://github.com/google/nomulus
synced 2026-05-25 09:10:51 +00:00
Compare commits
10 Commits
nomulus-20
...
nomulus-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c1b178c94 | ||
|
|
fe0353ae7d | ||
|
|
360c198f4f | ||
|
|
e79e76e578 | ||
|
|
a5dbfceae1 | ||
|
|
647d6a1b08 | ||
|
|
ec417e9258 | ||
|
|
55bef58063 | ||
|
|
ecc3d9f75d | ||
|
|
f23d2ca315 |
@@ -46,7 +46,7 @@ plugins {
|
||||
id 'com.diffplug.gradle.spotless' version '3.25.0'
|
||||
|
||||
id 'jacoco'
|
||||
id 'com.dorongold.task-tree' version '1.5'
|
||||
id 'com.dorongold.task-tree' version '2.1.0'
|
||||
}
|
||||
|
||||
node {
|
||||
|
||||
@@ -48,7 +48,6 @@ import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.CloudTasksUtils;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Stream;
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -97,8 +96,6 @@ public final class TldFanoutAction implements Runnable {
|
||||
EXCLUDE_PARAM,
|
||||
JITTER_SECONDS_PARAM);
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
@Inject Clock clock;
|
||||
|
||||
@@ -208,6 +208,15 @@
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/replicateToDatastore]]></url>
|
||||
<description>
|
||||
Replays recent transactions from SQL to the Datastore secondary backend.
|
||||
</description>
|
||||
<schedule>every 3 minutes</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
|
||||
<description>
|
||||
|
||||
@@ -211,6 +211,15 @@
|
||||
</cron>
|
||||
-->
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/replicateToDatastore]]></url>
|
||||
<description>
|
||||
Replays recent transactions from SQL to the Datastore secondary backend.
|
||||
</description>
|
||||
<schedule>every 3 minutes</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<!--
|
||||
The next two wipeout jobs are required when crash has production data.
|
||||
-->
|
||||
|
||||
@@ -120,6 +120,15 @@
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/replicateToDatastore]]></url>
|
||||
<description>
|
||||
Replays recent transactions from SQL to the Datastore secondary backend.
|
||||
</description>
|
||||
<schedule>every 3 minutes</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/commitLogCheckpoint]]></url>
|
||||
<description>
|
||||
|
||||
@@ -247,6 +247,15 @@
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/cron/replicateToDatastore]]></url>
|
||||
<description>
|
||||
Replays recent transactions from SQL to the Datastore secondary backend.
|
||||
</description>
|
||||
<schedule>every 3 minutes</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/wipeOutContactHistoryPii]]></url>
|
||||
<description>
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright 2021 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.common;
|
||||
|
||||
import static com.google.common.base.Functions.identity;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.EntityClasses.ALL_CLASSES;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.googlecode.objectify.annotation.EntitySubclass;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** A helper to manage class name and class path mapping. */
|
||||
public class ClassPathManager {
|
||||
/**
|
||||
* Class registry allowing us to restore the original class object from the unqualified class
|
||||
* name, which is all the datastore key gives us. Note that entities annotated
|
||||
* with @EntitySubclass are removed because they share the same kind of the key with their parent
|
||||
* class.
|
||||
*/
|
||||
public static final Map<String, Class<?>> CLASS_REGISTRY =
|
||||
ALL_CLASSES.stream()
|
||||
.filter(clazz -> !clazz.isAnnotationPresent(EntitySubclass.class))
|
||||
.collect(Collectors.toMap(com.googlecode.objectify.Key::getKind, identity()));
|
||||
|
||||
/**
|
||||
* Class name registry allowing us to obtain the class name the unqualified class, which is all
|
||||
* the datastore key gives us. Note that entities annotated with @EntitySubclass are removed
|
||||
* because they share the same kind of the key with their parent class.
|
||||
*/
|
||||
public static final Map<Class<?>, String> CLASS_NAME_REGISTRY =
|
||||
ALL_CLASSES.stream()
|
||||
.filter(clazz -> !clazz.isAnnotationPresent(EntitySubclass.class))
|
||||
.collect(Collectors.toMap(identity(), com.googlecode.objectify.Key::getKind));
|
||||
|
||||
@VisibleForTesting
|
||||
public static void addTestEntityClass(Class<?> clazz) {
|
||||
CLASS_REGISTRY.put(clazz.getSimpleName(), clazz);
|
||||
CLASS_NAME_REGISTRY.put(clazz, clazz.getSimpleName());
|
||||
}
|
||||
|
||||
public static <T> Class<T> getClass(String className) {
|
||||
checkArgument(CLASS_REGISTRY.containsKey(className), "Class not found in class registry");
|
||||
return (Class<T>) CLASS_REGISTRY.get(className);
|
||||
}
|
||||
|
||||
public static <T> String getClassName(Class<T> clazz) {
|
||||
checkArgument(CLASS_NAME_REGISTRY.containsKey(clazz), "Class not found in class name registry");
|
||||
return CLASS_NAME_REGISTRY.get(clazz);
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,7 @@ import javax.persistence.Embedded;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.PostLoad;
|
||||
import javax.persistence.Transient;
|
||||
import org.hibernate.collection.internal.PersistentSet;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Interval;
|
||||
|
||||
@@ -508,16 +509,37 @@ public class DomainContent extends EppResource
|
||||
this.nsHosts = forceEmptyToNull(nsHosts);
|
||||
}
|
||||
|
||||
// Note: for the two methods below, how we wish to treat the Hibernate setters depends on the
|
||||
// current state of the object and what's passed in. The key principle is that we wish to maintain
|
||||
// the link between parent and child objects, meaning that we should keep around whichever of the
|
||||
// two sets (the parameter vs the class variable and clear/populate that as appropriate.
|
||||
//
|
||||
// If the class variable is a PersistentSet and we overwrite it here, Hibernate will throw
|
||||
// an exception "A collection with cascade=”all-delete-orphan” was no longer referenced by the
|
||||
// owning entity instance". See https://stackoverflow.com/questions/5587482 for more details.
|
||||
|
||||
// Hibernate needs this in order to populate gracePeriods but no one else should ever use it
|
||||
@SuppressWarnings("UnusedMethod")
|
||||
private void setInternalGracePeriods(Set<GracePeriod> gracePeriods) {
|
||||
this.gracePeriods = gracePeriods;
|
||||
if (this.gracePeriods instanceof PersistentSet) {
|
||||
Set<GracePeriod> nonNullGracePeriods = nullToEmpty(gracePeriods);
|
||||
this.gracePeriods.retainAll(nonNullGracePeriods);
|
||||
this.gracePeriods.addAll(nonNullGracePeriods);
|
||||
} else {
|
||||
this.gracePeriods = gracePeriods;
|
||||
}
|
||||
}
|
||||
|
||||
// Hibernate needs this in order to populate dsData but no one else should ever use it
|
||||
@SuppressWarnings("UnusedMethod")
|
||||
private void setInternalDelegationSignerData(Set<DelegationSignerData> dsData) {
|
||||
this.dsData = dsData;
|
||||
if (this.dsData instanceof PersistentSet) {
|
||||
Set<DelegationSignerData> nonNullDsData = nullToEmpty(dsData);
|
||||
this.dsData.retainAll(nonNullDsData);
|
||||
this.dsData.addAll(nonNullDsData);
|
||||
} else {
|
||||
this.dsData = dsData;
|
||||
}
|
||||
}
|
||||
|
||||
public final String getCurrentSponsorRegistrarId() {
|
||||
|
||||
@@ -209,7 +209,7 @@ public class DomainHistory extends HistoryEntry implements SqlEntity {
|
||||
@SuppressWarnings("unused")
|
||||
private void setInternalDomainTransactionRecords(
|
||||
Set<DomainTransactionRecord> domainTransactionRecords) {
|
||||
this.domainTransactionRecords = domainTransactionRecords;
|
||||
super.setDomainTransactionRecords(domainTransactionRecords);
|
||||
}
|
||||
|
||||
@Id
|
||||
|
||||
@@ -16,6 +16,7 @@ package google.registry.model.reporting;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.googlecode.objectify.Key.getKind;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
@@ -63,6 +64,7 @@ import javax.persistence.Enumerated;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Transient;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.hibernate.collection.internal.PersistentSet;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
@@ -317,9 +319,23 @@ public class HistoryEntry extends ImmutableObject
|
||||
|
||||
/** This method exists solely to satisfy Hibernate. Use the {@link Builder} instead. */
|
||||
@SuppressWarnings("UnusedMethod")
|
||||
private void setDomainTransactionRecords(Set<DomainTransactionRecord> domainTransactionRecords) {
|
||||
this.domainTransactionRecords =
|
||||
domainTransactionRecords == null ? null : ImmutableSet.copyOf(domainTransactionRecords);
|
||||
protected void setDomainTransactionRecords(
|
||||
Set<DomainTransactionRecord> domainTransactionRecords) {
|
||||
// Note: how we wish to treat this Hibernate setter depends on the current state of the object
|
||||
// and what's passed in. The key principle is that we wish to maintain the link between parent
|
||||
// and child objects, meaning that we should keep around whichever of the two sets (the
|
||||
// parameter vs the class variable and clear/populate that as appropriate.
|
||||
//
|
||||
// If the class variable is a PersistentSet and we overwrite it here, Hibernate will throw
|
||||
// an exception "A collection with cascade=”all-delete-orphan” was no longer referenced by the
|
||||
// owning entity instance". See https://stackoverflow.com/questions/5587482 for more details.
|
||||
if (this.domainTransactionRecords instanceof PersistentSet) {
|
||||
Set<DomainTransactionRecord> nonNullRecords = nullToEmpty(domainTransactionRecords);
|
||||
this.domainTransactionRecords.retainAll(nonNullRecords);
|
||||
this.domainTransactionRecords.addAll(nonNullRecords);
|
||||
} else {
|
||||
this.domainTransactionRecords = domainTransactionRecords;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,18 +14,13 @@
|
||||
|
||||
package google.registry.model.translators;
|
||||
|
||||
import static com.google.common.base.Functions.identity;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.EntityClasses.ALL_CLASSES;
|
||||
|
||||
import com.google.appengine.api.datastore.Key;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.googlecode.objectify.annotation.EntitySubclass;
|
||||
import google.registry.model.common.ClassPathManager;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
@@ -36,15 +31,6 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
public class VKeyTranslatorFactory extends AbstractSimpleTranslatorFactory<VKey, Key> {
|
||||
|
||||
// Class registry allowing us to restore the original class object from the unqualified class
|
||||
// name, which is all the datastore key gives us.
|
||||
// Note that entities annotated with @EntitySubclass are removed because they share the same
|
||||
// kind of the key with their parent class.
|
||||
private static final Map<String, Class<?>> CLASS_REGISTRY =
|
||||
ALL_CLASSES.stream()
|
||||
.filter(clazz -> !clazz.isAnnotationPresent(EntitySubclass.class))
|
||||
.collect(Collectors.toMap(com.googlecode.objectify.Key::getKind, identity()));
|
||||
|
||||
public VKeyTranslatorFactory() {
|
||||
super(VKey.class);
|
||||
}
|
||||
@@ -67,7 +53,7 @@ public class VKeyTranslatorFactory extends AbstractSimpleTranslatorFactory<VKey,
|
||||
}
|
||||
|
||||
// Try to create the VKey from its reference type.
|
||||
Class<T> clazz = (Class<T>) CLASS_REGISTRY.get(key.getKind());
|
||||
Class<T> clazz = ClassPathManager.getClass(key.getKind());
|
||||
checkArgument(clazz != null, "Unknown Key type: %s", key.getKind());
|
||||
try {
|
||||
Method createVKeyMethod =
|
||||
@@ -92,11 +78,6 @@ public class VKeyTranslatorFactory extends AbstractSimpleTranslatorFactory<VKey,
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static void addTestEntityClass(Class<?> clazz) {
|
||||
CLASS_REGISTRY.put(com.googlecode.objectify.Key.getKind(clazz), clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleTranslator<VKey, Key> createTranslator() {
|
||||
return new SimpleTranslator<VKey, Key>() {
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.BackupGroupRoot;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.common.ClassPathManager;
|
||||
import google.registry.model.translators.VKeyTranslatorFactory;
|
||||
import google.registry.util.SerializeUtils;
|
||||
import java.io.Serializable;
|
||||
@@ -137,9 +138,9 @@ public class VKey<T> extends ImmutableObject implements Serializable {
|
||||
*
|
||||
* <p>Example of a Vkey string by fromWebsafeKey(): "agR0ZXN0chYLEgpEb21haW5CYXNlIgZST0lELTEM"
|
||||
*
|
||||
* <p>Example of a vkey string by stringify(): "google.registry.testing.TestObject@sql:rO0ABX" +
|
||||
* "QAA2Zvbw@ofy:agR0ZXN0cjELEg9FbnRpdHlHcm91cFJvb3QiCWNyb3NzLXRsZAwLEgpUZXN0T2JqZWN0IgNmb28M",
|
||||
* where sql key and ofy key are values are encoded in Base64.
|
||||
* <p>Example of a vkey string by stringify(): "kind:TestObject@sql:rO0ABXQAA2Zvbw" +
|
||||
* "@ofy:agR0ZXN0cjELEg9FbnRpdHlHcm91cFJvb3QiCWNyb3NzLXRsZAwLEgpUZXN0T2JqZWN0IgNmb28M", where sql
|
||||
* key and ofy key values are encoded in Base64.
|
||||
*/
|
||||
public static <T> VKey<T> create(String keyString) throws Exception {
|
||||
if (!keyString.startsWith(CLASS_TYPE + KV_SEPARATOR)) {
|
||||
@@ -149,7 +150,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
|
||||
ImmutableMap<String, String> kvs =
|
||||
ImmutableMap.copyOf(
|
||||
Splitter.on(DELIMITER).withKeyValueSeparator(KV_SEPARATOR).split(keyString));
|
||||
Class classType = Class.forName(kvs.get(CLASS_TYPE));
|
||||
Class classType = ClassPathManager.getClass(kvs.get(CLASS_TYPE));
|
||||
|
||||
if (kvs.containsKey(SQL_LOOKUP_KEY) && kvs.containsKey(OFY_LOOKUP_KEY)) {
|
||||
return VKey.create(
|
||||
@@ -290,7 +291,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
|
||||
/**
|
||||
* Constructs the string representation of a {@link VKey}.
|
||||
*
|
||||
* <p>The string representation of a vkey contains its type, and sql key or ofy key, or both. Each
|
||||
* <p>The string representation of a vkey contains its kind, and sql key or ofy key, or both. Each
|
||||
* of the keys is first serialized into a byte array then encoded via Base64 into a web safe
|
||||
* string.
|
||||
*
|
||||
@@ -302,7 +303,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
|
||||
*/
|
||||
public String stringify() {
|
||||
// class type is required to create a vkey
|
||||
String key = CLASS_TYPE + KV_SEPARATOR + getKind().getName();
|
||||
String key = CLASS_TYPE + KV_SEPARATOR + ClassPathManager.getClassName(getKind());
|
||||
if (maybeGetSqlKey().isPresent()) {
|
||||
key += DELIMITER + SQL_LOOKUP_KEY + KV_SEPARATOR + SerializeUtils.stringify(getSqlKey());
|
||||
}
|
||||
@@ -315,7 +316,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
|
||||
/**
|
||||
* Constructs the readable string representation of a {@link VKey}.
|
||||
*
|
||||
* <p>This readable string representation of a vkey contains its type and its sql key or ofy key,
|
||||
* <p>This readable string representation of a vkey contains its kind and its sql key or ofy key,
|
||||
* or both.
|
||||
*/
|
||||
@Override
|
||||
|
||||
@@ -45,6 +45,7 @@ public abstract class RdeModule {
|
||||
public static final String PARAM_WATERMARK = "watermark";
|
||||
public static final String PARAM_WATERMARKS = "watermarks";
|
||||
public static final String PARAM_MANUAL = "manual";
|
||||
public static final String PARAM_BEAM = "beam";
|
||||
public static final String PARAM_DIRECTORY = "directory";
|
||||
public static final String PARAM_MODE = "mode";
|
||||
public static final String PARAM_REVISION = "revision";
|
||||
@@ -72,6 +73,12 @@ public abstract class RdeModule {
|
||||
return extractBooleanParameter(req, PARAM_MANUAL);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter(PARAM_BEAM)
|
||||
static boolean provideBeam(HttpServletRequest req) {
|
||||
return extractBooleanParameter(req, PARAM_BEAM);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter(PARAM_DIRECTORY)
|
||||
static Optional<String> provideDirectory(HttpServletRequest req) {
|
||||
|
||||
@@ -264,6 +264,11 @@ public final class RdeStagingAction implements Runnable {
|
||||
@Inject @Config("beamStagingBucketUrl") String stagingBucketUrl;
|
||||
@Inject @Config("rdeBucket") String rdeBucket;
|
||||
@Inject @Parameter(RdeModule.PARAM_MANUAL) boolean manual;
|
||||
|
||||
@Inject
|
||||
@Parameter(RdeModule.PARAM_BEAM)
|
||||
boolean beam;
|
||||
|
||||
@Inject @Parameter(RdeModule.PARAM_DIRECTORY) Optional<String> directory;
|
||||
@Inject @Parameter(RdeModule.PARAM_MODE) ImmutableSet<String> modeStrings;
|
||||
@Inject @Parameter(RequestParameters.PARAM_TLDS) ImmutableSet<String> tlds;
|
||||
@@ -289,7 +294,7 @@ public final class RdeStagingAction implements Runnable {
|
||||
logger.atInfo().log("Pending deposit: %s", pending);
|
||||
}
|
||||
ValidationMode validationMode = lenient ? LENIENT : STRICT;
|
||||
if (tm().isOfy()) {
|
||||
if (tm().isOfy() && !beam) {
|
||||
RdeStagingMapper mapper = new RdeStagingMapper(validationMode, pendings);
|
||||
RdeStagingReducer reducer = reducerFactory.create(validationMode, gcsUtils);
|
||||
mrRunner
|
||||
@@ -382,6 +387,9 @@ public final class RdeStagingAction implements Runnable {
|
||||
if (revision.isPresent()) {
|
||||
throw new BadRequestException("Revision parameter not allowed in standard operation");
|
||||
}
|
||||
if (beam) {
|
||||
throw new BadRequestException("Beam parameter not allowed in standard operation");
|
||||
}
|
||||
|
||||
return ImmutableSetMultimap.copyOf(
|
||||
Multimaps.filterValues(
|
||||
|
||||
@@ -67,10 +67,16 @@ class RequestMetrics {
|
||||
private static String truncatePath(String path) {
|
||||
// We want to bucket RDAP requests by type to use less metric space,
|
||||
// e.g. "/rdap/domains" rather than "/rdap/domains/foo.tld"
|
||||
|
||||
if (path.startsWith("/rdap")) {
|
||||
List<String> splitPath = Splitter.on("/").omitEmptyStrings().splitToList(path);
|
||||
return Streams.stream(Iterables.limit(splitPath, 2))
|
||||
.collect(Collectors.joining("/", "/", "/"));
|
||||
// Similarly, we put all web WHOIS requests under the same path because otherwise its
|
||||
// cardinality is unbound, and it is possible to generate a huge amount of metrics with all
|
||||
// the different paths.
|
||||
} else if (path.startsWith("/whois")) {
|
||||
return "/whois";
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -18,14 +18,21 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.SYNTHETIC;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Streams;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Tool to enqueue a poll message for a registrar.
|
||||
@@ -54,14 +61,26 @@ class EnqueuePollMessageCommand extends MutatingCommand {
|
||||
String domainName;
|
||||
|
||||
@Parameter(
|
||||
names = {"-c", "--client"},
|
||||
names = {"-c", "--clients"},
|
||||
description =
|
||||
"Client identifier of the registrar to send the poll message to, if not the owning"
|
||||
+ " registrar of the domain")
|
||||
String clientId;
|
||||
"Comma-delimited list of the client identifier(s) of the registrar(s) to send the poll"
|
||||
+ " message to, if not the owning registrar of the domain")
|
||||
List<String> clientIds;
|
||||
|
||||
@Parameter(
|
||||
names = {"-a", "--all"},
|
||||
description = "Whether to send the message to all real registrars",
|
||||
arity = 1)
|
||||
boolean sendToAll;
|
||||
|
||||
@Inject
|
||||
@Config("registryAdminClientId")
|
||||
String registryAdminClientId;
|
||||
|
||||
@Override
|
||||
protected final void init() {
|
||||
checkArgument(
|
||||
!sendToAll || isNullOrEmpty(clientIds), "Cannot specify both --all and --clients");
|
||||
tm().transact(
|
||||
() -> {
|
||||
Optional<DomainBase> domainOpt =
|
||||
@@ -69,27 +88,39 @@ class EnqueuePollMessageCommand extends MutatingCommand {
|
||||
checkArgument(
|
||||
domainOpt.isPresent(), "Domain %s doesn't exist or isn't active", domainName);
|
||||
DomainBase domain = domainOpt.get();
|
||||
String registrarId =
|
||||
Optional.ofNullable(clientId).orElse(domain.getCurrentSponsorRegistrarId());
|
||||
ImmutableList<String> registrarIds;
|
||||
if (sendToAll) {
|
||||
registrarIds =
|
||||
Streams.stream(Registrar.loadAllCached())
|
||||
.filter(r -> r.isLive() && r.getType() == Registrar.Type.REAL)
|
||||
.map(Registrar::getRegistrarId)
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
} else if (!isNullOrEmpty(clientIds)) {
|
||||
registrarIds = ImmutableList.copyOf(clientIds);
|
||||
} else {
|
||||
registrarIds = ImmutableList.of(domain.getCurrentSponsorRegistrarId());
|
||||
}
|
||||
HistoryEntry historyEntry =
|
||||
new DomainHistory.Builder()
|
||||
.setDomain(domain)
|
||||
.setType(SYNTHETIC)
|
||||
.setBySuperuser(true)
|
||||
.setReason("Manual enqueueing of poll message")
|
||||
.setReason("Manual enqueueing of poll message: " + message)
|
||||
.setModificationTime(tm().getTransactionTime())
|
||||
.setRequestedByRegistrar(false)
|
||||
.setRegistrarId(registrarId)
|
||||
.build();
|
||||
PollMessage.OneTime pollMessage =
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setRegistrarId(registrarId)
|
||||
.setParent(historyEntry)
|
||||
.setEventTime(tm().getTransactionTime())
|
||||
.setMsg(message)
|
||||
.setRegistrarId(registryAdminClientId)
|
||||
.build();
|
||||
stageEntityChange(null, historyEntry);
|
||||
stageEntityChange(null, pollMessage);
|
||||
for (String registrarId : registrarIds) {
|
||||
stageEntityChange(
|
||||
null,
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setRegistrarId(registrarId)
|
||||
.setParent(historyEntry)
|
||||
.setEventTime(tm().getTransactionTime())
|
||||
.setMsg(message)
|
||||
.build());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ package google.registry.tools;
|
||||
|
||||
import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
|
||||
import static google.registry.model.tld.Registries.assertTldsExist;
|
||||
import static google.registry.rde.RdeModule.PARAM_BEAM;
|
||||
import static google.registry.rde.RdeModule.PARAM_DIRECTORY;
|
||||
import static google.registry.rde.RdeModule.PARAM_LENIENT;
|
||||
import static google.registry.rde.RdeModule.PARAM_MANUAL;
|
||||
import static google.registry.rde.RdeModule.PARAM_MODE;
|
||||
import static google.registry.rde.RdeModule.PARAM_REVISION;
|
||||
@@ -65,6 +67,20 @@ final class GenerateEscrowDepositCommand implements CommandWithRemoteApi {
|
||||
description = "Mode of operation: FULL for RDE deposits, THIN for BRDA deposits.")
|
||||
private RdeMode mode = RdeMode.FULL;
|
||||
|
||||
@Parameter(
|
||||
names = {"-l", "--lenient"},
|
||||
description =
|
||||
"Whether to run RDE in LENIENT mode, which omits validation of the generated "
|
||||
+ "XML deposit files.")
|
||||
private boolean lenient = false;
|
||||
|
||||
@Parameter(
|
||||
names = {"-b", "--beam"},
|
||||
description =
|
||||
"Whether to explicitly launch the beam pipeline instead of letting the action decide"
|
||||
+ " which one to run.")
|
||||
private boolean beam = false;
|
||||
|
||||
@Parameter(
|
||||
names = {"-r", "--revision"},
|
||||
description = "Revision number. Use >0 for resends.")
|
||||
@@ -119,6 +135,8 @@ final class GenerateEscrowDepositCommand implements CommandWithRemoteApi {
|
||||
.param(PARAM_MANUAL, String.valueOf(true))
|
||||
.param(PARAM_MODE, mode.toString())
|
||||
.param(PARAM_DIRECTORY, outdir)
|
||||
.param(PARAM_LENIENT, Boolean.toString(lenient))
|
||||
.param(PARAM_BEAM, Boolean.toString(beam))
|
||||
.param(PARAM_TLDS, tlds.stream().collect(Collectors.joining(",")))
|
||||
.param(
|
||||
PARAM_WATERMARKS,
|
||||
|
||||
@@ -48,6 +48,7 @@ import com.google.common.truth.Truth8;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.gcs.GcsUtils;
|
||||
import google.registry.model.common.ClassPathManager;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule;
|
||||
import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
@@ -67,7 +68,6 @@ import google.registry.model.replay.SqlReplayCheckpoint;
|
||||
import google.registry.model.server.Lock;
|
||||
import google.registry.model.tld.label.PremiumList;
|
||||
import google.registry.model.tld.label.PremiumList.PremiumEntry;
|
||||
import google.registry.model.translators.VKeyTranslatorFactory;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.persistence.transaction.TransactionManagerFactory;
|
||||
@@ -130,7 +130,7 @@ public class ReplayCommitLogsToSqlActionTest {
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
VKeyTranslatorFactory.addTestEntityClass(TestObject.class);
|
||||
ClassPathManager.addTestEntityClass(TestObject.class);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
|
||||
@@ -344,7 +344,7 @@ public class SyncRegistrarsSheetTest {
|
||||
ImmutableMap<String, String> row = getOnlyElement(getOnlyElement(rowsCaptor.getAllValues()));
|
||||
assertThat(row).containsEntry("clientIdentifier", "SomeRegistrar");
|
||||
assertThat(row).containsEntry("registrarName", "Some Registrar");
|
||||
assertThat(row).containsEntry("state", "");
|
||||
assertThat(row).containsEntry("state", "ACTIVE");
|
||||
assertThat(row).containsEntry("ianaIdentifier", "8");
|
||||
assertThat(row).containsEntry("billingIdentifier", "");
|
||||
assertThat(row).containsEntry("primaryContacts", "");
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
// Copyright 2021 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.common;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import google.registry.model.billing.BillingEvent.Cancellation;
|
||||
import google.registry.model.billing.BillingEvent.Modification;
|
||||
import google.registry.model.billing.BillingEvent.OneTime;
|
||||
import google.registry.model.billing.BillingEvent.Recurring;
|
||||
import google.registry.model.contact.ContactResource;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.model.index.EppResourceIndex;
|
||||
import google.registry.model.index.EppResourceIndexBucket;
|
||||
import google.registry.model.index.ForeignKeyIndex.ForeignKeyContactIndex;
|
||||
import google.registry.model.index.ForeignKeyIndex.ForeignKeyDomainIndex;
|
||||
import google.registry.model.index.ForeignKeyIndex.ForeignKeyHostIndex;
|
||||
import google.registry.model.ofy.CommitLogBucket;
|
||||
import google.registry.model.ofy.CommitLogCheckpoint;
|
||||
import google.registry.model.ofy.CommitLogCheckpointRoot;
|
||||
import google.registry.model.ofy.CommitLogManifest;
|
||||
import google.registry.model.ofy.CommitLogMutation;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.rde.RdeRevision;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarContact;
|
||||
import google.registry.model.replay.LastSqlTransaction;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.server.Lock;
|
||||
import google.registry.model.server.ServerSecret;
|
||||
import google.registry.model.tld.Registry;
|
||||
import google.registry.testing.TestObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ClassPathManager}. */
|
||||
public class ClassPathManagerTest {
|
||||
@Test
|
||||
void getClass_classInClassRegistry_returnsClass() throws ClassNotFoundException {
|
||||
/**
|
||||
* Class names are used in stringified vkeys, which can be present in task queues. Class name is
|
||||
* required to create a vkey. Changing these names could break task queue entries that are
|
||||
* present during a rollout. If you want to change the names of any of the classses supported in
|
||||
* CLASS_REGISTRY, you'll need to introduce some mechanism to deal with this. One way is to find
|
||||
* the corresponding class name by calling ClassPathManager.getClassName(clazz). The classes
|
||||
* below are all classes supported in CLASS_REGISTRY. This test breaks if someone changes a
|
||||
* classname without preserving the original name.
|
||||
*/
|
||||
assertThat(ClassPathManager.getClass("ForeignKeyContactIndex"))
|
||||
.isEqualTo(ForeignKeyContactIndex.class);
|
||||
assertThat(ClassPathManager.getClass("Modification")).isEqualTo(Modification.class);
|
||||
assertThat(ClassPathManager.getClass("CommitLogCheckpoint"))
|
||||
.isEqualTo(CommitLogCheckpoint.class);
|
||||
assertThat(ClassPathManager.getClass("CommitLogManifest")).isEqualTo(CommitLogManifest.class);
|
||||
assertThat(ClassPathManager.getClass("AllocationToken")).isEqualTo(AllocationToken.class);
|
||||
assertThat(ClassPathManager.getClass("OneTime")).isEqualTo(OneTime.class);
|
||||
assertThat(ClassPathManager.getClass("Cursor")).isEqualTo(Cursor.class);
|
||||
assertThat(ClassPathManager.getClass("RdeRevision")).isEqualTo(RdeRevision.class);
|
||||
assertThat(ClassPathManager.getClass("HostResource")).isEqualTo(HostResource.class);
|
||||
assertThat(ClassPathManager.getClass("Recurring")).isEqualTo(Recurring.class);
|
||||
assertThat(ClassPathManager.getClass("Registrar")).isEqualTo(Registrar.class);
|
||||
assertThat(ClassPathManager.getClass("ContactResource")).isEqualTo(ContactResource.class);
|
||||
assertThat(ClassPathManager.getClass("Cancellation")).isEqualTo(Cancellation.class);
|
||||
assertThat(ClassPathManager.getClass("RegistrarContact")).isEqualTo(RegistrarContact.class);
|
||||
assertThat(ClassPathManager.getClass("CommitLogBucket")).isEqualTo(CommitLogBucket.class);
|
||||
assertThat(ClassPathManager.getClass("LastSqlTransaction")).isEqualTo(LastSqlTransaction.class);
|
||||
assertThat(ClassPathManager.getClass("CommitLogCheckpointRoot"))
|
||||
.isEqualTo(CommitLogCheckpointRoot.class);
|
||||
assertThat(ClassPathManager.getClass("GaeUserIdConverter")).isEqualTo(GaeUserIdConverter.class);
|
||||
assertThat(ClassPathManager.getClass("EppResourceIndexBucket"))
|
||||
.isEqualTo(EppResourceIndexBucket.class);
|
||||
assertThat(ClassPathManager.getClass("Registry")).isEqualTo(Registry.class);
|
||||
assertThat(ClassPathManager.getClass("EntityGroupRoot")).isEqualTo(EntityGroupRoot.class);
|
||||
assertThat(ClassPathManager.getClass("Lock")).isEqualTo(Lock.class);
|
||||
assertThat(ClassPathManager.getClass("DomainBase")).isEqualTo(DomainBase.class);
|
||||
assertThat(ClassPathManager.getClass("CommitLogMutation")).isEqualTo(CommitLogMutation.class);
|
||||
assertThat(ClassPathManager.getClass("HistoryEntry")).isEqualTo(HistoryEntry.class);
|
||||
assertThat(ClassPathManager.getClass("PollMessage")).isEqualTo(PollMessage.class);
|
||||
assertThat(ClassPathManager.getClass("ForeignKeyHostIndex"))
|
||||
.isEqualTo(ForeignKeyHostIndex.class);
|
||||
assertThat(ClassPathManager.getClass("ServerSecret")).isEqualTo(ServerSecret.class);
|
||||
assertThat(ClassPathManager.getClass("EppResourceIndex")).isEqualTo(EppResourceIndex.class);
|
||||
assertThat(ClassPathManager.getClass("ForeignKeyDomainIndex"))
|
||||
.isEqualTo(ForeignKeyDomainIndex.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getClass_classNotInClassRegistry_throwsException() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> ClassPathManager.getClass("DomainHistory"));
|
||||
assertThat(thrown).hasMessageThat().contains("Class not found in class registry");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getClassName_classNotInClassRegistry_throwsException() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> ClassPathManager.getClassName(DomainHistory.class));
|
||||
assertThat(thrown).hasMessageThat().contains("Class not found in class name registry");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getClassName() {
|
||||
/**
|
||||
* Class names are used in stringified vkeys, which can be present in task queues. Class name is
|
||||
* required to create a vkey. Changing these names could break task queue entries that are
|
||||
* present during a rollout. If you want to change the names of any of the classses supported in
|
||||
* CLASS_NAME_REGISTRY, you'll need to introduce some mechanism to deal with this.
|
||||
* ClassPathManager.getClassName(clazz) allows you to verify the corresponding name of a class.
|
||||
* The classes below are all classes supported in CLASS_NAME_REGISTRY. This test breaks if
|
||||
* someone changes a classname without preserving the original name.
|
||||
*/
|
||||
assertThat(ClassPathManager.getClassName(ForeignKeyContactIndex.class))
|
||||
.isEqualTo("ForeignKeyContactIndex");
|
||||
assertThat(ClassPathManager.getClassName(Modification.class)).isEqualTo("Modification");
|
||||
assertThat(ClassPathManager.getClassName(CommitLogCheckpoint.class))
|
||||
.isEqualTo("CommitLogCheckpoint");
|
||||
assertThat(ClassPathManager.getClassName(CommitLogManifest.class))
|
||||
.isEqualTo("CommitLogManifest");
|
||||
assertThat(ClassPathManager.getClassName(AllocationToken.class)).isEqualTo("AllocationToken");
|
||||
assertThat(ClassPathManager.getClassName(OneTime.class)).isEqualTo("OneTime");
|
||||
assertThat(ClassPathManager.getClassName(Cursor.class)).isEqualTo("Cursor");
|
||||
assertThat(ClassPathManager.getClassName(RdeRevision.class)).isEqualTo("RdeRevision");
|
||||
assertThat(ClassPathManager.getClassName(HostResource.class)).isEqualTo("HostResource");
|
||||
assertThat(ClassPathManager.getClassName(Recurring.class)).isEqualTo("Recurring");
|
||||
assertThat(ClassPathManager.getClassName(Registrar.class)).isEqualTo("Registrar");
|
||||
assertThat(ClassPathManager.getClassName(ContactResource.class)).isEqualTo("ContactResource");
|
||||
assertThat(ClassPathManager.getClassName(Cancellation.class)).isEqualTo("Cancellation");
|
||||
assertThat(ClassPathManager.getClassName(RegistrarContact.class)).isEqualTo("RegistrarContact");
|
||||
assertThat(ClassPathManager.getClassName(CommitLogBucket.class)).isEqualTo("CommitLogBucket");
|
||||
assertThat(ClassPathManager.getClassName(LastSqlTransaction.class))
|
||||
.isEqualTo("LastSqlTransaction");
|
||||
assertThat(ClassPathManager.getClassName(CommitLogCheckpointRoot.class))
|
||||
.isEqualTo("CommitLogCheckpointRoot");
|
||||
assertThat(ClassPathManager.getClassName(GaeUserIdConverter.class))
|
||||
.isEqualTo("GaeUserIdConverter");
|
||||
assertThat(ClassPathManager.getClassName(EppResourceIndexBucket.class))
|
||||
.isEqualTo("EppResourceIndexBucket");
|
||||
assertThat(ClassPathManager.getClassName(Registry.class)).isEqualTo("Registry");
|
||||
assertThat(ClassPathManager.getClassName(EntityGroupRoot.class)).isEqualTo("EntityGroupRoot");
|
||||
assertThat(ClassPathManager.getClassName(Lock.class)).isEqualTo("Lock");
|
||||
assertThat(ClassPathManager.getClassName(DomainBase.class)).isEqualTo("DomainBase");
|
||||
assertThat(ClassPathManager.getClassName(CommitLogMutation.class))
|
||||
.isEqualTo("CommitLogMutation");
|
||||
assertThat(ClassPathManager.getClassName(HistoryEntry.class)).isEqualTo("HistoryEntry");
|
||||
assertThat(ClassPathManager.getClassName(PollMessage.class)).isEqualTo("PollMessage");
|
||||
assertThat(ClassPathManager.getClassName(ForeignKeyHostIndex.class))
|
||||
.isEqualTo("ForeignKeyHostIndex");
|
||||
assertThat(ClassPathManager.getClassName(ServerSecret.class)).isEqualTo("ServerSecret");
|
||||
assertThat(ClassPathManager.getClassName(EppResourceIndex.class)).isEqualTo("EppResourceIndex");
|
||||
assertThat(ClassPathManager.getClassName(ForeignKeyDomainIndex.class))
|
||||
.isEqualTo("ForeignKeyDomainIndex");
|
||||
}
|
||||
|
||||
@Test
|
||||
void addTestEntityClass_success() {
|
||||
ClassPathManager.addTestEntityClass(TestObject.class);
|
||||
assertThat(ClassPathManager.getClass("TestObject")).isEqualTo(TestObject.class);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.common.ClassPathManager;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.ofy.CommitLogCheckpoint;
|
||||
import google.registry.model.ofy.CommitLogCheckpointRoot;
|
||||
@@ -32,6 +33,7 @@ import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link VKeyTranslatorFactory}. */
|
||||
public class VKeyTranslatorFactoryTest {
|
||||
|
||||
@RegisterExtension
|
||||
@@ -45,7 +47,7 @@ public class VKeyTranslatorFactoryTest {
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
VKeyTranslatorFactory.addTestEntityClass(TestObject.class);
|
||||
ClassPathManager.addTestEntityClass(TestObject.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -27,9 +27,9 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import google.registry.model.billing.BillingEvent.OneTime;
|
||||
import google.registry.model.common.ClassPathManager;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.registrar.RegistrarContact;
|
||||
import google.registry.model.translators.VKeyTranslatorFactory;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import google.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import google.registry.testing.TestObject;
|
||||
@@ -63,7 +63,7 @@ class VKeyTest {
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
VKeyTranslatorFactory.addTestEntityClass(TestObject.class);
|
||||
ClassPathManager.addTestEntityClass(TestObject.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -161,14 +161,13 @@ class VKeyTest {
|
||||
@Test
|
||||
void testStringify_sqlOnlyVKey() throws Exception {
|
||||
assertThat(VKey.createSql(TestObject.class, "foo").stringify())
|
||||
.isEqualTo("kind:google.registry.testing.TestObject@sql:rO0ABXQAA2Zvbw");
|
||||
.isEqualTo("kind:TestObject@sql:rO0ABXQAA2Zvbw");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStringify_ofyOnlyVKey() throws Exception {
|
||||
assertThat(VKey.createOfy(TestObject.class, Key.create(TestObject.class, "foo")).stringify())
|
||||
.isEqualTo(
|
||||
"kind:google.registry.testing.TestObject@ofy:agR0ZXN0chMLEgpUZXN0T2JqZWN0IgNmb28M");
|
||||
.isEqualTo("kind:TestObject@ofy:agR0ZXN0chMLEgpUZXN0T2JqZWN0IgNmb28M");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -178,8 +177,8 @@ class VKeyTest {
|
||||
VKey<DomainBase> vkey = VKey.fromWebsafeKey(key.getString());
|
||||
assertThat(vkey.stringify())
|
||||
.isEqualTo(
|
||||
"kind:google.registry.model.domain.DomainBas"
|
||||
+ "e@sql:rO0ABXQABlJPSUQtMQ"
|
||||
"kind:DomainBase"
|
||||
+ "@sql:rO0ABXQABlJPSUQtMQ"
|
||||
+ "@ofy:agR0ZXN0chYLEgpEb21haW5CYXNlIgZST0lELTEM");
|
||||
}
|
||||
|
||||
@@ -188,7 +187,7 @@ class VKeyTest {
|
||||
assertThat(
|
||||
VKey.create(TestObject.class, "foo", Key.create(TestObject.create("foo"))).stringify())
|
||||
.isEqualTo(
|
||||
"kind:google.registry.testing.TestObject@sql:rO0ABXQAA2Zvbw@ofy:agR0ZXN0cjELEg9FbnRpdH"
|
||||
"kind:TestObject@sql:rO0ABXQAA2Zvbw@ofy:agR0ZXN0cjELEg9FbnRpdH"
|
||||
+ "lHcm91cFJvb3QiCWNyb3NzLXRsZAwLEgpUZXN0T2JqZWN0IgNmb28M");
|
||||
}
|
||||
|
||||
@@ -197,22 +196,20 @@ class VKeyTest {
|
||||
assertThat(
|
||||
VKey.create(TestObject.class, "test", Key.create(TestObject.create("foo"))).stringify())
|
||||
.isEqualTo(
|
||||
"kind:google.registry.testing.TestObject@sql:rO0ABXQABHRlc3Q@ofy:agR0ZXN0cjELEg9FbnRpd"
|
||||
"kind:TestObject@sql:rO0ABXQABHRlc3Q@ofy:agR0ZXN0cjELEg9FbnRpd"
|
||||
+ "HlHcm91cFJvb3QiCWNyb3NzLXRsZAwLEgpUZXN0T2JqZWN0IgNmb28M");
|
||||
}
|
||||
|
||||
/** Test create() via different vkey string representations. */
|
||||
@Test
|
||||
void testCreate_stringifedVKey_sqlOnlyVKeyString() throws Exception {
|
||||
assertThat(VKey.create("kind:google.registry.testing.TestObject@sql:rO0ABXQAA2Zvbw"))
|
||||
assertThat(VKey.create("kind:TestObject@sql:rO0ABXQAA2Zvbw"))
|
||||
.isEqualTo(VKey.createSql(TestObject.class, "foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreate_stringifedVKey_ofyOnlyVKeyString() throws Exception {
|
||||
assertThat(
|
||||
VKey.create(
|
||||
"kind:google.registry.testing.TestObject@ofy:agR0ZXN0chMLEgpUZXN0T2JqZWN0IgNmb28M"))
|
||||
assertThat(VKey.create("kind:TestObject@ofy:agR0ZXN0chMLEgpUZXN0T2JqZWN0IgNmb28M"))
|
||||
.isEqualTo(VKey.createOfy(TestObject.class, Key.create(TestObject.class, "foo")));
|
||||
}
|
||||
|
||||
@@ -220,7 +217,7 @@ class VKeyTest {
|
||||
void testCreate_stringifedVKey_asymmetricVKeyString() throws Exception {
|
||||
assertThat(
|
||||
VKey.create(
|
||||
"kind:google.registry.testing.TestObject@sql:rO0ABXQABHRlc3Q@ofy:agR0ZXN0cjELEg9Fb"
|
||||
"kind:TestObject@sql:rO0ABXQABHRlc3Q@ofy:agR0ZXN0cjELEg9Fb"
|
||||
+ "nRpdHlHcm91cFJvb3QiCWNyb3NzLXRsZAwLEgpUZXN0T2JqZWN0IgNmb28M"))
|
||||
.isEqualTo(VKey.create(TestObject.class, "test", Key.create(TestObject.create("foo"))));
|
||||
}
|
||||
@@ -229,7 +226,7 @@ class VKeyTest {
|
||||
void testCreate_stringifedVKey_sqlAndOfyVKeyString() throws Exception {
|
||||
assertThat(
|
||||
VKey.create(
|
||||
"kind:google.registry.testing.TestObject@sql:rO0ABXQAA2Zvbw@ofy:agR0ZXN0cjELEg9Fbn"
|
||||
"kind:TestObject@sql:rO0ABXQAA2Zvbw@ofy:agR0ZXN0cjELEg9Fbn"
|
||||
+ "RpdHlHcm91cFJvb3QiCWNyb3NzLXRsZAwLEgpUZXN0T2JqZWN0IgNmb28M"))
|
||||
.isEqualTo(VKey.create(TestObject.class, "foo", Key.create(TestObject.create("foo"))));
|
||||
}
|
||||
@@ -238,7 +235,7 @@ class VKeyTest {
|
||||
void testCreate_stringifyVkey_fromWebsafeKey() throws Exception {
|
||||
assertThat(
|
||||
VKey.create(
|
||||
"kind:google.registry.model.domain.DomainBase@sql:rO0ABXQABlJPSUQtMQ"
|
||||
"kind:DomainBase@sql:rO0ABXQABlJPSUQtMQ"
|
||||
+ "@ofy:agR0ZXN0chYLEgpEb21haW5CYXNlIgZST0lELTEM"))
|
||||
.isEqualTo(
|
||||
VKey.fromWebsafeKey(
|
||||
@@ -257,11 +254,10 @@ class VKeyTest {
|
||||
void testCreate_invalidStringifiedVKey_failure() throws Exception {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> VKey.create("kind:google.registry.testing.TestObject@sq:l@ofya:bc"));
|
||||
IllegalArgumentException.class, () -> VKey.create("kind:TestObject@sq:l@ofya:bc"));
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.contains("Cannot parse key string: kind:google.registry.testing.TestObject@sq:l@ofya:bc");
|
||||
.contains("Cannot parse key string: kind:TestObject@sq:l@ofya:bc");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -96,6 +96,7 @@ import google.registry.model.index.ForeignKeyIndex;
|
||||
import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.pricing.StaticPremiumListPricingEngine;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.Registrar.State;
|
||||
import google.registry.model.registrar.RegistrarAddress;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.reporting.HistoryEntryDao;
|
||||
@@ -758,6 +759,7 @@ public class DatabaseHelper {
|
||||
.setRegistrarId(registrarId)
|
||||
.setRegistrarName(registrarName)
|
||||
.setType(type)
|
||||
.setState(State.ACTIVE)
|
||||
.setIanaIdentifier(ianaIdentifier)
|
||||
.setLocalizedAddress(
|
||||
new RegistrarAddress.Builder()
|
||||
|
||||
@@ -20,6 +20,7 @@ import static google.registry.testing.DatabaseHelper.assertPollMessages;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.getOnlyHistoryEntryOfType;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistNewRegistrar;
|
||||
import static google.registry.testing.HistoryEntrySubject.assertAboutHistoryEntries;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
@@ -47,6 +48,8 @@ class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCo
|
||||
createTld("tld");
|
||||
inject.setStaticField(Ofy.class, "clock", fakeClock);
|
||||
domain = persistActiveDomain("example.tld");
|
||||
persistNewRegistrar("AdminRegistrar");
|
||||
command.registryAdminClientId = "AdminRegistrar";
|
||||
fakeClock.advanceOneMilli();
|
||||
}
|
||||
|
||||
@@ -59,11 +62,11 @@ class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCo
|
||||
.that(synthetic)
|
||||
.bySuperuser(true)
|
||||
.and()
|
||||
.hasMetadataReason("Manual enqueueing of poll message")
|
||||
.hasMetadataReason("Manual enqueueing of poll message: This domain is bad")
|
||||
.and()
|
||||
.hasNoXml()
|
||||
.and()
|
||||
.hasRegistrarId("TheRegistrar")
|
||||
.hasRegistrarId("AdminRegistrar")
|
||||
.and()
|
||||
.hasModificationTime(fakeClock.nowUtc())
|
||||
.and()
|
||||
@@ -79,24 +82,35 @@ class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCo
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_specifyClientId() throws Exception {
|
||||
void testSuccess_specifyClientIds() throws Exception {
|
||||
persistNewRegistrar("foobaz");
|
||||
runCommandForced(
|
||||
"--domain=example.tld", "--message=This domain needs work", "--client=NewRegistrar");
|
||||
"--domain=example.tld",
|
||||
"--message=This domain needs work",
|
||||
"--clients=TheRegistrar,NewRegistrar,foobaz");
|
||||
|
||||
HistoryEntry synthetic = getOnlyHistoryEntryOfType(domain, SYNTHETIC);
|
||||
assertAboutHistoryEntries()
|
||||
.that(synthetic)
|
||||
.bySuperuser(true)
|
||||
.and()
|
||||
.hasMetadataReason("Manual enqueueing of poll message")
|
||||
.hasMetadataReason("Manual enqueueing of poll message: This domain needs work")
|
||||
.and()
|
||||
.hasNoXml()
|
||||
.and()
|
||||
.hasRegistrarId("NewRegistrar")
|
||||
.hasRegistrarId("AdminRegistrar")
|
||||
.and()
|
||||
.hasModificationTime(fakeClock.nowUtc())
|
||||
.and()
|
||||
.hasMetadataRequestedByRegistrar(false);
|
||||
assertPollMessages(
|
||||
"TheRegistrar",
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setParent(synthetic)
|
||||
.setMsg("This domain needs work")
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(fakeClock.nowUtc())
|
||||
.build());
|
||||
assertPollMessages(
|
||||
"NewRegistrar",
|
||||
new PollMessage.OneTime.Builder()
|
||||
@@ -105,6 +119,59 @@ class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCo
|
||||
.setRegistrarId("NewRegistrar")
|
||||
.setEventTime(fakeClock.nowUtc())
|
||||
.build());
|
||||
assertPollMessages(
|
||||
"foobaz",
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setParent(synthetic)
|
||||
.setMsg("This domain needs work")
|
||||
.setRegistrarId("foobaz")
|
||||
.setEventTime(fakeClock.nowUtc())
|
||||
.build());
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testSuccess_sendToAllRegistrars() throws Exception {
|
||||
persistNewRegistrar("foobaz");
|
||||
runCommandForced("--domain=example.tld", "--message=This domain needs work", "--all=true");
|
||||
|
||||
HistoryEntry synthetic = getOnlyHistoryEntryOfType(domain, SYNTHETIC);
|
||||
assertAboutHistoryEntries()
|
||||
.that(synthetic)
|
||||
.bySuperuser(true)
|
||||
.and()
|
||||
.hasMetadataReason("Manual enqueueing of poll message: This domain needs work")
|
||||
.and()
|
||||
.hasNoXml()
|
||||
.and()
|
||||
.hasRegistrarId("AdminRegistrar")
|
||||
.and()
|
||||
.hasModificationTime(fakeClock.nowUtc())
|
||||
.and()
|
||||
.hasMetadataRequestedByRegistrar(false);
|
||||
assertPollMessages(
|
||||
"TheRegistrar",
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setParent(synthetic)
|
||||
.setMsg("This domain needs work")
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(fakeClock.nowUtc())
|
||||
.build());
|
||||
assertPollMessages(
|
||||
"NewRegistrar",
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setParent(synthetic)
|
||||
.setMsg("This domain needs work")
|
||||
.setRegistrarId("NewRegistrar")
|
||||
.setEventTime(fakeClock.nowUtc())
|
||||
.build());
|
||||
assertPollMessages(
|
||||
"foobaz",
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setParent(synthetic)
|
||||
.setMsg("This domain needs work")
|
||||
.setRegistrarId("foobaz")
|
||||
.setEventTime(fakeClock.nowUtc())
|
||||
.build());
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
@@ -131,4 +198,18 @@ class EnqueuePollMessageCommandTest extends CommandTestCase<EnqueuePollMessageCo
|
||||
assertThrows(ParameterException.class, () -> runCommandForced("--domain=example.tld"));
|
||||
assertThat(thrown).hasMessageThat().contains("The following option is required: -m, --message");
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
void testCantSpecifyClientIdsAndAll() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
runCommandForced(
|
||||
"--domain=example.tld",
|
||||
"--message=Domain is ended",
|
||||
"--all=true",
|
||||
"--clients=TheRegistrar"));
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("Cannot specify both --all and --clients");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +188,55 @@ public class GenerateEscrowDepositCommandTest
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCommand_success() throws Exception {
|
||||
void testCommand_successWithLenientValidationMode() throws Exception {
|
||||
runCommand(
|
||||
"--tld=tld",
|
||||
"--watermark=2017-01-01T00:00:00Z",
|
||||
"--mode=thin",
|
||||
"--lenient",
|
||||
"-r 42",
|
||||
"-o test");
|
||||
|
||||
assertTasksEnqueued(
|
||||
"rde-report",
|
||||
new TaskMatcher()
|
||||
.url("/_dr/task/rdeStaging")
|
||||
.header("Host", "backend.test.localhost")
|
||||
.param("mode", "THIN")
|
||||
.param("lenient", "true")
|
||||
.param("watermarks", "2017-01-01T00:00:00.000Z")
|
||||
.param("tlds", "tld")
|
||||
.param("directory", "test")
|
||||
.param("manual", "true")
|
||||
.param("revision", "42"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCommand_successWithBeam() throws Exception {
|
||||
runCommand(
|
||||
"--tld=tld",
|
||||
"--watermark=2017-01-01T00:00:00Z",
|
||||
"--mode=thin",
|
||||
"--beam",
|
||||
"-r 42",
|
||||
"-o test");
|
||||
|
||||
assertTasksEnqueued(
|
||||
"rde-report",
|
||||
new TaskMatcher()
|
||||
.url("/_dr/task/rdeStaging")
|
||||
.header("Host", "backend.test.localhost")
|
||||
.param("mode", "THIN")
|
||||
.param("beam", "true")
|
||||
.param("watermarks", "2017-01-01T00:00:00.000Z")
|
||||
.param("tlds", "tld")
|
||||
.param("directory", "test")
|
||||
.param("manual", "true")
|
||||
.param("revision", "42"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCommand_successWithDefaultValidationMode() throws Exception {
|
||||
runCommand("--tld=tld", "--watermark=2017-01-01T00:00:00Z", "--mode=thin", "-r 42", "-o test");
|
||||
|
||||
assertTasksEnqueued(
|
||||
@@ -197,6 +245,7 @@ public class GenerateEscrowDepositCommandTest
|
||||
.url("/_dr/task/rdeStaging")
|
||||
.header("Host", "backend.test.localhost")
|
||||
.param("mode", "THIN")
|
||||
.param("lenient", "false")
|
||||
.param("watermarks", "2017-01-01T00:00:00.000Z")
|
||||
.param("tlds", "tld")
|
||||
.param("directory", "test")
|
||||
@@ -213,6 +262,8 @@ public class GenerateEscrowDepositCommandTest
|
||||
new TaskMatcher()
|
||||
.url("/_dr/task/rdeStaging")
|
||||
.header("Host", "backend.test.localhost")
|
||||
.param("lenient", "false")
|
||||
.param("beam", "false")
|
||||
.param("mode", "THIN")
|
||||
.param("watermarks", "2017-01-01T00:00:00.000Z")
|
||||
.param("tlds", "tld")
|
||||
@@ -230,6 +281,8 @@ public class GenerateEscrowDepositCommandTest
|
||||
.url("/_dr/task/rdeStaging")
|
||||
.header("Host", "backend.test.localhost")
|
||||
.param("mode", "FULL")
|
||||
.param("lenient", "false")
|
||||
.param("beam", "false")
|
||||
.param("watermarks", "2017-01-01T00:00:00.000Z")
|
||||
.param("tlds", "tld")
|
||||
.param("directory", "test")
|
||||
@@ -252,6 +305,8 @@ public class GenerateEscrowDepositCommandTest
|
||||
.url("/_dr/task/rdeStaging")
|
||||
.header("Host", "backend.test.localhost")
|
||||
.param("mode", "THIN")
|
||||
.param("lenient", "false")
|
||||
.param("beam", "false")
|
||||
.param("watermarks", "2017-01-01T00:00:00.000Z,2017-01-02T00:00:00.000Z")
|
||||
.param("tlds", "tld,anothertld")
|
||||
.param("directory", "test")
|
||||
|
||||
@@ -8,7 +8,8 @@ com.diffplug.gradle.spotless:com.diffplug.gradle.spotless.gradle.plugin:3.25.0
|
||||
com.diffplug.spotless:spotless-lib-extra:1.25.0
|
||||
com.diffplug.spotless:spotless-lib:1.25.0
|
||||
com.diffplug.spotless:spotless-plugin-gradle:3.25.0
|
||||
com.dorongold.task-tree:com.dorongold.task-tree.gradle.plugin:1.5
|
||||
com.dorongold.plugins:task-tree:2.1.0
|
||||
com.dorongold.task-tree:com.dorongold.task-tree.gradle.plugin:2.1.0
|
||||
com.github.jengelman.gradle.plugins:shadow:5.1.0
|
||||
com.github.johnrengelman.shadow:com.github.johnrengelman.shadow.gradle.plugin:5.1.0
|
||||
com.github.node-gradle.node:com.github.node-gradle.node.gradle.plugin:3.0.1
|
||||
@@ -30,7 +31,6 @@ com.netflix.nebula:gradle-lint-plugin:16.0.2
|
||||
com.netflix.nebula:nebula-gradle-interop:1.0.11
|
||||
commons-io:commons-io:2.6
|
||||
commons-lang:commons-lang:2.6
|
||||
gradle.plugin.com.dorongold.plugins:task-tree:1.5
|
||||
javax.inject:javax.inject:1
|
||||
junit:junit:4.12
|
||||
nebula.lint:nebula.lint.gradle.plugin:16.0.2
|
||||
|
||||
Reference in New Issue
Block a user