mirror of
https://github.com/google/nomulus
synced 2026-05-27 10:10:38 +00:00
Compare commits
14 Commits
nomulus-20
...
proxy-2026
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8e647316e | ||
|
|
d6e0a7b979 | ||
|
|
5725eb95e0 | ||
|
|
aa12998276 | ||
|
|
d415416bc5 | ||
|
|
3a1068f313 | ||
|
|
69e5d40f04 | ||
|
|
64f6cd9af4 | ||
|
|
40184689ca | ||
|
|
826ad85d20 | ||
|
|
2b47bc9b0a | ||
|
|
9555dca8c6 | ||
|
|
49484c06d3 | ||
|
|
81d222e7d6 |
@@ -184,10 +184,10 @@ public class RdePipeline implements Serializable {
|
||||
private final CloudTasksUtils cloudTasksUtils;
|
||||
private final RdeMarshaller marshaller;
|
||||
|
||||
// Registrars to be excluded from data escrow. Not including the sandbox-only OTE type so that
|
||||
// if sneaks into production we would get an extra signal.
|
||||
// Registrars to be excluded from data escrow (i.e. all registrar types that have a null IANA
|
||||
// identifier and thus would not be valid according to the RDE schema).
|
||||
private static final ImmutableSet<Type> IGNORED_REGISTRAR_TYPES =
|
||||
Sets.immutableEnumSet(Registrar.Type.MONITORING, Registrar.Type.TEST);
|
||||
Sets.immutableEnumSet(Registrar.Type.MONITORING, Registrar.Type.OTE, Registrar.Type.TEST);
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
|
||||
@@ -1462,6 +1462,12 @@ public final class RegistryConfig {
|
||||
return ImmutableSet.copyOf(config.mosapi.services);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("mosapiTldThreadCnt")
|
||||
public static int provideMosapiTldThreads(RegistryConfigSettings config) {
|
||||
return config.mosapi.tldThreadCnt;
|
||||
}
|
||||
|
||||
private static String formatComments(String text) {
|
||||
return Splitter.on('\n').omitEmptyStrings().trimResults().splitToList(text).stream()
|
||||
.map(s -> "# " + s)
|
||||
|
||||
@@ -272,5 +272,6 @@ public class RegistryConfigSettings {
|
||||
public String entityType;
|
||||
public List<String> tlds;
|
||||
public List<String> services;
|
||||
public int tldThreadCnt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,4 +642,8 @@ mosapi:
|
||||
- "epp"
|
||||
- "dnssec"
|
||||
|
||||
# Provides a fixed thread pool for parallel TLD processing.
|
||||
# @see <a href="https://www.icann.org/mosapi-specification.pdf">
|
||||
# ICANN MoSAPI Specification, Section 12.3</a>
|
||||
tldThreadCnt: 4
|
||||
|
||||
|
||||
@@ -194,13 +194,27 @@ public final class ResourceFlowUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** Check that the same values aren't being added and removed in an update command. */
|
||||
public static void checkSameValuesNotAddedAndRemoved(
|
||||
ImmutableSet<?> fieldsToAdd, ImmutableSet<?> fieldsToRemove)
|
||||
throws AddRemoveSameValueException {
|
||||
/**
|
||||
* Verifies the adds and removes on a resource.
|
||||
*
|
||||
* <p>This throws an exception in three different situations: if the same value is being both
|
||||
* added and removed, if a value is being added that is already present, or if a value is being
|
||||
* removed that isn't present.
|
||||
*/
|
||||
public static <T> void verifyAddsAndRemoves(
|
||||
ImmutableSet<T> existingFields, ImmutableSet<T> fieldsToAdd, ImmutableSet<T> fieldsToRemove)
|
||||
throws AddRemoveSameValueException,
|
||||
AddExistingValueException,
|
||||
RemoveNonexistentValueException {
|
||||
if (!intersection(fieldsToAdd, fieldsToRemove).isEmpty()) {
|
||||
throw new AddRemoveSameValueException();
|
||||
}
|
||||
if (!intersection(fieldsToAdd, existingFields).isEmpty()) {
|
||||
throw new AddExistingValueException();
|
||||
}
|
||||
if (intersection(fieldsToRemove, existingFields).size() != fieldsToRemove.size()) {
|
||||
throw new RemoveNonexistentValueException();
|
||||
}
|
||||
}
|
||||
|
||||
/** Check that all {@link StatusValue} objects in a set are client-settable. */
|
||||
@@ -266,6 +280,20 @@ public final class ResourceFlowUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** Cannot add a value that is already present. */
|
||||
public static class AddExistingValueException extends ParameterValuePolicyErrorException {
|
||||
public AddExistingValueException() {
|
||||
super("Cannot add a value that is already present");
|
||||
}
|
||||
}
|
||||
|
||||
/** Cannot remove a value that does not exist. */
|
||||
public static class RemoveNonexistentValueException extends ParameterValuePolicyErrorException {
|
||||
public RemoveNonexistentValueException() {
|
||||
super("Cannot remove a value that does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
/** The specified status value cannot be set by clients. */
|
||||
public static class StatusNotClientSettableException extends ParameterValueRangeErrorException {
|
||||
public StatusNotClientSettableException(String statusValue) {
|
||||
|
||||
@@ -88,6 +88,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
@@ -298,11 +299,13 @@ public final class DomainCheckFlow implements TransactionalFlow {
|
||||
|
||||
boolean shouldUseTieredPricingPromotion =
|
||||
RegistryConfig.getTieredPricingPromotionRegistrarIds().contains(registrarId);
|
||||
ImmutableSet.Builder<CurrencyUnit> currenciesBuilder = new ImmutableSet.Builder<>();
|
||||
for (FeeCheckCommandExtensionItem feeCheckItem : feeCheck.getItems()) {
|
||||
for (String domainName : getDomainNamesToCheckForFee(feeCheckItem, domainNames.keySet())) {
|
||||
FeeCheckResponseExtensionItem.Builder<?> builder = feeCheckItem.createResponseBuilder();
|
||||
Optional<Domain> domain = Optional.ofNullable(domainObjs.get(domainName));
|
||||
Tld tld = Tld.get(domainNames.get(domainName).parent().toString());
|
||||
currenciesBuilder.add(tld.getCurrency());
|
||||
Optional<AllocationToken> token;
|
||||
try {
|
||||
// The precise token to use for this fee request may vary based on the domain or even the
|
||||
@@ -385,7 +388,8 @@ public final class DomainCheckFlow implements TransactionalFlow {
|
||||
responseItems.add(builder.setDomainNameIfSupported(domainName).build());
|
||||
}
|
||||
}
|
||||
return ImmutableList.of(feeCheck.createResponse(responseItems.build()));
|
||||
return ImmutableList.of(
|
||||
feeCheck.createResponse(responseItems.build(), currenciesBuilder.build()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -976,23 +976,21 @@ public class DomainFlowUtils {
|
||||
throw new UrgentAttributeNotSupportedException();
|
||||
}
|
||||
// There must be at least one of add/rem/chg, and chg isn't actually supported.
|
||||
if (secDnsUpdate.getChange() != null) {
|
||||
if (secDnsUpdate.getChange().isPresent()) {
|
||||
// The only thing you can change is maxSigLife, and we don't support that at all.
|
||||
throw new MaxSigLifeChangeNotSupportedException();
|
||||
}
|
||||
Add add = secDnsUpdate.getAdd();
|
||||
Remove remove = secDnsUpdate.getRemove();
|
||||
if (add == null && remove == null) {
|
||||
Optional<Add> add = secDnsUpdate.getAdd();
|
||||
Optional<Remove> remove = secDnsUpdate.getRemove();
|
||||
if (add.isEmpty() && remove.isEmpty()) {
|
||||
throw new EmptySecDnsUpdateException();
|
||||
}
|
||||
if (remove != null && Boolean.FALSE.equals(remove.getAll())) {
|
||||
if (remove.isPresent() && Boolean.FALSE.equals(remove.get().getAll())) {
|
||||
throw new SecDnsAllUsageException(); // Explicit all=false is meaningless.
|
||||
}
|
||||
Set<DomainDsData> toAdd = (add == null) ? ImmutableSet.of() : add.getDsData();
|
||||
Set<DomainDsData> toAdd = add.map(Add::getDsData).orElse(ImmutableSet.of());
|
||||
Set<DomainDsData> toRemove =
|
||||
(remove == null)
|
||||
? ImmutableSet.of()
|
||||
: (remove.getAll() == null) ? remove.getDsData() : oldDsData;
|
||||
remove.map(r -> (r.getAll() == null) ? r.getDsData() : oldDsData).orElse(ImmutableSet.of());
|
||||
// RFC 5910 specifies that removes are processed before adds.
|
||||
return ImmutableSet.copyOf(union(difference(oldDsData, toRemove), toAdd));
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ import static com.google.common.collect.Sets.union;
|
||||
import static google.registry.dns.DnsUtils.requestDomainDnsRefresh;
|
||||
import static google.registry.flows.FlowUtils.persistEntityChanges;
|
||||
import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn;
|
||||
import static google.registry.flows.ResourceFlowUtils.checkSameValuesNotAddedAndRemoved;
|
||||
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyAddsAndRemoves;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyAllStatusesAreClientSettable;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo;
|
||||
@@ -75,6 +75,8 @@ import google.registry.model.domain.fee.FeeUpdateCommandExtension;
|
||||
import google.registry.model.domain.metadata.MetadataExtension;
|
||||
import google.registry.model.domain.secdns.DomainDsData;
|
||||
import google.registry.model.domain.secdns.SecDnsUpdateExtension;
|
||||
import google.registry.model.domain.secdns.SecDnsUpdateExtension.Add;
|
||||
import google.registry.model.domain.secdns.SecDnsUpdateExtension.Remove;
|
||||
import google.registry.model.domain.superuser.DomainUpdateSuperuserExtension;
|
||||
import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
@@ -245,12 +247,19 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
private Domain performUpdate(Update command, Domain domain, DateTime now) throws EppException {
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
checkSameValuesNotAddedAndRemoved(add.getNameservers(), remove.getNameservers());
|
||||
checkSameValuesNotAddedAndRemoved(add.getContacts(), remove.getContacts());
|
||||
checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues());
|
||||
Change change = command.getInnerChange();
|
||||
Optional<SecDnsUpdateExtension> secDnsUpdate =
|
||||
eppInput.getSingleExtension(SecDnsUpdateExtension.class);
|
||||
verifyAddsAndRemoves(domain.getNameservers(), add.getNameservers(), remove.getNameservers());
|
||||
verifyAddsAndRemoves(domain.getContacts(), add.getContacts(), remove.getContacts());
|
||||
verifyAddsAndRemoves(domain.getStatusValues(), add.getStatusValues(), remove.getStatusValues());
|
||||
if (secDnsUpdate.isPresent()) {
|
||||
SecDnsUpdateExtension ext = secDnsUpdate.get();
|
||||
verifyAddsAndRemoves(
|
||||
domain.getDsData(),
|
||||
ext.getAdd().map(Add::getDsData).orElse(ImmutableSet.of()),
|
||||
ext.getRemove().map(Remove::getDsData).orElse(ImmutableSet.of()));
|
||||
}
|
||||
Change change = command.getInnerChange();
|
||||
|
||||
// We have to verify no duplicate contacts _before_ constructing the domain because it is
|
||||
// illegal to construct a domain with duplicate contacts.
|
||||
|
||||
@@ -116,6 +116,7 @@ public final class HostCreateFlow implements MutatingFlow {
|
||||
? new SubordinateHostMustHaveIpException()
|
||||
: new UnexpectedExternalHostIpException();
|
||||
}
|
||||
HostFlowUtils.validateInetAddresses(command.getInetAddresses());
|
||||
Host newHost =
|
||||
new Host.Builder()
|
||||
.setCreationRegistrarId(registrarId)
|
||||
|
||||
@@ -22,6 +22,7 @@ import static java.util.stream.Collectors.joining;
|
||||
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.AuthorizationErrorException;
|
||||
@@ -34,6 +35,7 @@ import google.registry.model.ForeignKeyUtils;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.util.Idn;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -108,6 +110,24 @@ public class HostFlowUtils {
|
||||
return superordinateDomain;
|
||||
}
|
||||
|
||||
/** Makes sure that no provided IP addresses are local / loopback addresses. */
|
||||
public static void validateInetAddresses(ImmutableSet<InetAddress> inetAddresses)
|
||||
throws EppException {
|
||||
if (inetAddresses == null) {
|
||||
return;
|
||||
}
|
||||
if (inetAddresses.stream().anyMatch(InetAddress::isLoopbackAddress)) {
|
||||
throw new LoopbackIpNotValidForHostException();
|
||||
}
|
||||
}
|
||||
|
||||
/** Loopback IPs are not valid for hosts. */
|
||||
static class LoopbackIpNotValidForHostException extends ParameterValuePolicyErrorException {
|
||||
public LoopbackIpNotValidForHostException() {
|
||||
super("Loopback IPs are not valid for hosts");
|
||||
}
|
||||
}
|
||||
|
||||
/** Superordinate domain for this hostname does not exist. */
|
||||
static class SuperordinateDomainDoesNotExistException extends ObjectDoesNotExistException {
|
||||
public SuperordinateDomainDoesNotExistException(String domainName) {
|
||||
|
||||
@@ -20,8 +20,8 @@ import static google.registry.dns.DnsUtils.requestHostDnsRefresh;
|
||||
import static google.registry.dns.RefreshDnsOnHostRenameAction.PARAM_HOST_KEY;
|
||||
import static google.registry.dns.RefreshDnsOnHostRenameAction.QUEUE_HOST_RENAME;
|
||||
import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn;
|
||||
import static google.registry.flows.ResourceFlowUtils.checkSameValuesNotAddedAndRemoved;
|
||||
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyAddsAndRemoves;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyAllStatusesAreClientSettable;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
|
||||
@@ -159,8 +159,11 @@ public final class HostUpdateFlow implements MutatingFlow {
|
||||
}
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues());
|
||||
checkSameValuesNotAddedAndRemoved(add.getInetAddresses(), remove.getInetAddresses());
|
||||
verifyAddsAndRemoves(
|
||||
existingHost.getStatusValues(), add.getStatusValues(), remove.getStatusValues());
|
||||
verifyAddsAndRemoves(
|
||||
existingHost.getInetAddresses(), add.getInetAddresses(), remove.getInetAddresses());
|
||||
HostFlowUtils.validateInetAddresses(add.getInetAddresses());
|
||||
VKey<Domain> newSuperordinateDomainKey =
|
||||
newSuperordinateDomain.map(Domain::createVKey).orElse(null);
|
||||
// If the superordinateDomain field is changing, set the lastSuperordinateChange to now.
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package google.registry.model.domain.fee;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.model.eppinput.EppInput.CommandExtension;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
@@ -42,4 +44,11 @@ public interface FeeCheckCommandExtension<
|
||||
ImmutableList<C> getItems();
|
||||
|
||||
R createResponse(ImmutableList<? extends FeeCheckResponseExtensionItem> items);
|
||||
|
||||
default R createResponse(
|
||||
ImmutableList<? extends FeeCheckResponseExtensionItem> items,
|
||||
ImmutableSet<CurrencyUnit> currenciesSeen)
|
||||
throws EppException {
|
||||
return createResponse(items);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import com.google.common.base.Ascii;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.fee.FeeCheckCommandExtensionItem;
|
||||
import jakarta.xml.bind.annotation.XmlAttribute;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
@@ -32,12 +31,13 @@ import org.joda.time.DateTime;
|
||||
* <pre>{@code
|
||||
* <fee:command name="renew" phase="sunrise" subphase="hello">
|
||||
* <fee:period unit="y">1</fee:period>
|
||||
* <fee:class>premium</fee:class>
|
||||
* <fee:date>2017-05-17T13:22:21.0Z</fee:date>
|
||||
* </fee:command>
|
||||
* }</pre>
|
||||
*
|
||||
* <p>The `feeClass` and `feeDate` attributes that are present in version 0.12 are removed from this
|
||||
* version.
|
||||
*/
|
||||
@XmlType(propOrder = {"period", "feeClass", "feeDate"})
|
||||
@XmlType(propOrder = {"period"})
|
||||
public class FeeCheckCommandExtensionItemStdV1 extends FeeCheckCommandExtensionItem {
|
||||
|
||||
/** The default validity period (if not specified) is 1 year for all operations. */
|
||||
@@ -50,12 +50,6 @@ public class FeeCheckCommandExtensionItemStdV1 extends FeeCheckCommandExtensionI
|
||||
|
||||
@XmlAttribute String subphase;
|
||||
|
||||
@XmlElement(name = "class")
|
||||
String feeClass;
|
||||
|
||||
@XmlElement(name = "date")
|
||||
DateTime feeDate;
|
||||
|
||||
/** Version 1.0 does not support domain name or currency in fee extension items. */
|
||||
@Override
|
||||
public boolean isDomainNameSupported() {
|
||||
@@ -107,6 +101,6 @@ public class FeeCheckCommandExtensionItemStdV1 extends FeeCheckCommandExtensionI
|
||||
|
||||
@Override
|
||||
public Optional<DateTime> getEffectiveDate() {
|
||||
return Optional.ofNullable(feeDate);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ package google.registry.model.domain.feestdv1;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.ParameterValuePolicyErrorException;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.domain.fee.FeeCheckCommandExtension;
|
||||
import google.registry.model.domain.fee.FeeCheckResponseExtensionItem;
|
||||
@@ -51,13 +54,33 @@ public class FeeCheckCommandExtensionStdV1 extends ImmutableObject
|
||||
@Override
|
||||
public FeeCheckResponseExtensionStdV1 createResponse(
|
||||
ImmutableList<? extends FeeCheckResponseExtensionItem> items) {
|
||||
throw new UnsupportedOperationException("FeeCheckCommandExtensionStdV1 requires a currency");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeeCheckResponseExtensionStdV1 createResponse(
|
||||
ImmutableList<? extends FeeCheckResponseExtensionItem> items,
|
||||
ImmutableSet<CurrencyUnit> currenciesSeen)
|
||||
throws EppException {
|
||||
ImmutableList.Builder<FeeCheckResponseExtensionItemStdV1> builder =
|
||||
new ImmutableList.Builder<>();
|
||||
for (FeeCheckResponseExtensionItem item : items) {
|
||||
if (item instanceof FeeCheckResponseExtensionItemStdV1) {
|
||||
builder.add((FeeCheckResponseExtensionItemStdV1) item);
|
||||
if (item instanceof FeeCheckResponseExtensionItemStdV1 stdv1Item) {
|
||||
builder.add(stdv1Item);
|
||||
}
|
||||
}
|
||||
return FeeCheckResponseExtensionStdV1.create(currency, builder.build());
|
||||
if (currenciesSeen.size() > 1) {
|
||||
throw new MultipleCurrenciesCannotBeCheckedException();
|
||||
}
|
||||
return FeeCheckResponseExtensionStdV1.create(currenciesSeen.iterator().next(), builder.build());
|
||||
}
|
||||
|
||||
/** Domains across multiple currencies cannot be checked simultaneously. */
|
||||
public static class MultipleCurrenciesCannotBeCheckedException
|
||||
extends ParameterValuePolicyErrorException {
|
||||
public MultipleCurrenciesCannotBeCheckedException() {
|
||||
// The fee extension 1.0 only supports one currency shared across all results
|
||||
super("Domains across multiple currencies cannot be checked simultaneously");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,11 @@ import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import jakarta.xml.bind.annotation.XmlAttribute;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import java.util.List;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** The version 1.0 response command entity for a domain check on a single resource. */
|
||||
@XmlType(propOrder = {"period", "fee", "feeClass", "effectiveDate", "notAfterDate"})
|
||||
@XmlType(propOrder = {"period", "fee"})
|
||||
public class FeeCheckResponseExtensionItemCommandStdV1 extends ImmutableObject {
|
||||
|
||||
/** The command that was checked. */
|
||||
@@ -53,26 +51,6 @@ public class FeeCheckResponseExtensionItemCommandStdV1 extends ImmutableObject {
|
||||
*/
|
||||
List<Fee> fee;
|
||||
|
||||
/**
|
||||
* The type of the fee.
|
||||
*
|
||||
* <p>We will use "premium" for fees on premium names, and omit the field otherwise.
|
||||
*/
|
||||
@XmlElement(name = "class")
|
||||
String feeClass;
|
||||
|
||||
/** The effective date that the check is to be performed on (if specified in the query). */
|
||||
@XmlElement(name = "date")
|
||||
DateTime effectiveDate;
|
||||
|
||||
/** The date after which the quoted fee is no longer valid (if applicable). */
|
||||
@XmlElement(name = "notAfter")
|
||||
DateTime notAfterDate;
|
||||
|
||||
public String getFeeClass() {
|
||||
return feeClass;
|
||||
}
|
||||
|
||||
/** Builder for {@link FeeCheckResponseExtensionItemCommandStdV1}. */
|
||||
public static class Builder extends Buildable.Builder<FeeCheckResponseExtensionItemCommandStdV1> {
|
||||
|
||||
@@ -96,24 +74,9 @@ public class FeeCheckResponseExtensionItemCommandStdV1 extends ImmutableObject {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEffectiveDate(DateTime effectiveDate) {
|
||||
getInstance().effectiveDate = effectiveDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setNotAfterDate(DateTime notAfterDate) {
|
||||
getInstance().notAfterDate = notAfterDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFee(List<Fee> fees) {
|
||||
getInstance().fee = forceEmptyToNull(ImmutableList.copyOf(fees));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setClass(String feeClass) {
|
||||
getInstance().feeClass = feeClass;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,20 +17,18 @@ package google.registry.model.domain.feestdv1;
|
||||
import static google.registry.util.CollectionUtils.forceEmptyToNull;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.domain.DomainObjectSpec;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.fee.FeeCheckResponseExtensionItem;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** The version 1.0 response for a domain check on a single resource. */
|
||||
@XmlType(propOrder = {"object", "command"})
|
||||
@XmlType(propOrder = {"objID", "feeClass", "command"})
|
||||
public class FeeCheckResponseExtensionItemStdV1 extends FeeCheckResponseExtensionItem {
|
||||
|
||||
/** The domain that was checked. */
|
||||
DomainObjectSpec object;
|
||||
String objID;
|
||||
|
||||
/** The command that was checked. */
|
||||
FeeCheckResponseExtensionItemCommandStdV1 command;
|
||||
@@ -53,15 +51,6 @@ public class FeeCheckResponseExtensionItemStdV1 extends FeeCheckResponseExtensio
|
||||
return super.getFees();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is not annotated for JAXB because this version of the extension doesn't support
|
||||
* "feeClass" and because the data comes off of the command object rather than a field.
|
||||
*/
|
||||
@Override
|
||||
public String getFeeClass() {
|
||||
return command.getFeeClass();
|
||||
}
|
||||
|
||||
/** Builder for {@link FeeCheckResponseExtensionItemStdV1}. */
|
||||
public static class Builder
|
||||
extends FeeCheckResponseExtensionItem.Builder<FeeCheckResponseExtensionItemStdV1> {
|
||||
@@ -91,13 +80,13 @@ public class FeeCheckResponseExtensionItemStdV1 extends FeeCheckResponseExtensio
|
||||
|
||||
@Override
|
||||
public Builder setClass(String feeClass) {
|
||||
commandBuilder.setClass(feeClass);
|
||||
super.setClass(feeClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setDomainNameIfSupported(String name) {
|
||||
getInstance().object = new DomainObjectSpec(name);
|
||||
getInstance().objID = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -106,17 +95,5 @@ public class FeeCheckResponseExtensionItemStdV1 extends FeeCheckResponseExtensio
|
||||
getInstance().command = commandBuilder.build();
|
||||
return super.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setEffectiveDateIfSupported(DateTime effectiveDate) {
|
||||
commandBuilder.setEffectiveDate(effectiveDate);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder setNotAfterDateIfSupported(DateTime notAfterDate) {
|
||||
commandBuilder.setNotAfterDate(notAfterDate);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
@Access(AccessType.FIELD)
|
||||
public abstract class DomainDsDataBase extends ImmutableObject implements UnsafeSerializable {
|
||||
|
||||
@XmlTransient @Transient String domainRepoId;
|
||||
@XmlTransient @Transient @Insignificant String domainRepoId;
|
||||
|
||||
/** The identifier for this particular key in the domain. */
|
||||
@Transient int keyTag;
|
||||
|
||||
@@ -24,6 +24,7 @@ import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlRootElement;
|
||||
import jakarta.xml.bind.annotation.XmlTransient;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/** The EPP secDNS extension that may be present on domain update commands. */
|
||||
@@ -55,16 +56,16 @@ public class SecDnsUpdateExtension extends ImmutableObject implements CommandExt
|
||||
return urgent;
|
||||
}
|
||||
|
||||
public Remove getRemove() {
|
||||
return remove;
|
||||
public Optional<Remove> getRemove() {
|
||||
return Optional.ofNullable(remove);
|
||||
}
|
||||
|
||||
public Add getAdd() {
|
||||
return add;
|
||||
public Optional<Add> getAdd() {
|
||||
return Optional.ofNullable(add);
|
||||
}
|
||||
|
||||
public Change getChange() {
|
||||
return change;
|
||||
public Optional<Change> getChange() {
|
||||
return Optional.ofNullable(change);
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
|
||||
@@ -14,13 +14,16 @@
|
||||
|
||||
package google.registry.model.eppcommon;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import google.registry.xml.ValidationMode;
|
||||
import google.registry.xml.XmlException;
|
||||
import google.registry.xml.XmlTransformer;
|
||||
@@ -31,7 +34,7 @@ import java.io.ByteArrayOutputStream;
|
||||
public class EppXmlTransformer {
|
||||
|
||||
// Hardcoded XML schemas, ordered with respect to dependency.
|
||||
private static final ImmutableList<String> SCHEMAS =
|
||||
private static final ImmutableList<String> ALL_SCHEMAS =
|
||||
ImmutableList.of(
|
||||
"eppcom.xsd",
|
||||
"epp.xsd",
|
||||
@@ -54,11 +57,24 @@ public class EppXmlTransformer {
|
||||
"allocationToken-1.0.xsd",
|
||||
"bulkToken.xsd");
|
||||
|
||||
// XML schemas that should not be used in production (yet)
|
||||
private static final ImmutableSet<String> NON_PROD_SCHEMAS = ImmutableSet.of("fee-std-v1.xsd");
|
||||
|
||||
private static final XmlTransformer INPUT_TRANSFORMER =
|
||||
new XmlTransformer(SCHEMAS, EppInput.class);
|
||||
new XmlTransformer(getSchemas(), EppInput.class);
|
||||
|
||||
private static final XmlTransformer OUTPUT_TRANSFORMER =
|
||||
new XmlTransformer(SCHEMAS, EppOutput.class);
|
||||
new XmlTransformer(getSchemas(), EppOutput.class);
|
||||
|
||||
@VisibleForTesting
|
||||
public static ImmutableList<String> getSchemas() {
|
||||
if (RegistryEnvironment.get().equals(RegistryEnvironment.PRODUCTION)) {
|
||||
return ALL_SCHEMAS.stream()
|
||||
.filter(s -> !NON_PROD_SCHEMAS.contains(s))
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
return ALL_SCHEMAS;
|
||||
}
|
||||
|
||||
public static void validateOutput(String xml) throws XmlException {
|
||||
OUTPUT_TRANSFORMER.validate(xml);
|
||||
|
||||
@@ -33,6 +33,7 @@ import google.registry.model.domain.rgp.RgpUpdateExtension;
|
||||
import google.registry.model.domain.secdns.SecDnsCreateExtension;
|
||||
import google.registry.model.eppinput.EppInput.CommandExtension;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import jakarta.xml.bind.annotation.XmlSchema;
|
||||
import java.util.EnumSet;
|
||||
|
||||
@@ -43,35 +44,52 @@ public class ProtocolDefinition {
|
||||
public static final String LANGUAGE = "en";
|
||||
|
||||
public static final ImmutableSet<String> SUPPORTED_OBJECT_SERVICES =
|
||||
ImmutableSet.of(
|
||||
"urn:ietf:params:xml:ns:host-1.0",
|
||||
"urn:ietf:params:xml:ns:domain-1.0",
|
||||
"urn:ietf:params:xml:ns:contact-1.0");
|
||||
ImmutableSet.of("urn:ietf:params:xml:ns:host-1.0", "urn:ietf:params:xml:ns:domain-1.0");
|
||||
|
||||
/** Enums repesenting valid service extensions that are recognized by the server. */
|
||||
/** Enum representing which environments should have which service extensions enabled. */
|
||||
private enum ServiceExtensionVisibility {
|
||||
ALL,
|
||||
ONLY_IN_PRODUCTION,
|
||||
ONLY_IN_NON_PRODUCTION,
|
||||
NONE
|
||||
}
|
||||
|
||||
/** Enum representing valid service extensions that are recognized by the server. */
|
||||
public enum ServiceExtension {
|
||||
LAUNCH_EXTENSION_1_0(LaunchCreateExtension.class, null, true),
|
||||
REDEMPTION_GRACE_PERIOD_1_0(RgpUpdateExtension.class, null, true),
|
||||
SECURE_DNS_1_1(SecDnsCreateExtension.class, null, true),
|
||||
FEE_0_6(FeeCheckCommandExtensionV06.class, FeeCheckResponseExtensionV06.class, true),
|
||||
FEE_0_11(FeeCheckCommandExtensionV11.class, FeeCheckResponseExtensionV11.class, true),
|
||||
FEE_0_12(FeeCheckCommandExtensionV12.class, FeeCheckResponseExtensionV12.class, true),
|
||||
FEE_1_00(FeeCheckCommandExtensionStdV1.class, FeeCheckResponseExtensionStdV1.class, false),
|
||||
METADATA_1_0(MetadataExtension.class, null, false);
|
||||
LAUNCH_EXTENSION_1_0(LaunchCreateExtension.class, null, ServiceExtensionVisibility.ALL),
|
||||
REDEMPTION_GRACE_PERIOD_1_0(RgpUpdateExtension.class, null, ServiceExtensionVisibility.ALL),
|
||||
SECURE_DNS_1_1(SecDnsCreateExtension.class, null, ServiceExtensionVisibility.ALL),
|
||||
FEE_0_6(
|
||||
FeeCheckCommandExtensionV06.class,
|
||||
FeeCheckResponseExtensionV06.class,
|
||||
ServiceExtensionVisibility.ALL),
|
||||
FEE_0_11(
|
||||
FeeCheckCommandExtensionV11.class,
|
||||
FeeCheckResponseExtensionV11.class,
|
||||
ServiceExtensionVisibility.ALL),
|
||||
FEE_0_12(
|
||||
FeeCheckCommandExtensionV12.class,
|
||||
FeeCheckResponseExtensionV12.class,
|
||||
ServiceExtensionVisibility.ALL),
|
||||
FEE_1_00(
|
||||
FeeCheckCommandExtensionStdV1.class,
|
||||
FeeCheckResponseExtensionStdV1.class,
|
||||
ServiceExtensionVisibility.ONLY_IN_NON_PRODUCTION),
|
||||
METADATA_1_0(MetadataExtension.class, null, ServiceExtensionVisibility.NONE);
|
||||
|
||||
private final Class<? extends CommandExtension> commandExtensionClass;
|
||||
private final Class<? extends ResponseExtension> responseExtensionClass;
|
||||
private final String uri;
|
||||
private final boolean visible;
|
||||
private final ServiceExtensionVisibility visibility;
|
||||
|
||||
ServiceExtension(
|
||||
Class<? extends CommandExtension> commandExtensionClass,
|
||||
Class<? extends ResponseExtension> responseExtensionClass,
|
||||
boolean visible) {
|
||||
ServiceExtensionVisibility visibility) {
|
||||
this.commandExtensionClass = commandExtensionClass;
|
||||
this.responseExtensionClass = responseExtensionClass;
|
||||
this.uri = getCommandExtensionUri(commandExtensionClass);
|
||||
this.visible = visible;
|
||||
this.visibility = visibility;
|
||||
}
|
||||
|
||||
public Class<? extends CommandExtension> getCommandExtensionClass() {
|
||||
@@ -86,14 +104,20 @@ public class ProtocolDefinition {
|
||||
return uri;
|
||||
}
|
||||
|
||||
public boolean getVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
/** Returns the namespace URI of the command extension class. */
|
||||
public static String getCommandExtensionUri(Class<? extends CommandExtension> clazz) {
|
||||
return clazz.getPackage().getAnnotation(XmlSchema.class).namespace();
|
||||
}
|
||||
|
||||
private boolean isVisible() {
|
||||
return switch (visibility) {
|
||||
case ALL -> true;
|
||||
case ONLY_IN_PRODUCTION -> RegistryEnvironment.get().equals(RegistryEnvironment.PRODUCTION);
|
||||
case ONLY_IN_NON_PRODUCTION ->
|
||||
!RegistryEnvironment.get().equals(RegistryEnvironment.PRODUCTION);
|
||||
case NONE -> false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,9 +135,8 @@ public class ProtocolDefinition {
|
||||
|
||||
/** A set of all the visible extension URIs. */
|
||||
private static final ImmutableSet<String> visibleServiceExtensionUris =
|
||||
EnumSet.allOf(ServiceExtension.class)
|
||||
.stream()
|
||||
.filter(ServiceExtension::getVisible)
|
||||
EnumSet.allOf(ServiceExtension.class).stream()
|
||||
.filter(ServiceExtension::isVisible)
|
||||
.map(ServiceExtension::getUri)
|
||||
.collect(toImmutableSet());
|
||||
|
||||
|
||||
@@ -62,6 +62,9 @@ import google.registry.module.ReadinessProbeAction.ReadinessProbeActionFrontend;
|
||||
import google.registry.module.ReadinessProbeAction.ReadinessProbeActionPubApi;
|
||||
import google.registry.module.ReadinessProbeAction.ReadinessProbeConsoleAction;
|
||||
import google.registry.monitoring.whitebox.WhiteboxModule;
|
||||
import google.registry.mosapi.GetServiceStateAction;
|
||||
import google.registry.mosapi.TriggerServiceStateAction;
|
||||
import google.registry.mosapi.module.MosApiRequestModule;
|
||||
import google.registry.rdap.RdapAutnumAction;
|
||||
import google.registry.rdap.RdapDomainAction;
|
||||
import google.registry.rdap.RdapDomainSearchAction;
|
||||
@@ -151,6 +154,7 @@ import google.registry.ui.server.console.settings.SecurityAction;
|
||||
EppToolModule.class,
|
||||
IcannReportingModule.class,
|
||||
LoadTestModule.class,
|
||||
MosApiRequestModule.class,
|
||||
RdapModule.class,
|
||||
RdeModule.class,
|
||||
ReportingModule.class,
|
||||
@@ -232,6 +236,8 @@ interface RequestComponent {
|
||||
|
||||
GenerateZoneFilesAction generateZoneFilesAction();
|
||||
|
||||
GetServiceStateAction getServiceStateAction();
|
||||
|
||||
IcannReportingStagingAction icannReportingStagingAction();
|
||||
|
||||
IcannReportingUploadAction icannReportingUploadAction();
|
||||
@@ -334,6 +340,8 @@ interface RequestComponent {
|
||||
|
||||
TmchSmdrlAction tmchSmdrlAction();
|
||||
|
||||
TriggerServiceStateAction triggerServiceStateAction();
|
||||
|
||||
UpdateRegistrarRdapBaseUrlsAction updateRegistrarRdapBaseUrlsAction();
|
||||
|
||||
UpdateUserGroupAction updateUserGroupAction();
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2025 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.mosapi;
|
||||
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.HttpException.ServiceUnavailableException;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.Optional;
|
||||
|
||||
/** An action that returns the current MoSAPI service state for a given TLD or all TLDs. */
|
||||
@Action(
|
||||
service = Action.Service.BACKEND,
|
||||
path = GetServiceStateAction.PATH,
|
||||
method = Action.Method.GET,
|
||||
auth = Auth.AUTH_ADMIN)
|
||||
public class GetServiceStateAction implements Runnable {
|
||||
|
||||
public static final String PATH = "/_dr/mosapi/getServiceState";
|
||||
public static final String TLD_PARAM = "tld";
|
||||
|
||||
private final MosApiStateService stateService;
|
||||
private final Response response;
|
||||
private final Gson gson;
|
||||
private final Optional<String> tld;
|
||||
|
||||
@Inject
|
||||
public GetServiceStateAction(
|
||||
MosApiStateService stateService,
|
||||
Response response,
|
||||
Gson gson,
|
||||
@Parameter(TLD_PARAM) Optional<String> tld) {
|
||||
this.stateService = stateService;
|
||||
this.response = response;
|
||||
this.gson = gson;
|
||||
this.tld = tld;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
response.setContentType(MediaType.JSON_UTF_8);
|
||||
try {
|
||||
if (tld.isPresent()) {
|
||||
response.setPayload(gson.toJson(stateService.getServiceStateSummary(tld.get())));
|
||||
} else {
|
||||
response.setPayload(gson.toJson(stateService.getAllServiceStateSummaries()));
|
||||
}
|
||||
} catch (MosApiException e) {
|
||||
throw new ServiceUnavailableException("Error fetching MoSAPI service state.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,9 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.mosapi.model;
|
||||
package google.registry.mosapi;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Represents the generic JSON error response from the MoSAPI service for a 400 Bad Request.
|
||||
@@ -20,4 +22,5 @@ package google.registry.mosapi.model;
|
||||
* @see <a href="https://www.icann.org/mosapi-specification.pdf">ICANN MoSAPI Specification, Section
|
||||
* 8</a>
|
||||
*/
|
||||
public record MosApiErrorResponse(String resultCode, String message, String description) {}
|
||||
public record MosApiErrorResponse(
|
||||
@Expose String resultCode, @Expose String message, @Expose String description) {}
|
||||
@@ -17,7 +17,6 @@ package google.registry.mosapi;
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import google.registry.mosapi.model.MosApiErrorResponse;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -42,6 +41,11 @@ public class MosApiException extends IOException {
|
||||
this.errorResponse = null;
|
||||
}
|
||||
|
||||
public MosApiException(String message) {
|
||||
super(message);
|
||||
this.errorResponse = null;
|
||||
}
|
||||
|
||||
public Optional<MosApiErrorResponse> getErrorResponse() {
|
||||
return Optional.ofNullable(errorResponse);
|
||||
}
|
||||
|
||||
34
core/src/main/java/google/registry/mosapi/MosApiMetrics.java
Normal file
34
core/src/main/java/google/registry/mosapi/MosApiMetrics.java
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2026 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.mosapi;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.mosapi.MosApiModels.TldServiceState;
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.List;
|
||||
|
||||
/** Metrics Exporter for MoSAPI. */
|
||||
public class MosApiMetrics {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
@Inject
|
||||
public MosApiMetrics() {}
|
||||
|
||||
public void recordStates(List<TldServiceState> states) {
|
||||
// b/467541269: Logic to push status to Cloud Monitoring goes here
|
||||
logger.atInfo().log("MoSAPI record metrics logic will be implemented from here");
|
||||
}
|
||||
}
|
||||
122
core/src/main/java/google/registry/mosapi/MosApiModels.java
Normal file
122
core/src/main/java/google/registry/mosapi/MosApiModels.java
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright 2025 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.mosapi;
|
||||
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Data models for ICANN MoSAPI. */
|
||||
public final class MosApiModels {
|
||||
|
||||
private MosApiModels() {}
|
||||
|
||||
/**
|
||||
* A wrapper response containing the state summaries of all monitored services.
|
||||
*
|
||||
* <p>This corresponds to the collection of service statuses returned when monitoring the state of
|
||||
* a TLD
|
||||
*
|
||||
* @see <a href="https://www.icann.org/mosapi-specification.pdf">ICANN MoSAPI Specification,
|
||||
* Section 5.1</a>
|
||||
*/
|
||||
public record AllServicesStateResponse(
|
||||
// A list of state summaries for each monitored service (e.g. DNS, RDDS, etc.)
|
||||
@Expose List<ServiceStateSummary> serviceStates) {
|
||||
|
||||
public AllServicesStateResponse {
|
||||
serviceStates = nullToEmptyImmutableCopy(serviceStates);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A summary of a service incident.
|
||||
*
|
||||
* @see <a href="https://www.icann.org/mosapi-specification.pdf">ICANN MoSAPI Specification,
|
||||
* Section 5.1</a>
|
||||
*/
|
||||
public record IncidentSummary(
|
||||
@Expose String incidentID,
|
||||
@Expose long startTime,
|
||||
@Expose boolean falsePositive,
|
||||
@Expose String state,
|
||||
@Expose @Nullable Long endTime) {}
|
||||
|
||||
/**
|
||||
* A curated summary of the service state for a TLD.
|
||||
*
|
||||
* <p>This class aggregates the high-level status of a TLD and details of any active incidents
|
||||
* affecting specific services (like DNS or RDDS), based on the data structures defined in the
|
||||
* MoSAPI specification.
|
||||
*
|
||||
* @see <a href="https://www.icann.org/mosapi-specification.pdf">ICANN MoSAPI Specification,
|
||||
* Section 5.1</a>
|
||||
*/
|
||||
public record ServiceStateSummary(
|
||||
@Expose String tld,
|
||||
@Expose String overallStatus,
|
||||
@Expose List<ServiceStatus> activeIncidents) {
|
||||
|
||||
public ServiceStateSummary {
|
||||
activeIncidents = nullToEmptyImmutableCopy(activeIncidents);
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents the status of a single monitored service. */
|
||||
public record ServiceStatus(
|
||||
/**
|
||||
* A JSON string that contains the status of the Service as seen from the monitoring system.
|
||||
* Possible values include "Up", "Down", "Disabled", "UP-inconclusive-no-data", etc.
|
||||
*/
|
||||
@Expose String status,
|
||||
|
||||
// A JSON number that contains the current percentage of the Emergency Threshold
|
||||
// of the Service. A value of "0" specifies that there are no Incidents
|
||||
// affecting the threshold.
|
||||
@Expose double emergencyThreshold,
|
||||
@Expose List<IncidentSummary> incidents) {
|
||||
|
||||
public ServiceStatus {
|
||||
incidents = nullToEmptyImmutableCopy(incidents);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the overall health of all monitored services for a TLD.
|
||||
*
|
||||
* @see <a href="https://www.icann.org/mosapi-specification.pdf">ICANN MoSAPI Specification,
|
||||
* Section 5.1</a>
|
||||
*/
|
||||
public record TldServiceState(
|
||||
@Expose String tld,
|
||||
long lastUpdateApiDatabase,
|
||||
|
||||
// A JSON string that contains the status of the TLD as seen from the monitoring system
|
||||
@Expose String status,
|
||||
|
||||
// A JSON object containing detailed information for each potential monitored service (i.e.,
|
||||
// DNS,
|
||||
// RDDS, EPP, DNSSEC, RDAP).
|
||||
@Expose @SerializedName("testedServices") Map<String, ServiceStatus> serviceStatuses) {
|
||||
|
||||
public TldServiceState {
|
||||
serviceStatuses = nullToEmptyImmutableCopy(serviceStatuses);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
// Copyright 2025 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.mosapi;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.mosapi.MosApiModels.AllServicesStateResponse;
|
||||
import google.registry.mosapi.MosApiModels.ServiceStateSummary;
|
||||
import google.registry.mosapi.MosApiModels.ServiceStatus;
|
||||
import google.registry.mosapi.MosApiModels.TldServiceState;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** A service that provides business logic for interacting with MoSAPI Service State. */
|
||||
public class MosApiStateService {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
private final ServiceMonitoringClient serviceMonitoringClient;
|
||||
private final ExecutorService tldExecutor;
|
||||
|
||||
private final ImmutableSet<String> tlds;
|
||||
|
||||
private final MosApiMetrics mosApiMetrics;
|
||||
|
||||
private static final String DOWN_STATUS = "Down";
|
||||
private static final String FETCH_ERROR_STATUS = "ERROR";
|
||||
|
||||
@Inject
|
||||
public MosApiStateService(
|
||||
ServiceMonitoringClient serviceMonitoringClient,
|
||||
MosApiMetrics mosApiMetrics,
|
||||
@Config("mosapiTlds") ImmutableSet<String> tlds,
|
||||
@Named("mosapiTldExecutor") ExecutorService tldExecutor) {
|
||||
this.serviceMonitoringClient = serviceMonitoringClient;
|
||||
this.mosApiMetrics = mosApiMetrics;
|
||||
this.tlds = tlds;
|
||||
this.tldExecutor = tldExecutor;
|
||||
}
|
||||
|
||||
/** Fetches and transforms the service state for a given TLD into a summary. */
|
||||
public ServiceStateSummary getServiceStateSummary(String tld) throws MosApiException {
|
||||
TldServiceState rawState = serviceMonitoringClient.getTldServiceState(tld);
|
||||
return transformToSummary(rawState);
|
||||
}
|
||||
|
||||
/** Fetches and transforms the service state for all configured TLDs. */
|
||||
public AllServicesStateResponse getAllServiceStateSummaries() {
|
||||
ImmutableList<CompletableFuture<ServiceStateSummary>> futures =
|
||||
tlds.stream()
|
||||
.map(
|
||||
tld ->
|
||||
CompletableFuture.supplyAsync(
|
||||
() -> {
|
||||
try {
|
||||
return getServiceStateSummary(tld);
|
||||
} catch (MosApiException e) {
|
||||
logger.atWarning().withCause(e).log(
|
||||
"Failed to get service state for TLD %s.", tld);
|
||||
// we don't want to throw exception if fetch failed
|
||||
return new ServiceStateSummary(tld, FETCH_ERROR_STATUS, null);
|
||||
}
|
||||
},
|
||||
tldExecutor))
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
|
||||
ImmutableList<ServiceStateSummary> summaries =
|
||||
futures.stream()
|
||||
.map(CompletableFuture::join) // Waits for all tasks to complete
|
||||
.collect(toImmutableList());
|
||||
|
||||
return new AllServicesStateResponse(summaries);
|
||||
}
|
||||
|
||||
private ServiceStateSummary transformToSummary(TldServiceState rawState) {
|
||||
ImmutableList<ServiceStatus> activeIncidents = ImmutableList.of();
|
||||
if (DOWN_STATUS.equalsIgnoreCase(rawState.status())) {
|
||||
activeIncidents =
|
||||
rawState.serviceStatuses().entrySet().stream()
|
||||
.filter(
|
||||
entry -> {
|
||||
ServiceStatus serviceStatus = entry.getValue();
|
||||
return serviceStatus.incidents() != null
|
||||
&& !serviceStatus.incidents().isEmpty();
|
||||
})
|
||||
.map(
|
||||
entry ->
|
||||
new ServiceStatus(
|
||||
// key is the service name
|
||||
entry.getKey(),
|
||||
entry.getValue().emergencyThreshold(),
|
||||
entry.getValue().incidents()))
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
return new ServiceStateSummary(rawState.tld(), rawState.status(), activeIncidents);
|
||||
}
|
||||
|
||||
/** Triggers monitoring exposure for all configured TLDs. */
|
||||
public void triggerMetricsForAllServiceStateSummaries() {
|
||||
ImmutableList<CompletableFuture<TldServiceState>> futures =
|
||||
tlds.stream()
|
||||
.map(
|
||||
tld ->
|
||||
CompletableFuture.supplyAsync(
|
||||
() -> {
|
||||
try {
|
||||
return serviceMonitoringClient.getTldServiceState(tld);
|
||||
} catch (MosApiException e) {
|
||||
// Log the error but don't rethrow as RuntimeException
|
||||
logger.atWarning().withCause(e).log(
|
||||
"Failed to fetch state for TLD: %s", tld);
|
||||
return null; // Return null so the stream keeps moving
|
||||
}
|
||||
},
|
||||
tldExecutor))
|
||||
.collect(toImmutableList());
|
||||
|
||||
List<TldServiceState> allStates =
|
||||
futures.stream()
|
||||
.map(CompletableFuture::join)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!allStates.isEmpty()) {
|
||||
try {
|
||||
mosApiMetrics.recordStates(allStates);
|
||||
} catch (Exception e) {
|
||||
logger.atSevere().withCause(e).log("Failed to submit MoSAPI metrics batch.");
|
||||
}
|
||||
} else {
|
||||
logger.atWarning().log("No successful TLD states fetched; skipping metrics push.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright 2025 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.mosapi;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonParseException;
|
||||
import google.registry.mosapi.MosApiModels.TldServiceState;
|
||||
import jakarta.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
/** Facade for MoSAPI's service monitoring endpoints. */
|
||||
public class ServiceMonitoringClient {
|
||||
|
||||
private static final String MONITORING_STATE_ENDPOINT = "v2/monitoring/state";
|
||||
private final MosApiClient mosApiClient;
|
||||
private final Gson gson;
|
||||
|
||||
@Inject
|
||||
public ServiceMonitoringClient(MosApiClient mosApiClient, Gson gson) {
|
||||
this.mosApiClient = mosApiClient;
|
||||
this.gson = gson;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the current state of all monitored services for a given TLD.
|
||||
*
|
||||
* @see <a href="https://www.icann.org/mosapi-specification.pdf">ICANN MoSAPI Specification,
|
||||
* Section 5.1</a>
|
||||
*/
|
||||
public TldServiceState getTldServiceState(String tld) throws MosApiException {
|
||||
try (Response response =
|
||||
mosApiClient.sendGetRequest(
|
||||
tld, MONITORING_STATE_ENDPOINT, Collections.emptyMap(), Collections.emptyMap())) {
|
||||
|
||||
ResponseBody responseBody = response.body();
|
||||
if (responseBody == null) {
|
||||
throw new MosApiException(
|
||||
String.format(
|
||||
"MoSAPI Service Monitoring API " + "returned an empty body with status: %d",
|
||||
response.code()));
|
||||
}
|
||||
String bodyString = responseBody.string();
|
||||
if (!response.isSuccessful()) {
|
||||
throw parseErrorResponse(response.code(), bodyString);
|
||||
}
|
||||
return gson.fromJson(bodyString, TldServiceState.class);
|
||||
} catch (IOException | JsonParseException e) {
|
||||
Throwables.throwIfInstanceOf(e, MosApiException.class);
|
||||
// Catch Gson's runtime exceptions (parsing errors) and wrap them
|
||||
throw new MosApiException("Failed to parse TLD service state response", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Parses an unsuccessful MoSAPI response into a domain-specific {@link MosApiException}. */
|
||||
private MosApiException parseErrorResponse(int statusCode, String bodyString) {
|
||||
try {
|
||||
MosApiErrorResponse error = gson.fromJson(bodyString, MosApiErrorResponse.class);
|
||||
return MosApiException.create(error);
|
||||
} catch (JsonParseException e) {
|
||||
return new MosApiException(
|
||||
String.format("MoSAPI json parsing error (%d): %s", statusCode, bodyString), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2026 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.mosapi;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.HttpException.InternalServerErrorException;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
/**
|
||||
* An action that triggers Metrics action for the current MoSAPI service state result for all TLDs.
|
||||
*/
|
||||
@Action(
|
||||
service = Action.Service.BACKEND,
|
||||
path = TriggerServiceStateAction.PATH,
|
||||
method = Action.Method.GET,
|
||||
auth = Auth.AUTH_ADMIN)
|
||||
public class TriggerServiceStateAction implements Runnable {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
public static final String PATH = "/_dr/task/triggerMosApiServiceState";
|
||||
private final MosApiStateService stateService;
|
||||
private final Response response;
|
||||
|
||||
@Inject
|
||||
public TriggerServiceStateAction(MosApiStateService stateService, Response response) {
|
||||
this.stateService = stateService;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
response.setContentType(MediaType.PLAIN_TEXT_UTF_8);
|
||||
try {
|
||||
stateService.triggerMetricsForAllServiceStateSummaries();
|
||||
response.setStatus(200);
|
||||
response.setPayload("MoSAPI metrics triggered successfully for all TLDs.");
|
||||
} catch (Exception e) {
|
||||
logger.atSevere().withCause(e).log("Error triggering MoSAPI metrics.");
|
||||
throw new InternalServerErrorException("Failed to process MoSAPI metrics.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,8 @@ import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
@@ -184,4 +186,21 @@ public final class MosApiModule {
|
||||
.sslSocketFactory(sslContext.getSocketFactory(), trustManager)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a fixed thread pool for parallel TLD processing.
|
||||
*
|
||||
* <p>Strictly bound to 4 threads to comply with MoSAPI session limits (4 concurrent sessions per
|
||||
* certificate). This is used by MosApiStateService to fetch data in parallel.
|
||||
*
|
||||
* @see <a href="https://www.icann.org/mosapi-specification.pdf">ICANN MoSAPI Specification,
|
||||
* Section 12.3</a>
|
||||
*/
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("mosapiTldExecutor")
|
||||
static ExecutorService provideMosapiTldExecutor(
|
||||
@Config("mosapiTldThreadCnt") int threadPoolSize) {
|
||||
return Executors.newFixedThreadPool(threadPoolSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright 2025 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.mosapi.module;
|
||||
|
||||
import static google.registry.request.RequestParameters.extractOptionalParameter;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.request.Parameter;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.Optional;
|
||||
|
||||
/** Dagger module for MoSAPI requests. */
|
||||
@Module
|
||||
public final class MosApiRequestModule {
|
||||
@Provides
|
||||
@Parameter("tld")
|
||||
static Optional<String> provideTld(HttpServletRequest req) {
|
||||
return extractOptionalParameter(req, "tld");
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,6 @@ import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.xml.XMLConstants;
|
||||
@@ -82,7 +81,7 @@ public class XmlTransformer {
|
||||
* @param schemaFilenames schema files, used only for validating, and relative to this package.
|
||||
* @param recognizedClasses the classes that can be used to marshal to and from
|
||||
*/
|
||||
public XmlTransformer(List<String> schemaFilenames, Class<?>... recognizedClasses) {
|
||||
public XmlTransformer(ImmutableList<String> schemaFilenames, Class<?>... recognizedClasses) {
|
||||
try {
|
||||
this.jaxbContext = JAXBContext.newInstance(recognizedClasses);
|
||||
this.schema = loadXmlSchemas(schemaFilenames);
|
||||
@@ -251,7 +250,7 @@ public class XmlTransformer {
|
||||
}
|
||||
|
||||
/** Creates a single {@link Schema} from multiple {@code .xsd} files. */
|
||||
public static Schema loadXmlSchemas(List<String> schemaFilenames) {
|
||||
public static Schema loadXmlSchemas(ImmutableList<String> schemaFilenames) {
|
||||
try (Closer closer = Closer.create()) {
|
||||
StreamSource[] sources = new StreamSource[schemaFilenames.size()];
|
||||
for (int i = 0; i < schemaFilenames.size(); ++i) {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<element name="renew" type="fee:transformCommandType" />
|
||||
<element name="renData" type="fee:transformResultType" />
|
||||
<element name="transfer" type="fee:transformCommandType" />
|
||||
<element name="trnData" type="fee:transferResultType" />
|
||||
<element name="trnData" type="fee:transformResultType" />
|
||||
<element name="update" type="fee:transformCommandType" />
|
||||
<element name="updData" type="fee:transformResultType" />
|
||||
<element name="delData" type="fee:transformResultType" />
|
||||
@@ -33,32 +33,24 @@
|
||||
<sequence>
|
||||
<element name="currency" type="fee:currencyType"
|
||||
minOccurs="0" />
|
||||
<element name="command" type="fee:commandCheckType"
|
||||
maxOccurs="unbounded" />
|
||||
<element name="command" type="fee:commandType"
|
||||
minOccurs="1" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
<complexType name="commandCheckType">
|
||||
<sequence>
|
||||
<element name="period"
|
||||
type="domain:periodType"
|
||||
minOccurs="0" />
|
||||
<element name="class"
|
||||
type="token"
|
||||
minOccurs="0" />
|
||||
<element name="date"
|
||||
type="dateTime"
|
||||
minOccurs="0" />
|
||||
</sequence>
|
||||
<attribute name="name" type="fee:commandTypeValue" />
|
||||
<attribute name="phase" type="token" />
|
||||
<attribute name="subphase" type="token" />
|
||||
<complexType name="objectIdentifierType">
|
||||
<simpleContent>
|
||||
<extension base="eppcom:labelType">
|
||||
<attribute name="element"
|
||||
type="NMTOKEN" default="name" />
|
||||
</extension>
|
||||
</simpleContent>
|
||||
</complexType>
|
||||
|
||||
<!-- server <check> result -->
|
||||
<complexType name="chkDataType">
|
||||
<sequence>
|
||||
<element name="currency" type="fee:currencyType" minOccurs="0"/>
|
||||
<element name="currency" type="fee:currencyType" />
|
||||
<element name="cd" type="fee:objectCDType"
|
||||
maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
@@ -66,47 +58,13 @@
|
||||
|
||||
<complexType name="objectCDType">
|
||||
<sequence>
|
||||
<element name="object">
|
||||
<complexType>
|
||||
<sequence>
|
||||
<any namespace="##other" processContents="lax"/>
|
||||
</sequence>
|
||||
</complexType>
|
||||
</element>
|
||||
<element name="command"
|
||||
type="fee:commandCDType"
|
||||
maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
<complexType name="commandCDType">
|
||||
<sequence>
|
||||
<element name="period"
|
||||
type="domain:periodType"
|
||||
minOccurs="0" maxOccurs="1" />
|
||||
<element name="fee"
|
||||
type="fee:feeType"
|
||||
<element name="objID" type="fee:objectIdentifierType" />
|
||||
<element name="class" type="token" minOccurs="0" />
|
||||
<element name="command" type="fee:commandDataType"
|
||||
minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="credit"
|
||||
type="fee:creditType"
|
||||
minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="class"
|
||||
type="token"
|
||||
minOccurs="0" />
|
||||
<element name="reason"
|
||||
type="token"
|
||||
minOccurs="0" />
|
||||
<element name="date"
|
||||
type="dateTime"
|
||||
minOccurs="0" />
|
||||
<element name="notAfter"
|
||||
type="dateTime"
|
||||
minOccurs="0" />
|
||||
<element name="reason" type="fee:reasonType" minOccurs="0" />
|
||||
</sequence>
|
||||
<attribute name="avail" type="boolean" default="1" />
|
||||
<attribute name="name" type="fee:commandTypeValue" />
|
||||
<attribute name="phase" type="token" />
|
||||
<attribute name="subphase" type="token" />
|
||||
</complexType>
|
||||
|
||||
<!-- general transform (create, renew, update, transfer) command-->
|
||||
@@ -121,32 +79,15 @@
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
<!-- general transform (create, renew, update, delete) result -->
|
||||
<!-- general transform (create, renew, update) result -->
|
||||
<complexType name="transformResultType">
|
||||
<sequence>
|
||||
<element name="currency" type="fee:currencyType" />
|
||||
<element name="fee" type="fee:feeType"
|
||||
minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="credit" type="fee:creditType"
|
||||
minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="balance" type="fee:balanceType"
|
||||
<element name="currency" type="fee:currencyType"
|
||||
minOccurs="0" />
|
||||
<element name="creditLimit" type="fee:creditLimitType"
|
||||
minOccurs="0" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
|
||||
<!-- transfer result -->
|
||||
<complexType name="transferResultType">
|
||||
<sequence>
|
||||
<element name="currency" type="fee:currencyType" />
|
||||
|
||||
<!-- only used op="query" responses -->
|
||||
<element name="period" type="domain:periodType"
|
||||
minOccurs="0" />
|
||||
|
||||
<element name="fee" type="fee:feeType"
|
||||
maxOccurs="unbounded" />
|
||||
minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="credit" type="fee:creditType"
|
||||
minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="balance" type="fee:balanceType"
|
||||
@@ -163,10 +104,50 @@
|
||||
</restriction>
|
||||
</simpleType>
|
||||
|
||||
<simpleType name="commandTypeValue">
|
||||
<complexType name="commandType">
|
||||
<sequence>
|
||||
<element name="period" type="domain:periodType"
|
||||
minOccurs="0" maxOccurs="1" />
|
||||
</sequence>
|
||||
<attribute name="name" type="fee:commandEnum" use="required"/>
|
||||
<attribute name="customName" type="token"/>
|
||||
<attribute name="phase" type="token" />
|
||||
<attribute name="subphase" type="token" />
|
||||
</complexType>
|
||||
|
||||
<complexType name="commandDataType">
|
||||
<complexContent>
|
||||
<extension base="fee:commandType">
|
||||
<sequence>
|
||||
<element name="fee" type="fee:feeType"
|
||||
minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="credit" type="fee:creditType"
|
||||
minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="reason" type="fee:reasonType"
|
||||
minOccurs="0" />
|
||||
</sequence>
|
||||
<attribute name="standard" type="boolean" default="0" />
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
|
||||
<complexType name="reasonType">
|
||||
<simpleContent>
|
||||
<extension base="token">
|
||||
<attribute name="lang" type="language" default="en"/>
|
||||
</extension>
|
||||
</simpleContent>
|
||||
</complexType>
|
||||
|
||||
<simpleType name="commandEnum">
|
||||
<restriction base="token">
|
||||
<minLength value="3"/>
|
||||
<maxLength value="16"/>
|
||||
<enumeration value="create"/>
|
||||
<enumeration value="delete"/>
|
||||
<enumeration value="renew"/>
|
||||
<enumeration value="update"/>
|
||||
<enumeration value="transfer"/>
|
||||
<enumeration value="restore"/>
|
||||
<enumeration value="custom"/>
|
||||
</restriction>
|
||||
</simpleType>
|
||||
|
||||
@@ -186,9 +167,10 @@
|
||||
<simpleContent>
|
||||
<extension base="fee:nonNegativeDecimal">
|
||||
<attribute name="description"/>
|
||||
<attribute name="lang" type="language" default="en"/>
|
||||
<attribute name="refundable" type="boolean" />
|
||||
<attribute name="grace-period" type="duration" />
|
||||
<attribute name="applied" default="immediate">
|
||||
<attribute name="applied">
|
||||
<simpleType>
|
||||
<restriction base="token">
|
||||
<enumeration value="immediate" />
|
||||
@@ -204,6 +186,7 @@
|
||||
<simpleContent>
|
||||
<extension base="fee:negativeDecimal">
|
||||
<attribute name="description"/>
|
||||
<attribute name="lang" type="language" default="en"/>
|
||||
</extension>
|
||||
</simpleContent>
|
||||
</complexType>
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
package google.registry.flows;
|
||||
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
import static org.joda.time.format.ISODateTimeFormat.dateTimeNoMillis;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@@ -26,7 +25,7 @@ class EppLoggedOutTest extends EppTestCase {
|
||||
|
||||
@Test
|
||||
void testHello() throws Exception {
|
||||
DateTime now = DateTime.now(UTC);
|
||||
DateTime now = clock.nowUtc();
|
||||
assertThatCommand("hello.xml", null)
|
||||
.atTime(now)
|
||||
.hasResponse("greeting.xml", ImmutableMap.of("DATE", now.toString(dateTimeNoMillis())));
|
||||
|
||||
@@ -36,6 +36,7 @@ import google.registry.flows.EppTestComponent.FakesAndMocksModule;
|
||||
import google.registry.flows.picker.FlowPicker;
|
||||
import google.registry.model.billing.BillingBase;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.eppcommon.EppXmlTransformer;
|
||||
import google.registry.model.eppcommon.ProtocolDefinition;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
@@ -289,6 +290,8 @@ public abstract class FlowTestCase<F extends Flow> {
|
||||
if (output.isResponse()) {
|
||||
assertThat(output.isSuccess()).isTrue();
|
||||
}
|
||||
// Verify that expected xml is syntatically correct.
|
||||
EppXmlTransformer.validateOutput(xml);
|
||||
try {
|
||||
assertXmlEquals(
|
||||
xml, new String(marshal(output, ValidationMode.STRICT), UTF_8), ignoredPathsPlusTrid);
|
||||
|
||||
@@ -77,9 +77,11 @@ import google.registry.model.billing.BillingRecurrence;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import google.registry.model.domain.feestdv1.FeeCheckCommandExtensionStdV1.MultipleCurrenciesCannotBeCheckedException;
|
||||
import google.registry.model.domain.token.AllocationToken;
|
||||
import google.registry.model.domain.token.AllocationToken.TokenStatus;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
|
||||
import google.registry.model.tld.Tld;
|
||||
@@ -788,6 +790,31 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_multipleCurencies_v12() throws Exception {
|
||||
persistResource(
|
||||
createTld("example")
|
||||
.asBuilder()
|
||||
.setCurrency(JPY)
|
||||
.setCreateBillingCostTransitions(
|
||||
ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
|
||||
.setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
|
||||
.setRenewBillingCostTransitions(
|
||||
ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
|
||||
.setRegistryLockOrUnlockBillingCost(Money.ofMajor(JPY, 800))
|
||||
.setServerStatusChangeBillingCost(Money.ofMajor(JPY, 800))
|
||||
.setRestoreBillingCost(Money.ofMajor(JPY, 800))
|
||||
.build());
|
||||
persistResource(
|
||||
Registrar.loadByRegistrarId("TheRegistrar")
|
||||
.get()
|
||||
.asBuilder()
|
||||
.setBillingAccountMap(ImmutableMap.of(USD, "foo", JPY, "bar"))
|
||||
.build());
|
||||
setEppInput("domain_check_fee_multiple_currencies_v12.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_multiple_currencies_response_v12.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_superuserNotAuthorizedForTld() throws Exception {
|
||||
persistActiveDomain("example2.tld");
|
||||
@@ -951,23 +978,34 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_default_token_v11.xml"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideFeeTestParams")
|
||||
void testFeeExtension_latest(String name, FeeFileLoader fileLoader) throws Exception {
|
||||
@Test
|
||||
void testFeeExtension_v12() throws Exception {
|
||||
persistActiveDomain("example1.tld");
|
||||
setEppInputXml(fileLoader.load(this, "domain_check_fee_v12.xml"));
|
||||
runFlowAssertResponse(fileLoader.load(this, "domain_check_fee_response_v12.xml"));
|
||||
setEppInput("domain_check_fee_v12.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_v12.xml"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideFeeTestParams")
|
||||
void testFeeExtension_defaultToken_latest(String name, FeeFileLoader fileLoader)
|
||||
throws Exception {
|
||||
@Test
|
||||
void testFeeExtension_stdv1() throws Exception {
|
||||
persistActiveDomain("example1.tld");
|
||||
setEppInput("domain_check_fee_stdv1.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_stdv1.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_defaultToken_v12() throws Exception {
|
||||
setUpDefaultToken();
|
||||
persistActiveDomain("example1.tld");
|
||||
setEppInputXml(
|
||||
fileLoader.load(this, "domain_check_fee_v12.xml", ImmutableMap.of("CURRENCY", "USD")));
|
||||
runFlowAssertResponse(fileLoader.load(this, "domain_check_fee_response_default_token_v12.xml"));
|
||||
setEppInput("domain_check_fee_v12.xml", ImmutableMap.of("CURRENCY", "USD"));
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_default_token_v12.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_defaultToken_stdv1() throws Exception {
|
||||
setUpDefaultToken();
|
||||
persistActiveDomain("example1.tld");
|
||||
setEppInput("domain_check_fee_stdv1.xml", ImmutableMap.of("CURRENCY", "USD"));
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_response_default_token_stdv1.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1017,18 +1055,20 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
|
||||
// Version 11 cannot have multiple commands.
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideFeeTestParams")
|
||||
void testFeeExtension_multipleCommands_latest(String name, FeeFileLoader loader)
|
||||
throws Exception {
|
||||
setEppInputXml(loader.load(this, "domain_check_fee_multiple_commands_v12.xml"));
|
||||
runFlowAssertResponse(loader.load(this, "domain_check_fee_multiple_commands_response_v12.xml"));
|
||||
@Test
|
||||
void testFeeExtension_multipleCommands_v12() throws Exception {
|
||||
setEppInput("domain_check_fee_multiple_commands_v12.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_multiple_commands_response_v12.xml"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideFeeTestParams")
|
||||
void testFeeExtension_multipleCommands_tokenNotValidForSome_latest(
|
||||
String name, FeeFileLoader loader) throws Exception {
|
||||
@Test
|
||||
void testFeeExtension_multipleCommands_std_v1() throws Exception {
|
||||
setEppInput("domain_check_fee_multiple_commands_stdv1.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_multiple_commands_response_stdv1.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_multipleCommands_tokenNotValidForSome_v12() throws Exception {
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
@@ -1036,19 +1076,39 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE, CommandName.TRANSFER))
|
||||
.setDiscountFraction(0.1)
|
||||
.build());
|
||||
setEppInputXml(loader.load(this, "domain_check_fee_multiple_commands_allocationtoken_v12.xml"));
|
||||
setEppInput("domain_check_fee_multiple_commands_allocationtoken_v12.xml");
|
||||
runFlowAssertResponse(
|
||||
loader.load(this, "domain_check_fee_multiple_commands_allocationtoken_response_v12.xml"));
|
||||
loadFile("domain_check_fee_multiple_commands_allocationtoken_response_v12.xml"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideFeeTestParams")
|
||||
void testFeeExtension_multipleCommands_defaultTokenOnlyOnCreate_latest(
|
||||
String name, FeeFileLoader loader) throws Exception {
|
||||
setUpDefaultToken();
|
||||
setEppInputXml(loader.load(this, "domain_check_fee_multiple_commands_v12.xml"));
|
||||
@Test
|
||||
void testFeeExtension_multipleCommands_tokenNotValidForSome_std_v1() throws Exception {
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(UNLIMITED_USE)
|
||||
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE, CommandName.TRANSFER))
|
||||
.setDiscountFraction(0.1)
|
||||
.build());
|
||||
setEppInput("domain_check_fee_multiple_commands_allocationtoken_stdv1.xml");
|
||||
runFlowAssertResponse(
|
||||
loader.load(this, "domain_check_fee_multiple_commands_default_token_response_v12.xml"));
|
||||
loadFile("domain_check_fee_multiple_commands_allocationtoken_response_stdv1.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_multipleCommands_defaultTokenOnlyOnCreate_v12() throws Exception {
|
||||
setUpDefaultToken();
|
||||
setEppInput("domain_check_fee_multiple_commands_v12.xml");
|
||||
runFlowAssertResponse(
|
||||
loadFile("domain_check_fee_multiple_commands_default_token_response_v12.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_multipleCommands_defaultTokenOnlyOnCreate_std_v1() throws Exception {
|
||||
setUpDefaultToken();
|
||||
setEppInput("domain_check_fee_multiple_commands_stdv1.xml");
|
||||
runFlowAssertResponse(
|
||||
loadFile("domain_check_fee_multiple_commands_default_token_response_stdv1.xml"));
|
||||
}
|
||||
|
||||
@Disabled("TODO(b/454680236): broken test")
|
||||
@@ -1316,33 +1376,47 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v11_update.xml"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideFeeTestParams")
|
||||
void testFeeExtension_premiumLabels_latest(String name, FeeFileLoader loader) throws Exception {
|
||||
@Test
|
||||
void testFeeExtension_premiumLabels_v12() throws Exception {
|
||||
createTld("example");
|
||||
setEppInputXml(loader.load(this, "domain_check_fee_premium_v12.xml"));
|
||||
runFlowAssertResponse(loader.load(this, "domain_check_fee_premium_response_v12.xml"));
|
||||
setEppInput("domain_check_fee_premium_v12.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v12.xml"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideFeeTestParams")
|
||||
void testFeeExtension_premiumLabels_v12_specifiedPriceRenewal_renewPriceOnly(
|
||||
String name, FeeFileLoader loader) throws Exception {
|
||||
@Test
|
||||
void testFeeExtension_premiumLabels_std_v1() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_stdv1.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_stdv1.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_premiumLabels_v12_specifiedPriceRenewal_renewPriceOnly() throws Exception {
|
||||
createTld("example");
|
||||
persistBillingRecurrenceForDomain(
|
||||
persistActiveDomain("rich.example"), SPECIFIED, Money.of(USD, new BigDecimal("27.74")));
|
||||
setEppInputXml(loader.load(this, "domain_check_fee_premium_v12_renew_only.xml"));
|
||||
setEppInput("domain_check_fee_premium_v12_renew_only.xml");
|
||||
runFlowAssertResponse(
|
||||
loader.load(
|
||||
this,
|
||||
loadFile(
|
||||
"domain_check_fee_premium_response_v12_renew_only.xml",
|
||||
ImmutableMap.of("RENEWPRICE", "27.74")));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideFeeTestParams")
|
||||
void testFeeExtension_premiumLabels_doesNotApplyDefaultToken_latest(
|
||||
String name, FeeFileLoader loader) throws Exception {
|
||||
@Test
|
||||
void testFeeExtension_premiumLabels_std_v1_specifiedPriceRenewal_renewPriceOnly()
|
||||
throws Exception {
|
||||
createTld("example");
|
||||
persistBillingRecurrenceForDomain(
|
||||
persistActiveDomain("rich.example"), SPECIFIED, Money.of(USD, new BigDecimal("27.74")));
|
||||
setEppInput("domain_check_fee_premium_stdv1_renew_only.xml");
|
||||
runFlowAssertResponse(
|
||||
loadFile(
|
||||
"domain_check_fee_premium_response_stdv1_renew_only.xml",
|
||||
ImmutableMap.of("RENEWPRICE", "27.74")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_premiumLabels_doesNotApplyDefaultToken_v12() throws Exception {
|
||||
createTld("example");
|
||||
AllocationToken defaultToken =
|
||||
persistResource(
|
||||
@@ -1359,19 +1433,46 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
.asBuilder()
|
||||
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
|
||||
.build());
|
||||
setEppInputXml(loader.load(this, "domain_check_fee_premium_v12.xml"));
|
||||
runFlowAssertResponse(loader.load(this, "domain_check_fee_premium_response_v12.xml"));
|
||||
setEppInput("domain_check_fee_premium_v12.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v12.xml"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideFeeTestParams")
|
||||
void testFeeExtension_premiumLabels_v12_withRenewalOnRestore(String name, FeeFileLoader loader)
|
||||
throws Exception {
|
||||
@Test
|
||||
void testFeeExtension_premiumLabels_doesNotApplyDefaultToken_std_v1() throws Exception {
|
||||
createTld("example");
|
||||
setEppInputXml(loader.load(this, "domain_check_fee_premium_v12.xml"));
|
||||
AllocationToken defaultToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("bbbbb")
|
||||
.setTokenType(DEFAULT_PROMO)
|
||||
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
|
||||
.setAllowedTlds(ImmutableSet.of("example"))
|
||||
.setDiscountPremiums(false)
|
||||
.setDiscountFraction(0.5)
|
||||
.build());
|
||||
persistResource(
|
||||
Tld.get("example")
|
||||
.asBuilder()
|
||||
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
|
||||
.build());
|
||||
setEppInput("domain_check_fee_premium_stdv1.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_stdv1.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_premiumLabels_v12_withRenewalOnRestore() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_v12.xml");
|
||||
persistPendingDeleteDomain("rich.example");
|
||||
runFlowAssertResponse(
|
||||
loader.load(this, "domain_check_fee_premium_response_v12_with_renewal.xml"));
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_v12_with_renewal.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_premiumLabels_std_v1_withRenewalOnRestore() throws Exception {
|
||||
createTld("example");
|
||||
setEppInput("domain_check_fee_premium_stdv1.xml");
|
||||
persistPendingDeleteDomain("rich.example");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_premium_response_stdv1_with_renewal.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1482,23 +1583,32 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
loadFile("domain_check_fee_reserved_response_v11_restore_with_renewals.xml"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideFeeTestParams")
|
||||
void testFeeExtension_reservedName_latest(String name, FeeFileLoader loader) throws Exception {
|
||||
@Test
|
||||
void testFeeExtension_reservedName_v12() throws Exception {
|
||||
persistResource(
|
||||
Tld.get("tld")
|
||||
.asBuilder()
|
||||
.setReservedLists(createReservedList())
|
||||
.setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70"))
|
||||
.build());
|
||||
setEppInputXml(loader.load(this, "domain_check_fee_reserved_v12.xml"));
|
||||
runFlowAssertResponse(loader.load(this, "domain_check_fee_reserved_response_v12.xml"));
|
||||
setEppInput("domain_check_fee_reserved_v12.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_reserved_response_v12.xml"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideFeeTestParams")
|
||||
void testFeeExtension_reservedName_restoreFeeWithDupes_latest(String name, FeeFileLoader loader)
|
||||
throws Exception {
|
||||
@Test
|
||||
void testFeeExtension_reservedName_std_v1() throws Exception {
|
||||
persistResource(
|
||||
Tld.get("tld")
|
||||
.asBuilder()
|
||||
.setReservedLists(createReservedList())
|
||||
.setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70"))
|
||||
.build());
|
||||
setEppInput("domain_check_fee_reserved_stdv1.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_reserved_response_stdv1.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_reservedName_restoreFeeWithDupes_v12() throws Exception {
|
||||
persistResource(
|
||||
Tld.get("tld")
|
||||
.asBuilder()
|
||||
@@ -1506,9 +1616,23 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
.setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70"))
|
||||
.build());
|
||||
// The domain needs to exist in order for it to be loaded to check for restore fee.
|
||||
setEppInputXml(loader.load(this, "domain_check_fee_reserved_dupes_v12.xml"));
|
||||
setEppInput("domain_check_fee_reserved_dupes_v12.xml");
|
||||
persistBillingRecurrenceForDomain(persistActiveDomain("allowedinsunrise.tld"), DEFAULT, null);
|
||||
runFlowAssertResponse(loader.load(this, "domain_check_fee_reserved_dupes_response_v12.xml"));
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_reserved_dupes_response_v12.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_reservedName_restoreFeeWithDupes_std_v1() throws Exception {
|
||||
persistResource(
|
||||
Tld.get("tld")
|
||||
.asBuilder()
|
||||
.setReservedLists(createReservedList())
|
||||
.setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70"))
|
||||
.build());
|
||||
// The domain needs to exist in order for it to be loaded to check for restore fee.
|
||||
setEppInput("domain_check_fee_reserved_dupes_stdv1.xml");
|
||||
persistBillingRecurrenceForDomain(persistActiveDomain("allowedinsunrise.tld"), DEFAULT, null);
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_reserved_dupes_response_stdv1.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1595,10 +1719,8 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_reserved_sunrise_response_v11_restore.xml"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideFeeTestParams")
|
||||
void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_latest(
|
||||
String name, FeeFileLoader loader) throws Exception {
|
||||
@Test
|
||||
void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_v12() throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Tld.get("tld")
|
||||
@@ -1606,8 +1728,21 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
.setReservedLists(createReservedList())
|
||||
.setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70"))
|
||||
.build());
|
||||
setEppInputXml(loader.load(this, "domain_check_fee_reserved_v12.xml"));
|
||||
runFlowAssertResponse(loader.load(this, "domain_check_fee_reserved_sunrise_response_v12.xml"));
|
||||
setEppInput("domain_check_fee_reserved_v12.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_reserved_sunrise_response_v12.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_feesNotOmittedOnReservedNamesInSunrise_std_v1() throws Exception {
|
||||
createTld("tld", START_DATE_SUNRISE);
|
||||
persistResource(
|
||||
Tld.get("tld")
|
||||
.asBuilder()
|
||||
.setReservedLists(createReservedList())
|
||||
.setPremiumList(persistPremiumList("tld", USD, "premiumcollision,USD 70"))
|
||||
.build());
|
||||
setEppInput("domain_check_fee_reserved_stdv1.xml");
|
||||
runFlowAssertResponse(loadFile("domain_check_fee_reserved_sunrise_response_stdv1.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1794,14 +1929,47 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideFeeTestParams")
|
||||
void testFeeExtension_invalidCommand_latest(String name, FeeFileLoader loader) {
|
||||
setEppInputXml(loader.load(this, "domain_check_fee_invalid_command_v12.xml"));
|
||||
@Test
|
||||
void testFeeExtension_invalidCommand_v12() {
|
||||
setEppInput("domain_check_fee_invalid_command_v12.xml");
|
||||
EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_invalidCommand_std_v1() {
|
||||
setEppInput("domain_check_fee_invalid_command_stdv1.xml");
|
||||
EppException thrown = assertThrows(UnknownFeeCommandException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFeeExtension_invalid_multipleCurrencies_std_v1() {
|
||||
persistResource(
|
||||
createTld("example")
|
||||
.asBuilder()
|
||||
.setCurrency(JPY)
|
||||
.setCreateBillingCostTransitions(
|
||||
ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
|
||||
.setEapFeeSchedule(ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
|
||||
.setRenewBillingCostTransitions(
|
||||
ImmutableSortedMap.of(START_OF_TIME, Money.ofMajor(JPY, 800)))
|
||||
.setRegistryLockOrUnlockBillingCost(Money.ofMajor(JPY, 800))
|
||||
.setServerStatusChangeBillingCost(Money.ofMajor(JPY, 800))
|
||||
.setRestoreBillingCost(Money.ofMajor(JPY, 800))
|
||||
.build());
|
||||
persistResource(
|
||||
Registrar.loadByRegistrarId("TheRegistrar")
|
||||
.get()
|
||||
.asBuilder()
|
||||
.setBillingAccountMap(ImmutableMap.of(USD, "foo", JPY, "bar"))
|
||||
.build());
|
||||
setEppInput("domain_check_fee_multiple_currencies_stdv1.xml");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(MultipleCurrenciesCannotBeCheckedException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_eapFeeCheck_v06() throws Exception {
|
||||
runEapFeeCheckTest(
|
||||
@@ -1834,21 +2002,11 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
new FeeFileLoader(/* isFeeStdV1= */ false));
|
||||
}
|
||||
|
||||
@Disabled("v1.0 buggy")
|
||||
@Test
|
||||
void testSuccess_eapFeeCheck_std_v1() throws Exception {
|
||||
runEapFeeCheckTest(
|
||||
"domain_check_fee_v12.xml",
|
||||
"domain_check_eap_fee_response_v12.xml",
|
||||
new FeeFileLoader(/* isFeeStdV1= */ true));
|
||||
}
|
||||
|
||||
@Disabled("v1.0 buggy")
|
||||
@Test
|
||||
void testSuccess_eapFeeCheck_date_std_v1() throws Exception {
|
||||
runEapFeeCheckTest(
|
||||
"domain_check_fee_date_v12.xml",
|
||||
"domain_check_eap_fee_response_date_v12.xml",
|
||||
"domain_check_fee_stdv1.xml",
|
||||
"domain_check_eap_fee_response_stdv1.xml",
|
||||
new FeeFileLoader(/* isFeeStdV1= */ true));
|
||||
}
|
||||
|
||||
@@ -2003,10 +2161,14 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fee versions 0.12 and 1.0 are the same in how they're requested (though not in the responses.
|
||||
* As a result, for tests that throw an exception, we can use the same XML content.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static Stream<Arguments> provideFeeTestParams() {
|
||||
return Stream.of(
|
||||
// Arguments.of("fee_std_v1", new FeeFileLoader(true)),
|
||||
Arguments.of("fee_std_v1", new FeeFileLoader(true)),
|
||||
Arguments.of("fee_12", new FeeFileLoader(false)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,11 +63,11 @@ import google.registry.config.RegistryConfig;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.UnimplementedExtensionException;
|
||||
import google.registry.flows.EppRequestSource;
|
||||
import google.registry.flows.FlowTestCase.CommitMode;
|
||||
import google.registry.flows.FlowTestCase.UserPrivileges;
|
||||
import google.registry.flows.FlowUtils.NotLoggedInException;
|
||||
import google.registry.flows.ResourceFlowTestCase;
|
||||
import google.registry.flows.ResourceFlowUtils.AddExistingValueException;
|
||||
import google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException;
|
||||
import google.registry.flows.ResourceFlowUtils.RemoveNonexistentValueException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException;
|
||||
@@ -452,6 +452,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
|
||||
@Test
|
||||
void testSuccess_removeClientUpdateProhibited() throws Exception {
|
||||
setEppInput("domain_update_remove_client_update_prohibited.xml");
|
||||
persistReferencedEntities();
|
||||
persistResource(
|
||||
persistDomain()
|
||||
@@ -547,21 +548,26 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_secDnsAddSameDoesNothing() throws Exception {
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_dsdata_add.xml",
|
||||
ImmutableSet.of(SOME_DSDATA),
|
||||
ImmutableSet.of(SOME_DSDATA),
|
||||
ImmutableMap.of(
|
||||
"KEY_TAG",
|
||||
"1",
|
||||
"ALG",
|
||||
"2",
|
||||
"DIGEST_TYPE",
|
||||
"2",
|
||||
"DIGEST",
|
||||
"9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08"),
|
||||
false);
|
||||
void testFailure_secDnsAddSame_throwsException() throws Exception {
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
AddExistingValueException.class,
|
||||
() ->
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_dsdata_add.xml",
|
||||
ImmutableSet.of(SOME_DSDATA),
|
||||
ImmutableSet.of(SOME_DSDATA),
|
||||
ImmutableMap.of(
|
||||
"KEY_TAG",
|
||||
"1",
|
||||
"ALG",
|
||||
"2",
|
||||
"DIGEST_TYPE",
|
||||
"2",
|
||||
"DIGEST",
|
||||
"9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08"),
|
||||
false));
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -679,7 +685,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
2,
|
||||
2,
|
||||
base16()
|
||||
.decode("9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08"))),
|
||||
.decode("0F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08"))),
|
||||
ImmutableMap.of(
|
||||
"KEY_TAG",
|
||||
"1",
|
||||
@@ -688,8 +694,8 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
"DIGEST_TYPE",
|
||||
"2",
|
||||
"DIGEST",
|
||||
"9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08"),
|
||||
false);
|
||||
"0F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08"),
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -797,29 +803,43 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_secDnsAddRemoveSame() throws Exception {
|
||||
// Adding and removing the same dsData is a no-op because removes are processed first.
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_dsdata_add_rem_same.xml",
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DomainDsData.create(
|
||||
12345, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DomainDsData.create(
|
||||
12345, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
|
||||
false);
|
||||
void testFailure_secDnsAddRemoveSame_throwsException() throws Exception {
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
AddRemoveSameValueException.class,
|
||||
() ->
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_dsdata_add_rem_same.xml",
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DomainDsData.create(
|
||||
12345,
|
||||
3,
|
||||
1,
|
||||
base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DomainDsData.create(
|
||||
12345,
|
||||
3,
|
||||
1,
|
||||
base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
|
||||
false));
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_secDnsRemoveAlreadyNotThere() throws Exception {
|
||||
// Removing a dsData that isn't there is a no-op.
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_dsdata_rem.xml",
|
||||
ImmutableSet.of(SOME_DSDATA),
|
||||
ImmutableSet.of(SOME_DSDATA),
|
||||
false);
|
||||
void testFailure_secDnsRemoveAlreadyNotThere_throwsException() throws Exception {
|
||||
EppException thrown =
|
||||
assertThrows(
|
||||
RemoveNonexistentValueException.class,
|
||||
() ->
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_dsdata_rem.xml",
|
||||
ImmutableSet.of(SOME_DSDATA),
|
||||
ImmutableSet.of(SOME_DSDATA),
|
||||
false));
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
void doServerStatusBillingTest(String xmlFilename, boolean isBillable) throws Exception {
|
||||
@@ -854,14 +874,6 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
doServerStatusBillingTest("domain_update_add_server_status.xml", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_noBillingOnPreExistingServerStatus() throws Exception {
|
||||
eppRequestSource = EppRequestSource.TOOL;
|
||||
Domain addStatusDomain = persistActiveDomain(getUniqueIdFromCommand());
|
||||
persistResource(addStatusDomain.asBuilder().addStatusValue(SERVER_RENEW_PROHIBITED).build());
|
||||
doServerStatusBillingTest("domain_update_add_server_status.xml", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_removeServerStatusBillingEvent() throws Exception {
|
||||
eppRequestSource = EppRequestSource.TOOL;
|
||||
@@ -1373,6 +1385,52 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_addExistingNameserver() throws Exception {
|
||||
Host host = persistActiveHost("ns2.example.foo");
|
||||
persistResource(
|
||||
DatabaseHelper.newDomain(getUniqueIdFromCommand())
|
||||
.asBuilder()
|
||||
.setNameservers(ImmutableSet.of(host.createVKey()))
|
||||
.build());
|
||||
setEppInput("domain_update_add_nameserver.xml");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(AddExistingValueException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_addExistingStatusValue() throws Exception {
|
||||
persistResource(
|
||||
DatabaseHelper.newDomain(getUniqueIdFromCommand())
|
||||
.asBuilder()
|
||||
.setStatusValues(ImmutableSet.of(CLIENT_RENEW_PROHIBITED))
|
||||
.build());
|
||||
setEppInput("domain_update_add_non_server_status.xml");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(AddExistingValueException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_removeNonexistentNameserver() throws Exception {
|
||||
persistActiveDomain(getUniqueIdFromCommand());
|
||||
persistActiveHost("ns1.example.foo");
|
||||
setEppInput("domain_update_remove_nameserver.xml");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(RemoveNonexistentValueException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_removeNonexistentStatusValue() throws Exception {
|
||||
persistActiveDomain(getUniqueIdFromCommand());
|
||||
setEppInput("domain_update_remove_client_update_prohibited.xml");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(RemoveNonexistentValueException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_minimumDataset_addingNewRegistrantFails() throws Exception {
|
||||
persistReferencedEntities();
|
||||
|
||||
@@ -45,6 +45,7 @@ import google.registry.flows.host.HostFlowUtils.HostNameNotNormalizedException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameNotPunyCodedException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameTooLongException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException;
|
||||
import google.registry.flows.host.HostFlowUtils.LoopbackIpNotValidForHostException;
|
||||
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException;
|
||||
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainInPendingDeleteException;
|
||||
import google.registry.model.ForeignKeyUtils;
|
||||
@@ -322,6 +323,26 @@ class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Host> {
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_localhostInetAddress_ipv4() {
|
||||
createTld("tld");
|
||||
persistActiveDomain("example.tld");
|
||||
setEppHostCreateInput("ns1.example.tld", "<host:addr ip=\"v4\">127.0.0.1</host:addr>");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(LoopbackIpNotValidForHostException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_localhostInetAddress_ipv6() {
|
||||
createTld("tld");
|
||||
persistActiveDomain("example.tld");
|
||||
setEppHostCreateInput("ns1.example.tld", "<host:addr ip=\"v6\">::1</host:addr>");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(LoopbackIpNotValidForHostException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIcannActivityReportField_getsLogged() throws Exception {
|
||||
runFlow();
|
||||
|
||||
@@ -48,7 +48,9 @@ import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppRequestSource;
|
||||
import google.registry.flows.FlowUtils.NotLoggedInException;
|
||||
import google.registry.flows.ResourceFlowTestCase;
|
||||
import google.registry.flows.ResourceFlowUtils.AddExistingValueException;
|
||||
import google.registry.flows.ResourceFlowUtils.AddRemoveSameValueException;
|
||||
import google.registry.flows.ResourceFlowUtils.RemoveNonexistentValueException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceDoesNotExistException;
|
||||
import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException;
|
||||
@@ -61,6 +63,7 @@ import google.registry.flows.host.HostFlowUtils.HostNameNotNormalizedException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameNotPunyCodedException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameTooLongException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException;
|
||||
import google.registry.flows.host.HostFlowUtils.LoopbackIpNotValidForHostException;
|
||||
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException;
|
||||
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainInPendingDeleteException;
|
||||
import google.registry.flows.host.HostUpdateFlow.CannotAddIpToExternalHostException;
|
||||
@@ -521,6 +524,8 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
.asBuilder()
|
||||
.setSuperordinateDomain(foo.createVKey())
|
||||
.setLastTransferTime(null)
|
||||
.setInetAddresses(
|
||||
ImmutableSet.of(InetAddresses.forString("1080:0:0:0:8:800:200C:417A")))
|
||||
.build());
|
||||
persistResource(foo.asBuilder().setSubordinateHosts(ImmutableSet.of(oldHostName())).build());
|
||||
clock.advanceOneMilli();
|
||||
@@ -560,6 +565,8 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
.setSuperordinateDomain(domain.createVKey())
|
||||
.setLastTransferTime(clock.nowUtc().minusDays(20))
|
||||
.setLastSuperordinateChange(clock.nowUtc().minusDays(3))
|
||||
.setInetAddresses(
|
||||
ImmutableSet.of(InetAddresses.forString("1080:0:0:0:8:800:200C:417A")))
|
||||
.build());
|
||||
DateTime lastTransferTime = host.getLastTransferTime();
|
||||
persistResource(domain.asBuilder().setSubordinateHosts(ImmutableSet.of(oldHostName())).build());
|
||||
@@ -597,6 +604,8 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
.setSuperordinateDomain(foo.createVKey())
|
||||
.setLastTransferTime(lastTransferTime)
|
||||
.setLastSuperordinateChange(clock.nowUtc().minusDays(3))
|
||||
.setInetAddresses(
|
||||
ImmutableSet.of(InetAddresses.forString("1080:0:0:0:8:800:200C:417A")))
|
||||
.build());
|
||||
persistResource(foo.asBuilder().setSubordinateHosts(ImmutableSet.of(oldHostName())).build());
|
||||
clock.advanceOneMilli();
|
||||
@@ -631,6 +640,8 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
.setSuperordinateDomain(foo.createVKey())
|
||||
.setLastTransferTime(lastTransferTime)
|
||||
.setLastSuperordinateChange(clock.nowUtc().minusDays(10))
|
||||
.setInetAddresses(
|
||||
ImmutableSet.of(InetAddresses.forString("1080:0:0:0:8:800:200C:417A")))
|
||||
.build());
|
||||
persistResource(foo.asBuilder().setSubordinateHosts(ImmutableSet.of(oldHostName())).build());
|
||||
clock.advanceOneMilli();
|
||||
@@ -665,6 +676,8 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
.setSuperordinateDomain(foo.createVKey())
|
||||
.setLastTransferTime(null)
|
||||
.setLastSuperordinateChange(clock.nowUtc().minusDays(3))
|
||||
.setInetAddresses(
|
||||
ImmutableSet.of(InetAddresses.forString("1080:0:0:0:8:800:200C:417A")))
|
||||
.build());
|
||||
persistResource(foo.asBuilder().setSubordinateHosts(ImmutableSet.of(oldHostName())).build());
|
||||
Host renamedHost = doSuccessfulTest();
|
||||
@@ -686,7 +699,12 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
createTld("foo");
|
||||
Domain domain = persistActiveDomain("example.foo");
|
||||
persistResource(
|
||||
newHost(oldHostName()).asBuilder().setSuperordinateDomain(domain.createVKey()).build());
|
||||
newHost(oldHostName())
|
||||
.asBuilder()
|
||||
.setSuperordinateDomain(domain.createVKey())
|
||||
.setInetAddresses(
|
||||
ImmutableSet.of(InetAddresses.forString("1080:0:0:0:8:800:200C:417A")))
|
||||
.build());
|
||||
DateTime lastTransferTime = clock.nowUtc().minusDays(2);
|
||||
persistResource(
|
||||
domain
|
||||
@@ -727,6 +745,8 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
.setSuperordinateDomain(domain.createVKey())
|
||||
.setLastTransferTime(lastTransferTime)
|
||||
.setLastSuperordinateChange(clock.nowUtc().minusDays(4))
|
||||
.setInetAddresses(
|
||||
ImmutableSet.of(InetAddresses.forString("1080:0:0:0:8:800:200C:417A")))
|
||||
.build());
|
||||
persistResource(
|
||||
domain
|
||||
@@ -762,6 +782,8 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
.setSuperordinateDomain(domain.createVKey())
|
||||
.setLastTransferTime(clock.nowUtc().minusDays(12))
|
||||
.setLastSuperordinateChange(clock.nowUtc().minusDays(4))
|
||||
.setInetAddresses(
|
||||
ImmutableSet.of(InetAddresses.forString("1080:0:0:0:8:800:200C:417A")))
|
||||
.build());
|
||||
domain =
|
||||
persistResource(
|
||||
@@ -1006,6 +1028,50 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_addExistingInetAddress() throws Exception {
|
||||
createTld("tld");
|
||||
Domain domain = persistActiveDomain("example.tld");
|
||||
persistResource(
|
||||
newHost(oldHostName())
|
||||
.asBuilder()
|
||||
.setSuperordinateDomain(domain.createVKey())
|
||||
.setLastTransferTime(clock.nowUtc().minusDays(12))
|
||||
.setLastSuperordinateChange(clock.nowUtc().minusDays(4))
|
||||
.setInetAddresses(
|
||||
ImmutableSet.of(InetAddresses.forString("1080:0:0:0:8:800:200C:417A")))
|
||||
.build());
|
||||
setEppHostUpdateInput(
|
||||
"ns1.example.tld",
|
||||
"ns2.example.tld",
|
||||
"<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>",
|
||||
null);
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(AddExistingValueException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_removeNonexistentInetAddress() throws Exception {
|
||||
createTld("tld");
|
||||
Domain domain = persistActiveDomain("example.tld");
|
||||
persistResource(
|
||||
newHost(oldHostName())
|
||||
.asBuilder()
|
||||
.setSuperordinateDomain(domain.createVKey())
|
||||
.setLastTransferTime(clock.nowUtc().minusDays(12))
|
||||
.setLastSuperordinateChange(clock.nowUtc().minusDays(4))
|
||||
.build());
|
||||
setEppHostUpdateInput(
|
||||
"ns1.example.tld",
|
||||
"ns2.example.tld",
|
||||
null,
|
||||
"<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(RemoveNonexistentValueException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_clientUpdateProhibited_removed() throws Exception {
|
||||
setEppInput("host_update_remove_client_update_prohibited.xml");
|
||||
@@ -1077,7 +1143,12 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
setEppInput("host_update_prohibited_status.xml");
|
||||
createTld("tld");
|
||||
persistActiveDomain("example.tld");
|
||||
persistActiveHost("ns1.example.tld");
|
||||
persistResource(
|
||||
persistActiveHost("ns1.example.tld")
|
||||
.asBuilder()
|
||||
.setInetAddresses(
|
||||
ImmutableSet.of(InetAddresses.forString("1080:0:0:0:8:800:200C:417A")))
|
||||
.build());
|
||||
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
@@ -1306,6 +1377,28 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
doFailingHostNameTest("foo.co.uk", HostNameTooShallowException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_localhostInetAddress_ipv4() throws Exception {
|
||||
createTld("tld");
|
||||
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
|
||||
setEppHostUpdateInput(
|
||||
"ns1.example.tld", "ns2.example.tld", "<host:addr ip=\"v4\">127.0.0.1</host:addr>", null);
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(LoopbackIpNotValidForHostException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_localhostInetAddress_ipv6() throws Exception {
|
||||
createTld("tld");
|
||||
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
|
||||
setEppHostUpdateInput(
|
||||
"ns1.example.tld", "ns2.example.tld", "<host:addr ip=\"v6\">::1</host:addr>", null);
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(LoopbackIpNotValidForHostException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_metadata() throws Exception {
|
||||
createTld("tld");
|
||||
|
||||
@@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Tests for {@link EppXmlTransformer}. */
|
||||
@@ -38,4 +39,26 @@ class EppXmlTransformerTest {
|
||||
ClassCastException.class,
|
||||
() -> unmarshal(EppOutput.class, loadBytes(getClass(), "contact_info.xml").read()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSchemas_inNonProduction_includesFee1Point0() {
|
||||
var currentEnv = RegistryEnvironment.get();
|
||||
try {
|
||||
RegistryEnvironment.SANDBOX.setup();
|
||||
assertThat(EppXmlTransformer.getSchemas()).contains("fee-std-v1.xsd");
|
||||
} finally {
|
||||
currentEnv.setup();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSchemas_inProduction_skipsFee1Point0() {
|
||||
var currentEnv = RegistryEnvironment.get();
|
||||
try {
|
||||
RegistryEnvironment.PRODUCTION.setup();
|
||||
assertThat(EppXmlTransformer.getSchemas()).doesNotContain("fee-std-v1.xsd");
|
||||
} finally {
|
||||
currentEnv.setup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,10 +68,7 @@ class EppInputTest {
|
||||
assertThat(loginCommand.options.version).isEqualTo("1.0");
|
||||
assertThat(loginCommand.options.language).isEqualTo("en");
|
||||
assertThat(loginCommand.services.objectServices)
|
||||
.containsExactly(
|
||||
"urn:ietf:params:xml:ns:host-1.0",
|
||||
"urn:ietf:params:xml:ns:domain-1.0",
|
||||
"urn:ietf:params:xml:ns:contact-1.0");
|
||||
.containsExactly("urn:ietf:params:xml:ns:host-1.0", "urn:ietf:params:xml:ns:domain-1.0");
|
||||
assertThat(loginCommand.services.serviceExtensions)
|
||||
.containsExactly("urn:ietf:params:xml:ns:launch-1.0", "urn:ietf:params:xml:ns:rgp-1.0");
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import google.registry.flows.TlsCredentials.EppTlsModule;
|
||||
import google.registry.flows.custom.CustomLogicModule;
|
||||
import google.registry.loadtest.LoadTestModule;
|
||||
import google.registry.monitoring.whitebox.WhiteboxModule;
|
||||
import google.registry.mosapi.module.MosApiRequestModule;
|
||||
import google.registry.rdap.RdapModule;
|
||||
import google.registry.rde.RdeModule;
|
||||
import google.registry.reporting.ReportingModule;
|
||||
@@ -60,6 +61,7 @@ import google.registry.ui.server.console.ConsoleModule;
|
||||
EppToolModule.class,
|
||||
IcannReportingModule.class,
|
||||
LoadTestModule.class,
|
||||
MosApiRequestModule.class,
|
||||
RdapModule.class,
|
||||
RdeModule.class,
|
||||
ReportingModule.class,
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright 2025 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.mosapi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.mosapi.MosApiModels.AllServicesStateResponse;
|
||||
import google.registry.mosapi.MosApiModels.ServiceStateSummary;
|
||||
import google.registry.request.HttpException.ServiceUnavailableException;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/** Unit tests for {@link GetServiceStateAction}. */
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class GetServiceStateActionTest {
|
||||
|
||||
@Mock private MosApiStateService stateService;
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
@Test
|
||||
void testRun_singleTld_returnsStateForTld() throws Exception {
|
||||
GetServiceStateAction action =
|
||||
new GetServiceStateAction(stateService, response, gson, Optional.of("example"));
|
||||
|
||||
ServiceStateSummary summary = new ServiceStateSummary("example", "Up", null);
|
||||
when(stateService.getServiceStateSummary("example")).thenReturn(summary);
|
||||
|
||||
action.run();
|
||||
|
||||
assertThat(response.getContentType()).isEqualTo(MediaType.JSON_UTF_8);
|
||||
assertThat(response.getPayload())
|
||||
.contains(
|
||||
"""
|
||||
"overallStatus":"Up"
|
||||
"""
|
||||
.trim());
|
||||
verify(stateService).getServiceStateSummary("example");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_noTld_returnsStateForAll() {
|
||||
GetServiceStateAction action =
|
||||
new GetServiceStateAction(stateService, response, gson, Optional.empty());
|
||||
|
||||
AllServicesStateResponse allStates = new AllServicesStateResponse(ImmutableList.of());
|
||||
when(stateService.getAllServiceStateSummaries()).thenReturn(allStates);
|
||||
|
||||
action.run();
|
||||
|
||||
assertThat(response.getContentType()).isEqualTo(MediaType.JSON_UTF_8);
|
||||
assertThat(response.getPayload())
|
||||
.contains(
|
||||
"""
|
||||
"serviceStates":[]
|
||||
"""
|
||||
.trim());
|
||||
verify(stateService).getAllServiceStateSummaries();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_serviceThrowsException_throwsServiceUnavailable() throws Exception {
|
||||
GetServiceStateAction action =
|
||||
new GetServiceStateAction(stateService, response, gson, Optional.of("example"));
|
||||
|
||||
doThrow(new MosApiException("Backend error", null))
|
||||
.when(stateService)
|
||||
.getServiceStateSummary("example");
|
||||
|
||||
ServiceUnavailableException thrown =
|
||||
assertThrows(ServiceUnavailableException.class, action::run);
|
||||
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("Error fetching MoSAPI service state.");
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
// 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.mosapi.model;
|
||||
package google.registry.mosapi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@@ -20,7 +20,6 @@ import google.registry.mosapi.MosApiException.DateOrderInvalidException;
|
||||
import google.registry.mosapi.MosApiException.EndDateSyntaxInvalidException;
|
||||
import google.registry.mosapi.MosApiException.MosApiAuthorizationException;
|
||||
import google.registry.mosapi.MosApiException.StartDateSyntaxInvalidException;
|
||||
import google.registry.mosapi.model.MosApiErrorResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link MosApiException}. */
|
||||
|
||||
172
core/src/test/java/google/registry/mosapi/MosApiModelsTest.java
Normal file
172
core/src/test/java/google/registry/mosapi/MosApiModelsTest.java
Normal file
@@ -0,0 +1,172 @@
|
||||
// Copyright 2025 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.mosapi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import google.registry.mosapi.MosApiModels.AllServicesStateResponse;
|
||||
import google.registry.mosapi.MosApiModels.IncidentSummary;
|
||||
import google.registry.mosapi.MosApiModels.ServiceStateSummary;
|
||||
import google.registry.mosapi.MosApiModels.ServiceStatus;
|
||||
import google.registry.mosapi.MosApiModels.TldServiceState;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Tests for {@link MosApiModels}. */
|
||||
public final class MosApiModelsTest {
|
||||
|
||||
private static final Gson gson =
|
||||
new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
|
||||
|
||||
@Test
|
||||
public void testAllServicesStateResponse_nullCollection_initializedToEmpty() {
|
||||
AllServicesStateResponse response = new AllServicesStateResponse(null);
|
||||
assertThat(response.serviceStates()).isEmpty();
|
||||
assertThat(response.serviceStates()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServiceStateSummary_nullCollection_initializedToEmpty() {
|
||||
ServiceStateSummary summary = new ServiceStateSummary("example", "Up", null);
|
||||
assertThat(summary.activeIncidents()).isEmpty();
|
||||
assertThat(summary.activeIncidents()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServiceStatus_nullCollection_initializedToEmpty() {
|
||||
ServiceStatus status = new ServiceStatus("Up", 0.0, null);
|
||||
assertThat(status.incidents()).isEmpty();
|
||||
assertThat(status.incidents()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTldServiceState_nullCollection_initializedToEmpty() {
|
||||
TldServiceState state = new TldServiceState("example", 123456L, "Up", null);
|
||||
assertThat(state.serviceStatuses()).isEmpty();
|
||||
assertThat(state.serviceStatuses()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncidentSummary_jsonSerialization() {
|
||||
IncidentSummary incident = new IncidentSummary("inc-123", 1000L, false, "Active", 2000L);
|
||||
String json = gson.toJson(incident);
|
||||
// Using Text Blocks to avoid escaping quotes
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"incidentID":"inc-123"
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"startTime":1000
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"falsePositive":false
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"state":"Active"
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"endTime":2000
|
||||
"""
|
||||
.trim());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServiceStatus_jsonSerialization() {
|
||||
IncidentSummary incident = new IncidentSummary("inc-1", 1000L, false, "Resolved", null);
|
||||
ServiceStatus status = new ServiceStatus("Down", 75.5, ImmutableList.of(incident));
|
||||
String json = gson.toJson(status);
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"status":"Down"
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"emergencyThreshold":75.5
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"incidents":[
|
||||
"""
|
||||
.trim());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTldServiceState_jsonSerialization() {
|
||||
ServiceStatus dnsStatus = new ServiceStatus("Up", 0.0, ImmutableList.of());
|
||||
TldServiceState state =
|
||||
new TldServiceState("app", 1700000000L, "Up", ImmutableMap.of("DNS", dnsStatus));
|
||||
|
||||
String json = gson.toJson(state);
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"tld":"app"
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"status":"Up"
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"testedServices":{"DNS":{
|
||||
"""
|
||||
.trim());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllServicesStateResponse_jsonSerialization() {
|
||||
ServiceStateSummary summary = new ServiceStateSummary("dev", "Up", ImmutableList.of());
|
||||
AllServicesStateResponse response = new AllServicesStateResponse(ImmutableList.of(summary));
|
||||
|
||||
String json = gson.toJson(response);
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"serviceStates":[
|
||||
"""
|
||||
.trim());
|
||||
assertThat(json)
|
||||
.contains(
|
||||
"""
|
||||
"tld":"dev"
|
||||
"""
|
||||
.trim());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
// Copyright 2025 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.mosapi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import google.registry.mosapi.MosApiModels.AllServicesStateResponse;
|
||||
import google.registry.mosapi.MosApiModels.IncidentSummary;
|
||||
import google.registry.mosapi.MosApiModels.ServiceStateSummary;
|
||||
import google.registry.mosapi.MosApiModels.ServiceStatus;
|
||||
import google.registry.mosapi.MosApiModels.TldServiceState;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/** Unit tests for {@link MosApiStateService}. */
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class MosApiStateServiceTest {
|
||||
|
||||
@Mock private ServiceMonitoringClient client;
|
||||
@Mock private MosApiMetrics metrics;
|
||||
|
||||
private final ExecutorService executor = MoreExecutors.newDirectExecutorService();
|
||||
|
||||
private MosApiStateService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new MosApiStateService(client, metrics, ImmutableSet.of("tld1", "tld2"), executor);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetServiceStateSummary_upStatus_returnsEmptyIncidents() throws Exception {
|
||||
TldServiceState rawState = new TldServiceState("tld1", 12345L, "Up", ImmutableMap.of());
|
||||
when(client.getTldServiceState("tld1")).thenReturn(rawState);
|
||||
|
||||
ServiceStateSummary result = service.getServiceStateSummary("tld1");
|
||||
|
||||
assertThat(result.tld()).isEqualTo("tld1");
|
||||
assertThat(result.overallStatus()).isEqualTo("Up");
|
||||
assertThat(result.activeIncidents()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetServiceStateSummary_downStatus_filtersActiveIncidents() throws Exception {
|
||||
IncidentSummary dnsIncident = new IncidentSummary("inc-1", 100L, false, "Open", null);
|
||||
ServiceStatus dnsService = new ServiceStatus("Down", 50.0, ImmutableList.of(dnsIncident));
|
||||
|
||||
ServiceStatus rdapService = new ServiceStatus("Up", 0.0, ImmutableList.of());
|
||||
|
||||
TldServiceState rawState =
|
||||
new TldServiceState(
|
||||
"tld1", 12345L, "Down", ImmutableMap.of("DNS", dnsService, "RDAP", rdapService));
|
||||
|
||||
when(client.getTldServiceState("tld1")).thenReturn(rawState);
|
||||
|
||||
ServiceStateSummary result = service.getServiceStateSummary("tld1");
|
||||
|
||||
assertThat(result.overallStatus()).isEqualTo("Down");
|
||||
assertThat(result.activeIncidents()).hasSize(1);
|
||||
|
||||
ServiceStatus incidentSummary = result.activeIncidents().get(0);
|
||||
assertThat(incidentSummary.status()).isEqualTo("DNS");
|
||||
assertThat(incidentSummary.incidents()).containsExactly(dnsIncident);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetServiceStateSummary_throwsException_whenClientFails() throws Exception {
|
||||
when(client.getTldServiceState("tld1")).thenThrow(new MosApiException("Network error", null));
|
||||
|
||||
assertThrows(MosApiException.class, () -> service.getServiceStateSummary("tld1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAllServiceStateSummaries_success() throws Exception {
|
||||
TldServiceState state1 = new TldServiceState("tld1", 1L, "Up", ImmutableMap.of());
|
||||
TldServiceState state2 = new TldServiceState("tld2", 2L, "Up", ImmutableMap.of());
|
||||
|
||||
when(client.getTldServiceState("tld1")).thenReturn(state1);
|
||||
when(client.getTldServiceState("tld2")).thenReturn(state2);
|
||||
|
||||
AllServicesStateResponse response = service.getAllServiceStateSummaries();
|
||||
|
||||
assertThat(response.serviceStates()).hasSize(2);
|
||||
assertThat(response.serviceStates().stream().map(ServiceStateSummary::tld))
|
||||
.containsExactly("tld1", "tld2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetAllServiceStateSummaries_partialFailure_returnsErrorState() throws Exception {
|
||||
TldServiceState state1 = new TldServiceState("tld1", 1L, "Up", ImmutableMap.of());
|
||||
when(client.getTldServiceState("tld1")).thenReturn(state1);
|
||||
|
||||
when(client.getTldServiceState("tld2")).thenThrow(new MosApiException("Failure", null));
|
||||
|
||||
AllServicesStateResponse response = service.getAllServiceStateSummaries();
|
||||
|
||||
assertThat(response.serviceStates()).hasSize(2);
|
||||
|
||||
ServiceStateSummary summary1 =
|
||||
response.serviceStates().stream().filter(s -> s.tld().equals("tld1")).findFirst().get();
|
||||
assertThat(summary1.overallStatus()).isEqualTo("Up");
|
||||
|
||||
ServiceStateSummary summary2 =
|
||||
response.serviceStates().stream().filter(s -> s.tld().equals("tld2")).findFirst().get();
|
||||
|
||||
assertThat(summary2.overallStatus()).isEqualTo("ERROR");
|
||||
assertThat(summary2.activeIncidents()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTriggerMetricsForAllServiceStateSummaries_success() throws Exception {
|
||||
TldServiceState state1 = new TldServiceState("tld1", 1L, "Up", ImmutableMap.of());
|
||||
TldServiceState state2 = new TldServiceState("tld2", 2L, "Up", ImmutableMap.of());
|
||||
|
||||
when(client.getTldServiceState("tld1")).thenReturn(state1);
|
||||
when(client.getTldServiceState("tld2")).thenReturn(state2);
|
||||
|
||||
service.triggerMetricsForAllServiceStateSummaries();
|
||||
|
||||
verify(metrics)
|
||||
.recordStates(
|
||||
argThat(
|
||||
states ->
|
||||
states.size() == 2
|
||||
&& states.stream()
|
||||
.anyMatch(s -> s.tld().equals("tld1") && s.status().equals("Up"))
|
||||
&& states.stream()
|
||||
.anyMatch(s -> s.tld().equals("tld2") && s.status().equals("Up"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTriggerMetricsForAllServiceStateSummaries_partialFailure_recordsErrorMetric()
|
||||
throws Exception {
|
||||
TldServiceState state1 = new TldServiceState("tld1", 1L, "Up", ImmutableMap.of());
|
||||
when(client.getTldServiceState("tld1")).thenReturn(state1);
|
||||
when(client.getTldServiceState("tld2")).thenThrow(new MosApiException("Network Error", null));
|
||||
|
||||
service.triggerMetricsForAllServiceStateSummaries();
|
||||
|
||||
verify(metrics)
|
||||
.recordStates(
|
||||
argThat(
|
||||
states ->
|
||||
states.size() == 1
|
||||
&& states.stream()
|
||||
.anyMatch(s -> s.tld().equals("tld1") && s.status().equals("Up"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
// Copyright 2025 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.mosapi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.anyMap;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.mosapi.MosApiModels.TldServiceState;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.Protocol;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ServiceMonitoringClientTest {
|
||||
|
||||
private static final String TLD = "example";
|
||||
private static final String ENDPOINT = "v2/monitoring/state";
|
||||
private final MosApiClient mosApiClient = mock(MosApiClient.class);
|
||||
private final Gson gson = GsonUtils.provideGson();
|
||||
private ServiceMonitoringClient client;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
client = new ServiceMonitoringClient(mosApiClient, gson);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetTldServiceState_success() throws Exception {
|
||||
String jsonResponse =
|
||||
"""
|
||||
{
|
||||
"tld": "example",
|
||||
"services": [
|
||||
{
|
||||
"service": "DNS",
|
||||
"status": "OPERATIONAL"
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
|
||||
try (Response response = createMockResponse(200, jsonResponse)) {
|
||||
when(mosApiClient.sendGetRequest(eq(TLD), eq(ENDPOINT), anyMap(), anyMap()))
|
||||
.thenReturn(response);
|
||||
|
||||
TldServiceState result = client.getTldServiceState(TLD);
|
||||
assertThat(gson.toJson(result)).contains("example");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetTldServiceState_apiError_throwsMosApiException() throws Exception {
|
||||
String errorJson =
|
||||
"""
|
||||
{
|
||||
"resultCode": "2011",
|
||||
"message": "Invalid duration"
|
||||
}
|
||||
""";
|
||||
|
||||
try (Response response = createMockResponse(400, errorJson)) {
|
||||
when(mosApiClient.sendGetRequest(eq(TLD), eq(ENDPOINT), anyMap(), anyMap()))
|
||||
.thenReturn(response);
|
||||
|
||||
MosApiException thrown =
|
||||
assertThrows(MosApiException.class, () -> client.getTldServiceState(TLD));
|
||||
assertThat(thrown.getMessage()).contains("2011");
|
||||
assertThat(thrown.getMessage()).contains("Invalid duration");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetTldServiceState_nonJsonError_throwsMosApiException() throws Exception {
|
||||
String htmlError =
|
||||
"""
|
||||
<html>
|
||||
<body>502 Bad Gateway</body>
|
||||
</html>
|
||||
""";
|
||||
|
||||
try (Response response = createMockResponse(502, htmlError)) {
|
||||
when(mosApiClient.sendGetRequest(eq(TLD), eq(ENDPOINT), anyMap(), anyMap()))
|
||||
.thenReturn(response);
|
||||
|
||||
MosApiException thrown =
|
||||
assertThrows(MosApiException.class, () -> client.getTldServiceState(TLD));
|
||||
assertThat(thrown.getMessage()).contains("MoSAPI json parsing error (502)");
|
||||
assertThat(thrown.getMessage()).contains("502 Bad Gateway");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetTldServiceState_emptyBody_throwsMosApiException() throws Exception {
|
||||
Response response =
|
||||
new Response.Builder()
|
||||
.request(new Request.Builder().url("http://localhost").build())
|
||||
.protocol(Protocol.HTTP_1_1)
|
||||
.code(204)
|
||||
.message("No Content")
|
||||
.build();
|
||||
|
||||
when(mosApiClient.sendGetRequest(eq(TLD), eq(ENDPOINT), anyMap(), anyMap()))
|
||||
.thenReturn(response);
|
||||
|
||||
MosApiException thrown =
|
||||
assertThrows(MosApiException.class, () -> client.getTldServiceState(TLD));
|
||||
assertThat(thrown.getMessage()).contains("returned an empty body");
|
||||
}
|
||||
|
||||
private Response createMockResponse(int code, String body) {
|
||||
return new Response.Builder()
|
||||
.request(new Request.Builder().url("http://localhost").build())
|
||||
.protocol(Protocol.HTTP_1_1)
|
||||
.code(code)
|
||||
.message(code == 200 ? "OK" : "Error")
|
||||
.body(ResponseBody.create(body, MediaType.parse("application/json")))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2026 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.mosapi;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.request.HttpException.InternalServerErrorException;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/** Unit tests for {@link TriggerServiceStateActionTest}. */
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class TriggerServiceStateActionTest {
|
||||
|
||||
private final MosApiStateService stateService = mock(MosApiStateService.class);
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
private TriggerServiceStateAction action;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
action = new TriggerServiceStateAction(stateService, response);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_success() {
|
||||
action.run();
|
||||
|
||||
verify(stateService).triggerMetricsForAllServiceStateSummaries();
|
||||
|
||||
assertThat(response.getContentType()).isEqualTo(MediaType.PLAIN_TEXT_UTF_8);
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo("MoSAPI metrics triggered successfully for all TLDs.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRun_failure_throwsInternalServerError() {
|
||||
doThrow(new RuntimeException("Database error"))
|
||||
.when(stateService)
|
||||
.triggerMetricsForAllServiceStateSummaries();
|
||||
|
||||
InternalServerErrorException thrown =
|
||||
assertThrows(InternalServerErrorException.class, () -> action.run());
|
||||
|
||||
assertThat(thrown.getMessage()).contains("Failed to process MoSAPI metrics.");
|
||||
|
||||
assertThat(response.getContentType()).isEqualTo(MediaType.PLAIN_TEXT_UTF_8);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright 2025 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.mosapi.module;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link MosApiRequestModule}. */
|
||||
public class MosApiRequestModuleTest {
|
||||
|
||||
@Test
|
||||
void testProvideTld_paramPresent() {
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
when(req.getParameter("tld")).thenReturn("example.tld");
|
||||
|
||||
Optional<String> result = MosApiRequestModule.provideTld(req);
|
||||
|
||||
assertThat(result).hasValue("example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProvideTld_paramMissing() {
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
when(req.getParameter("tld")).thenReturn(null);
|
||||
|
||||
Optional<String> result = MosApiRequestModule.provideTld(req);
|
||||
|
||||
assertThat(result).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProvideTld_paramEmptyString() {
|
||||
HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
when(req.getParameter("tld")).thenReturn("");
|
||||
|
||||
Optional<String> result = MosApiRequestModule.provideTld(req);
|
||||
|
||||
assertThat(result).isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="0">example1.tld</domain:name>
|
||||
<domain:reason>In use</domain:reason>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="1">example2.tld</domain:name>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="1">example3.tld</domain:name>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">13.00</fee:fee>
|
||||
<fee:fee description="Early Access Period, fee expires: 2010-01-02T10:00:00.002Z">100.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example2.tld</fee:objID>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">13.00</fee:fee>
|
||||
<fee:fee description="Early Access Period, fee expires: 2010-01-02T10:00:00.002Z">100.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example3.tld</fee:objID>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">13.00</fee:fee>
|
||||
<fee:fee description="Early Access Period, fee expires: 2010-01-02T10:00:00.002Z">100.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -0,0 +1,17 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example1.tld</domain:name>
|
||||
</domain:check>
|
||||
</check>
|
||||
<extension>
|
||||
<fee:check xmlns:fee="urn:ietf:params:xml:ns:fee-0.12">
|
||||
<fee:command name="Create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
</fee:check>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
@@ -0,0 +1,58 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="1">example1.tld</domain:name>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">11.70</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="update">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="update">0.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -0,0 +1,24 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example1.tld</domain:name>
|
||||
</domain:check>
|
||||
</check>
|
||||
<extension>
|
||||
<allocationToken:allocationToken
|
||||
xmlns:allocationToken=
|
||||
"urn:ietf:params:xml:ns:allocationToken-1.0">
|
||||
abc123
|
||||
</allocationToken:allocationToken>
|
||||
<fee:check xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:command name="create" />
|
||||
<fee:command name="renew" />
|
||||
<fee:command name="transfer" />
|
||||
<fee:command name="restore" />
|
||||
<fee:command name="update" />
|
||||
</fee:check>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
@@ -0,0 +1,58 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="1">example1.tld</domain:name>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">6.50</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="update">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="update">0.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -0,0 +1,58 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="1">example1.tld</domain:name>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">13.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="update">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="update">0.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -0,0 +1,19 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example1.tld</domain:name>
|
||||
</domain:check>
|
||||
</check>
|
||||
<extension>
|
||||
<fee:check xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:command name="create" />
|
||||
<fee:command name="renew" />
|
||||
<fee:command name="transfer" />
|
||||
<fee:command name="restore" />
|
||||
<fee:command name="update" />
|
||||
</fee:check>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
@@ -0,0 +1,45 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="true">example.example</domain:name>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="true">example.tld</domain:name>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:fee-0.12"
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<fee:cd>
|
||||
<fee:object>
|
||||
<domain:name>example.example</domain:name>
|
||||
</fee:object>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">800</fee:fee>
|
||||
<fee:fee description="Early Access Period, fee expires: 294247-01-10T04:00:54.775Z">800</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:object>
|
||||
<domain:name>example.tld</domain:name>
|
||||
</fee:object>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">13.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -0,0 +1,18 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.tld</domain:name>
|
||||
<domain:name>example.example</domain:name>
|
||||
</domain:check>
|
||||
</check>
|
||||
<extension>
|
||||
<fee:check xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
</fee:check>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
@@ -0,0 +1,16 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.example</domain:name>
|
||||
<domain:name>example.tld</domain:name>
|
||||
</domain:check>
|
||||
</check>
|
||||
<extension>
|
||||
<fee:check xmlns:fee="urn:ietf:params:xml:ns:fee-0.12">
|
||||
<fee:command name="create" />
|
||||
</fee:check>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
@@ -0,0 +1,61 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="1">rich.example</domain:name>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:cd>
|
||||
<fee:objID>rich.example</fee:objID>
|
||||
<fee:class>premium</fee:class>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">100.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>rich.example</fee:objID>
|
||||
<fee:class>premium</fee:class>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">100.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>rich.example</fee:objID>
|
||||
<fee:class>premium</fee:class>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">100.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>rich.example</fee:objID>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>rich.example</fee:objID>
|
||||
<fee:command name="update">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="update">0.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -0,0 +1,31 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="false">rich.example</domain:name>
|
||||
<domain:reason>In use</domain:reason>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:cd>
|
||||
<fee:objID>rich.example</fee:objID>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">%RENEWPRICE%</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -0,0 +1,64 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="false">rich.example</domain:name>
|
||||
<domain:reason>In use</domain:reason>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:cd>
|
||||
<fee:objID>rich.example</fee:objID>
|
||||
<fee:class>premium</fee:class>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">100.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>rich.example</fee:objID>
|
||||
<fee:class>premium</fee:class>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">100.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>rich.example</fee:objID>
|
||||
<fee:class>premium</fee:class>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">100.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>rich.example</fee:objID>
|
||||
<fee:class>premium</fee:class>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">100.00</fee:fee>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>rich.example</fee:objID>
|
||||
<fee:command name="update">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="update">0.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -1,4 +1,4 @@
|
||||
domain_check_fee_premium_response_v12.xml<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
domain_check_fee_premium_response_v12.xml<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
domain_check_fee_premium_response_v12.xml<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>rich.example</domain:name>
|
||||
</domain:check>
|
||||
</check>
|
||||
<extension>
|
||||
<fee:check xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:command name="create" />
|
||||
<fee:command name="renew" />
|
||||
<fee:command name="transfer" />
|
||||
<fee:command name="restore" />
|
||||
<fee:command name="update" />
|
||||
</fee:check>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
@@ -0,0 +1,15 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>rich.example</domain:name>
|
||||
</domain:check>
|
||||
</check>
|
||||
<extension>
|
||||
<fee:check xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:command name="renew" />
|
||||
</fee:check>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
@@ -0,0 +1,122 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="0">reserved.tld</domain:name>
|
||||
<domain:reason>Reserved</domain:reason>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="0">allowedinsunrise.tld</domain:name>
|
||||
<domain:reason>In use</domain:reason>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="0">allowedinsunrise.tld</domain:name>
|
||||
<domain:reason>In use</domain:reason>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="0">premiumcollision.tld</domain:name>
|
||||
<domain:reason>Cannot be delegated</domain:reason>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:cd>
|
||||
<fee:objID>reserved.tld</fee:objID>
|
||||
<fee:class>reserved</fee:class>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>reserved.tld</fee:objID>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>reserved.tld</fee:objID>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>reserved.tld</fee:objID>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>allowedinsunrise.tld</fee:objID>
|
||||
<fee:class>reserved</fee:class>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>allowedinsunrise.tld</fee:objID>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>allowedinsunrise.tld</fee:objID>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>allowedinsunrise.tld</fee:objID>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>premiumcollision.tld</fee:objID>
|
||||
<fee:class>reserved</fee:class>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>premiumcollision.tld</fee:objID>
|
||||
<fee:class>premium</fee:class>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">70.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>premiumcollision.tld</fee:objID>
|
||||
<fee:class>premium</fee:class>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">70.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>premiumcollision.tld</fee:objID>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -0,0 +1,33 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>reserved.tld</domain:name>
|
||||
<domain:name>allowedinsunrise.tld</domain:name>
|
||||
<domain:name>allowedinsunrise.tld</domain:name>
|
||||
<domain:name>premiumcollision.tld</domain:name>
|
||||
</domain:check>
|
||||
</check>
|
||||
<extension>
|
||||
<launch:check xmlns:launch="urn:ietf:params:xml:ns:launch-1.0" type="avail">
|
||||
<launch:phase name="foo">custom</launch:phase>
|
||||
</launch:check>
|
||||
<fee:check xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
</fee:check>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
@@ -0,0 +1,150 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="0">reserved.tld</domain:name>
|
||||
<domain:reason>Reserved</domain:reason>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="0">allowedinsunrise.tld</domain:name>
|
||||
<domain:reason>Reserved</domain:reason>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="0">collision.tld</domain:name>
|
||||
<domain:reason>Cannot be delegated</domain:reason>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="0">premiumcollision.tld</domain:name>
|
||||
<domain:reason>Cannot be delegated</domain:reason>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:cd>
|
||||
<fee:objID>reserved.tld</fee:objID>
|
||||
<fee:class>reserved</fee:class>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>reserved.tld</fee:objID>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>reserved.tld</fee:objID>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>reserved.tld</fee:objID>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>allowedinsunrise.tld</fee:objID>
|
||||
<fee:class>reserved</fee:class>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>allowedinsunrise.tld</fee:objID>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>allowedinsunrise.tld</fee:objID>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>allowedinsunrise.tld</fee:objID>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>collision.tld</fee:objID>
|
||||
<fee:class>reserved</fee:class>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>collision.tld</fee:objID>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>collision.tld</fee:objID>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>collision.tld</fee:objID>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>premiumcollision.tld</fee:objID>
|
||||
<fee:class>reserved</fee:class>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>premiumcollision.tld</fee:objID>
|
||||
<fee:class>premium</fee:class>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">70.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>premiumcollision.tld</fee:objID>
|
||||
<fee:class>premium</fee:class>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">70.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>premiumcollision.tld</fee:objID>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -64,8 +64,8 @@
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">70.00</fee:fee>
|
||||
<fee:class>premium</fee:class>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
<fee:class>premium</fee:class>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>reserved.tld</domain:name>
|
||||
<domain:name>allowedinsunrise.tld</domain:name>
|
||||
<domain:name>collision.tld</domain:name>
|
||||
<domain:name>premiumcollision.tld</domain:name>
|
||||
</domain:check>
|
||||
</check>
|
||||
<extension>
|
||||
<launch:check xmlns:launch="urn:ietf:params:xml:ns:launch-1.0" type="avail">
|
||||
<launch:phase name="foo">custom</launch:phase>
|
||||
</launch:check>
|
||||
<fee:check xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
</fee:check>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
@@ -0,0 +1,153 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="0">reserved.tld</domain:name>
|
||||
<domain:reason>Reserved</domain:reason>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="1">allowedinsunrise.tld</domain:name>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="1">collision.tld</domain:name>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="1">premiumcollision.tld</domain:name>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:cd>
|
||||
<fee:objID>reserved.tld</fee:objID>
|
||||
<fee:class>reserved</fee:class>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>reserved.tld</fee:objID>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>reserved.tld</fee:objID>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>reserved.tld</fee:objID>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>allowedinsunrise.tld</fee:objID>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">11.05</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>allowedinsunrise.tld</fee:objID>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>allowedinsunrise.tld</fee:objID>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>allowedinsunrise.tld</fee:objID>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>collision.tld</fee:objID>
|
||||
<fee:class>collision</fee:class>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">11.05</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>collision.tld</fee:objID>
|
||||
<fee:class>collision</fee:class>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>collision.tld</fee:objID>
|
||||
<fee:class>collision</fee:class>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">11.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>collision.tld</fee:objID>
|
||||
<fee:class>collision</fee:class>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>premiumcollision.tld</fee:objID>
|
||||
<fee:class>premium-collision</fee:class>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">59.50</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>premiumcollision.tld</fee:objID>
|
||||
<fee:class>premium-collision</fee:class>
|
||||
<fee:command name="renew">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">70.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>premiumcollision.tld</fee:objID>
|
||||
<fee:class>premium-collision</fee:class>
|
||||
<fee:command name="transfer">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="renew">70.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>premiumcollision.tld</fee:objID>
|
||||
<fee:class>collision</fee:class>
|
||||
<fee:command name="restore">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="restore">17.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -0,0 +1,51 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="0">example1.tld</domain:name>
|
||||
<domain:reason>In use</domain:reason>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="1">example2.tld</domain:name>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="1">example3.tld</domain:name>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">6.50</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example2.tld</fee:objID>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">6.50</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example3.tld</fee:objID>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">6.50</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -0,0 +1,51 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<domain:chkData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:cd>
|
||||
<domain:name avail="0">example1.tld</domain:name>
|
||||
<domain:reason>In use</domain:reason>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="1">example2.tld</domain:name>
|
||||
</domain:cd>
|
||||
<domain:cd>
|
||||
<domain:name avail="1">example3.tld</domain:name>
|
||||
</domain:cd>
|
||||
</domain:chkData>
|
||||
</resData>
|
||||
<extension>
|
||||
<fee:chkData xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:cd>
|
||||
<fee:objID>example1.tld</fee:objID>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">13.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example2.tld</fee:objID>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">13.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
<fee:cd>
|
||||
<fee:objID>example3.tld</fee:objID>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
<fee:fee description="create">13.00</fee:fee>
|
||||
</fee:command>
|
||||
</fee:cd>
|
||||
</fee:chkData>
|
||||
</extension>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
||||
@@ -0,0 +1,24 @@
|
||||
<!-- From domain_check_fee_v12.xml, removed `fee:class` line -->
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example1.tld</domain:name>
|
||||
<domain:name>example2.tld</domain:name>
|
||||
<domain:name>example3.tld</domain:name>
|
||||
</domain:check>
|
||||
</check>
|
||||
<extension>
|
||||
<launch:check xmlns:launch="urn:ietf:params:xml:ns:launch-1.0" type="avail">
|
||||
<launch:phase name="foo">custom</launch:phase>
|
||||
</launch:check>
|
||||
<fee:check xmlns:fee="urn:ietf:params:xml:ns:epp:fee-1.0">
|
||||
<fee:currency>USD</fee:currency>
|
||||
<fee:command name="create">
|
||||
<fee:period unit="y">1</fee:period>
|
||||
</fee:command>
|
||||
</fee:check>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
@@ -1,4 +1,4 @@
|
||||
<epp xmlns:domain="urn:ietf:params:xml:ns:domain-1.0" xmlns:contact="urn:ietf:params:xml:ns:contact-1.0" xmlns:fee="urn:ietf:params:xml:ns:fee-0.6" xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0" xmlns:bulkToken="urn:google:params:xml:ns:bulkToken-1.0" xmlns:fee11="urn:ietf:params:xml:ns:fee-0.11" xmlns:fee="urn:ietf:params:xml:ns:fee-0.12" xmlns:launch="urn:ietf:params:xml:ns:launch-1.0" xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1" xmlns:host="urn:ietf:params:xml:ns:host-1.0">
|
||||
<epp xmlns:domain="urn:ietf:params:xml:ns:domain-1.0" xmlns:contact="urn:ietf:params:xml:ns:contact-1.0" xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0" xmlns:bulkToken="urn:google:params:xml:ns:bulkToken-1.0" xmlns:fee="urn:ietf:params:xml:ns:fee-0.12" xmlns:launch="urn:ietf:params:xml:ns:launch-1.0" xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1" xmlns:host="urn:ietf:params:xml:ns:host-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<domain:ns>
|
||||
<domain:hostObj>ns1.example.foo</domain:hostObj>
|
||||
</domain:ns>
|
||||
<domain:status s="clientUpdateProhibited"/>
|
||||
</domain:rem>
|
||||
<domain:chg>
|
||||
<domain:authInfo>
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
<domain:hostObj>ns1.example.foo</domain:hostObj>
|
||||
</domain:ns>
|
||||
<domain:contact type="tech">sh8013</domain:contact>
|
||||
<domain:status s="clientUpdateProhibited"/>
|
||||
</domain:rem>
|
||||
<domain:chg>
|
||||
<domain:registrant/>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<domain:ns>
|
||||
<domain:hostObj>ns1.example.foo</domain:hostObj>
|
||||
</domain:ns>
|
||||
<domain:status s="clientUpdateProhibited"/>
|
||||
</domain:rem>
|
||||
</domain:update>
|
||||
</update>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<domain:ns>
|
||||
<domain:hostObj>ns1.example.foo</domain:hostObj>
|
||||
</domain:ns>
|
||||
<domain:status s="clientUpdateProhibited"/>
|
||||
</domain:rem>
|
||||
<domain:chg>
|
||||
<domain:authInfo>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<domain:ns>
|
||||
<domain:hostObj>ns1.example.foo</domain:hostObj>
|
||||
</domain:ns>
|
||||
<domain:status s="clientUpdateProhibited"/>
|
||||
</domain:rem>
|
||||
<domain:chg>
|
||||
<domain:authInfo>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<update>
|
||||
<domain:update
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.tld</domain:name>
|
||||
<domain:add />
|
||||
<domain:rem>
|
||||
<domain:status s="clientUpdateProhibited"/>
|
||||
</domain:rem>
|
||||
<domain:chg />
|
||||
</domain:update>
|
||||
</update>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
@@ -15,7 +15,6 @@
|
||||
<domain:ns>
|
||||
<domain:hostObj>ns1.example.foo</domain:hostObj>
|
||||
</domain:ns>
|
||||
<domain:status s="clientUpdateProhibited"/>
|
||||
</domain:rem>
|
||||
<domain:chg>
|
||||
<domain:authInfo>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<secDNS:keyTag>12346</secDNS:keyTag>
|
||||
<secDNS:alg>3</secDNS:alg>
|
||||
<secDNS:digestType>1</secDNS:digestType>
|
||||
<secDNS:digest>38EC35D5B3A34B44C39B</secDNS:digest>
|
||||
<secDNS:digest>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</secDNS:digest>
|
||||
</secDNS:dsData>
|
||||
</secDNS:rem>
|
||||
</secDNS:update>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<version>1.0</version>
|
||||
<lang>en</lang>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<svcExtension>
|
||||
<extURI>urn:ietf:params:xml:ns:launch-1.0</extURI>
|
||||
@@ -15,6 +14,7 @@
|
||||
<extURI>urn:ietf:params:xml:ns:fee-0.6</extURI>
|
||||
<extURI>urn:ietf:params:xml:ns:fee-0.11</extURI>
|
||||
<extURI>urn:ietf:params:xml:ns:fee-0.12</extURI>
|
||||
<extURI>urn:ietf:params:xml:ns:epp:fee-1.0</extURI>
|
||||
</svcExtension>
|
||||
</svcMenu>
|
||||
<dcp>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<svcs>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
<svcExtension>
|
||||
<extURI>urn:ietf:params:xml:ns:launch-1.0</extURI>
|
||||
<extURI>urn:ietf:params:xml:ns:rgp-1.0</extURI>
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<svcs>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
<svcExtension>
|
||||
<extURI>urn:ietf:params:xml:ns:launch-1.0</extURI>
|
||||
<extURI>urn:ietf:params:xml:ns:rgp-1.0</extURI>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<svcs>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
<svcExtension>
|
||||
<extURI>urn:ietf:params:xml:ns:launch-1.0</extURI>
|
||||
<extURI>urn:ietf:params:xml:ns:rgp-1.0</extURI>
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<svcs>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
<svcExtension>
|
||||
<extURI>urn:ietf:params:xml:ns:launch-1.0</extURI>
|
||||
<extURI>urn:ietf:params:xml:ns:rgp-1.0</extURI>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<version>1.0</version>
|
||||
<lang>en</lang>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<svcExtension>
|
||||
<extURI>urn:ietf:params:xml:ns:launch-1.0</extURI>
|
||||
@@ -15,6 +14,7 @@
|
||||
<extURI>urn:ietf:params:xml:ns:fee-0.6</extURI>
|
||||
<extURI>urn:ietf:params:xml:ns:fee-0.11</extURI>
|
||||
<extURI>urn:ietf:params:xml:ns:fee-0.12</extURI>
|
||||
<extURI>urn:ietf:params:xml:ns:epp:fee-1.0</extURI>
|
||||
</svcExtension>
|
||||
</svcMenu>
|
||||
<dcp>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<svcs>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
<svcExtension>
|
||||
<extURI>http://custom/obj1ext-1.0</extURI>
|
||||
</svcExtension>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<svcs>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
</svcs>
|
||||
</login>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<svcs>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:foo-1.0</objURI>
|
||||
</svcs>
|
||||
</login>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<svcs>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
</svcs>
|
||||
</login>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<svcs>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
</svcs>
|
||||
</login>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<svcs>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
</svcs>
|
||||
</login>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
|
||||
@@ -12,7 +12,6 @@ xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
|
||||
</options>
|
||||
<svcs>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<svcExtension>
|
||||
<extURI>urn:ietf:params:xml:ns:secDNS-1.1</extURI>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<svcs>
|
||||
<objURI>urn:ietf:params:xml:ns:host-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:domain-1.0</objURI>
|
||||
<objURI>urn:ietf:params:xml:ns:contact-1.0</objURI>
|
||||
<svcExtension>
|
||||
<extURI>urn:ietf:params:xml:ns:launch-1.0</extURI>
|
||||
<extURI>urn:ietf:params:xml:ns:rgp-1.0</extURI>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user