Fix exDate calculation in domain transfer flows (#389)

* Fix exDate calculation in domain transfer flows

* Link ICANN rule for zero-period transfer

* Get rid of some unnecessary method parameters

* Add domain info commands to test case
This commit is contained in:
sarahcaseybot 2020-01-15 16:43:39 -05:00 committed by GitHub
parent d28debf149
commit 1a0dd0e47b
29 changed files with 725 additions and 315 deletions

View file

@ -42,6 +42,8 @@ import google.registry.model.EppResource.ForeignKeyedEppResource;
import google.registry.model.EppResource.ResourceWithTransferData; import google.registry.model.EppResource.ResourceWithTransferData;
import google.registry.model.contact.ContactResource; import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DomainBase; import google.registry.model.domain.DomainBase;
import google.registry.model.domain.Period;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.eppcommon.AuthInfo; import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
import google.registry.model.index.ForeignKeyIndex; import google.registry.model.index.ForeignKeyIndex;
@ -247,6 +249,30 @@ public final class ResourceFlowUtils {
} }
} }
/**
* Computes the exDate for the domain at the given transfer approval time with an adjusted amount
* of transfer period years if the domain is in the auto renew grace period at the time of
* approval.
*
* @param domain is the domain already projected at approvalTime
*/
public static DateTime computeExDateForApprovalTime(
DomainBase domain, DateTime approvalTime, Period period) {
boolean inAutoRenew = domain.getGracePeriodStatuses().contains(GracePeriodStatus.AUTO_RENEW);
// inAutoRenew is set to false if the period is zero because a zero-period transfer should not
// subsume an autorenew.
// https://www.icann.org/resources/unthemed-pages/appendix-07-2010-01-06-en section 3.1.2
// specifies that when a transfer occurs without a change to the expiration date, the losing
// registrar's account should still be charged for the autorenew.
if (period.getValue() == 0) {
inAutoRenew = false;
}
return DomainBase.extendRegistrationWithCap(
approvalTime,
domain.getRegistrationExpirationTime(),
period.getValue() - (inAutoRenew ? 1 : 0));
}
/** Resource with this id does not exist. */ /** Resource with this id does not exist. */
public static class ResourceDoesNotExistException extends ObjectDoesNotExistException { public static class ResourceDoesNotExistException extends ObjectDoesNotExistException {
public ResourceDoesNotExistException(Class<?> type, String targetId) { public ResourceDoesNotExistException(Class<?> type, String targetId) {

View file

@ -16,6 +16,7 @@ package google.registry.flows.domain;
import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.collect.Iterables.getOnlyElement;
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn; import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.computeExDateForApprovalTime;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence; import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyHasPendingTransfer; import static google.registry.flows.ResourceFlowUtils.verifyHasPendingTransfer;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo;
@ -26,7 +27,6 @@ import static google.registry.flows.domain.DomainFlowUtils.updateAutorenewRecurr
import static google.registry.flows.domain.DomainTransferUtils.createGainingTransferPollMessage; import static google.registry.flows.domain.DomainTransferUtils.createGainingTransferPollMessage;
import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse; import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse;
import static google.registry.model.ResourceTransferUtils.approvePendingTransfer; import static google.registry.model.ResourceTransferUtils.approvePendingTransfer;
import static google.registry.model.domain.DomainBase.extendRegistrationWithCap;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL; import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL;
import static google.registry.model.transaction.TransactionManagerFactory.tm; import static google.registry.model.transaction.TransactionManagerFactory.tm;
@ -136,9 +136,7 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
// increase the registration time, since the transfer subsumes the autorenew's extra year. // increase the registration time, since the transfer subsumes the autorenew's extra year.
GracePeriod autorenewGrace = GracePeriod autorenewGrace =
getOnlyElement(existingDomain.getGracePeriodsOfType(GracePeriodStatus.AUTO_RENEW), null); getOnlyElement(existingDomain.getGracePeriodsOfType(GracePeriodStatus.AUTO_RENEW), null);
int extraYears = transferData.getTransferPeriod().getValue();
if (autorenewGrace != null) { if (autorenewGrace != null) {
extraYears = 0;
// During a normal transfer, if the domain is in the auto-renew grace period, the auto-renew // During a normal transfer, if the domain is in the auto-renew grace period, the auto-renew
// billing event is cancelled and the gaining registrar is charged for the one year renewal. // billing event is cancelled and the gaining registrar is charged for the one year renewal.
// But, if the superuser extension is used to request a transfer without an additional year // But, if the superuser extension is used to request a transfer without an additional year
@ -152,8 +150,8 @@ public final class DomainTransferApproveFlow implements TransactionalFlow {
// Close the old autorenew event and poll message at the transfer time (aka now). This may end // Close the old autorenew event and poll message at the transfer time (aka now). This may end
// up deleting the poll message. // up deleting the poll message.
updateAutorenewRecurrenceEndTime(existingDomain, now); updateAutorenewRecurrenceEndTime(existingDomain, now);
DateTime newExpirationTime = extendRegistrationWithCap( DateTime newExpirationTime =
now, existingDomain.getRegistrationExpirationTime(), extraYears); computeExDateForApprovalTime(existingDomain, now, transferData.getTransferPeriod());
// Create a new autorenew event starting at the expiration time. // Create a new autorenew event starting at the expiration time.
BillingEvent.Recurring autorenewEvent = new BillingEvent.Recurring.Builder() BillingEvent.Recurring autorenewEvent = new BillingEvent.Recurring.Builder()
.setReason(Reason.RENEW) .setReason(Reason.RENEW)

View file

@ -18,13 +18,13 @@ import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence; import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo;
import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse; import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse;
import static google.registry.model.domain.DomainBase.extendRegistrationWithCap;
import google.registry.flows.EppException; import google.registry.flows.EppException;
import google.registry.flows.ExtensionManager; import google.registry.flows.ExtensionManager;
import google.registry.flows.Flow; import google.registry.flows.Flow;
import google.registry.flows.FlowModule.ClientId; import google.registry.flows.FlowModule.ClientId;
import google.registry.flows.FlowModule.TargetId; import google.registry.flows.FlowModule.TargetId;
import google.registry.flows.ResourceFlowUtils;
import google.registry.flows.annotations.ReportingSpec; import google.registry.flows.annotations.ReportingSpec;
import google.registry.flows.exceptions.NoTransferHistoryToQueryException; import google.registry.flows.exceptions.NoTransferHistoryToQueryException;
import google.registry.flows.exceptions.NotAuthorizedToViewTransferException; import google.registry.flows.exceptions.NotAuthorizedToViewTransferException;
@ -86,10 +86,12 @@ public final class DomainTransferQueryFlow implements Flow {
throw new NotAuthorizedToViewTransferException(); throw new NotAuthorizedToViewTransferException();
} }
DateTime newExpirationTime = null; DateTime newExpirationTime = null;
if (transferData.getTransferStatus().isApproved() if (transferData.getTransferStatus().isApproved()) {
|| transferData.getTransferStatus().equals(TransferStatus.PENDING)) { newExpirationTime = transferData.getTransferredRegistrationExpirationTime();
// TODO(b/25084229): fix exDate computation logic. } else if (transferData.getTransferStatus().equals(TransferStatus.PENDING)) {
newExpirationTime = extendRegistrationWithCap(now, domain.getRegistrationExpirationTime(), 1); newExpirationTime =
ResourceFlowUtils.computeExDateForApprovalTime(
domain, now, domain.getTransferData().getTransferPeriod());
} }
return responseBuilder return responseBuilder
.setResData(createTransferResponse(targetId, transferData, newExpirationTime)) .setResData(createTransferResponse(targetId, transferData, newExpirationTime))

View file

@ -15,6 +15,7 @@
package google.registry.flows.domain; package google.registry.flows.domain;
import static google.registry.flows.FlowUtils.validateClientIsLoggedIn; import static google.registry.flows.FlowUtils.validateClientIsLoggedIn;
import static google.registry.flows.ResourceFlowUtils.computeExDateForApprovalTime;
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence; import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
import static google.registry.flows.ResourceFlowUtils.verifyAuthInfo; import static google.registry.flows.ResourceFlowUtils.verifyAuthInfo;
import static google.registry.flows.ResourceFlowUtils.verifyAuthInfoPresentForResourceTransfer; import static google.registry.flows.ResourceFlowUtils.verifyAuthInfoPresentForResourceTransfer;
@ -29,7 +30,6 @@ import static google.registry.flows.domain.DomainTransferUtils.createLosingTrans
import static google.registry.flows.domain.DomainTransferUtils.createPendingTransferData; import static google.registry.flows.domain.DomainTransferUtils.createPendingTransferData;
import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse; import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse;
import static google.registry.flows.domain.DomainTransferUtils.createTransferServerApproveEntities; import static google.registry.flows.domain.DomainTransferUtils.createTransferServerApproveEntities;
import static google.registry.model.domain.DomainBase.extendRegistrationWithCap;
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING; import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.transaction.TransactionManagerFactory.tm; import static google.registry.model.transaction.TransactionManagerFactory.tm;
@ -56,7 +56,6 @@ import google.registry.model.domain.Period;
import google.registry.model.domain.fee.FeeTransferCommandExtension; import google.registry.model.domain.fee.FeeTransferCommandExtension;
import google.registry.model.domain.fee.FeeTransformResponseExtension; import google.registry.model.domain.fee.FeeTransformResponseExtension;
import google.registry.model.domain.metadata.MetadataExtension; import google.registry.model.domain.metadata.MetadataExtension;
import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.domain.superuser.DomainTransferRequestSuperuserExtension; import google.registry.model.domain.superuser.DomainTransferRequestSuperuserExtension;
import google.registry.model.eppcommon.AuthInfo; import google.registry.model.eppcommon.AuthInfo;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
@ -183,18 +182,10 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
// //
// See b/19430703#comment17 and https://www.icann.org/news/advisory-2002-06-06-en for the // See b/19430703#comment17 and https://www.icann.org/news/advisory-2002-06-06-en for the
// policy documentation for transfers subsuming autorenews within the autorenew grace period. // policy documentation for transfers subsuming autorenews within the autorenew grace period.
int extraYears = period.getValue(); DomainBase domainAtTransferTime = existingDomain.cloneProjectedAtTime(automaticTransferTime);
DomainBase domainAtTransferTime =
existingDomain.cloneProjectedAtTime(automaticTransferTime);
if (!domainAtTransferTime.getGracePeriodsOfType(GracePeriodStatus.AUTO_RENEW).isEmpty()) {
extraYears = 0;
}
// The new expiration time if there is a server approval. // The new expiration time if there is a server approval.
DateTime serverApproveNewExpirationTime = DateTime serverApproveNewExpirationTime =
extendRegistrationWithCap( computeExDateForApprovalTime(domainAtTransferTime, automaticTransferTime, period);
automaticTransferTime,
domainAtTransferTime.getRegistrationExpirationTime(),
extraYears);
// Create speculative entities in anticipation of an automatic server approval. // Create speculative entities in anticipation of an automatic server approval.
ImmutableSet<TransferServerApproveEntity> serverApproveEntities = ImmutableSet<TransferServerApproveEntity> serverApproveEntities =
createTransferServerApproveEntities( createTransferServerApproveEntities(
@ -337,10 +328,8 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
// If the registration were approved this instant, this is what the new expiration would be, // If the registration were approved this instant, this is what the new expiration would be,
// because we cap at 10 years from the moment of approval. This is different than the server // because we cap at 10 years from the moment of approval. This is different than the server
// approval new expiration time, which is capped at 10 years from the server approve time. // approval new expiration time, which is capped at 10 years from the server approve time.
DateTime approveNowExtendedRegistrationTime = extendRegistrationWithCap( DateTime approveNowExtendedRegistrationTime =
now, computeExDateForApprovalTime(existingDomain, now, period);
existingDomain.getRegistrationExpirationTime(),
period.getValue());
return createTransferResponse( return createTransferResponse(
targetId, newDomain.getTransferData(), approveNowExtendedRegistrationTime); targetId, newDomain.getTransferData(), approveNowExtendedRegistrationTime);
} }

View file

@ -17,7 +17,6 @@ package google.registry.model;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static google.registry.model.domain.DomainBase.extendRegistrationWithCap;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -53,24 +52,22 @@ public final class ResourceTransferUtils {
TransferStatus.PENDING, TransferStatus.CLIENT_APPROVED, TransferStatus.SERVER_APPROVED); TransferStatus.PENDING, TransferStatus.CLIENT_APPROVED, TransferStatus.SERVER_APPROVED);
/** /**
* Create a transfer response using the id and type of this resource and the specified * Create a transfer response using the id and type of this resource and the specified {@link
* {@link TransferData}. * TransferData}.
*/ */
public static TransferResponse createTransferResponse( public static TransferResponse createTransferResponse(
EppResource eppResource, TransferData transferData, DateTime now) { EppResource eppResource, TransferData transferData) {
assertIsContactOrDomain(eppResource); assertIsContactOrDomain(eppResource);
TransferResponse.Builder<? extends TransferResponse, ?> builder; TransferResponse.Builder<? extends TransferResponse, ?> builder;
if (eppResource instanceof ContactResource) { if (eppResource instanceof ContactResource) {
builder = new ContactTransferResponse.Builder().setContactId(eppResource.getForeignKey()); builder = new ContactTransferResponse.Builder().setContactId(eppResource.getForeignKey());
} else { } else {
DomainBase domain = (DomainBase) eppResource;
builder = builder =
new DomainTransferResponse.Builder() new DomainTransferResponse.Builder()
.setFullyQualifiedDomainName(eppResource.getForeignKey()) .setFullyQualifiedDomainName(eppResource.getForeignKey())
// TODO(b/25084229): fix exDate computation logic.
.setExtendedRegistrationExpirationTime( .setExtendedRegistrationExpirationTime(
ADD_EXDATE_STATUSES.contains(transferData.getTransferStatus()) ADD_EXDATE_STATUSES.contains(transferData.getTransferStatus())
? extendRegistrationWithCap(now, domain.getRegistrationExpirationTime(), 1) ? transferData.getTransferredRegistrationExpirationTime()
: null); : null);
} }
builder.setGainingClientId(transferData.getGainingClientId()) builder.setGainingClientId(transferData.getGainingClientId())
@ -118,16 +115,20 @@ public final class ResourceTransferUtils {
if (resource.getStatusValues().contains(StatusValue.PENDING_TRANSFER)) { if (resource.getStatusValues().contains(StatusValue.PENDING_TRANSFER)) {
TransferData oldTransferData = resource.getTransferData(); TransferData oldTransferData = resource.getTransferData();
ofy().delete().keys(oldTransferData.getServerApproveEntities()); ofy().delete().keys(oldTransferData.getServerApproveEntities());
ofy().save().entity(new PollMessage.OneTime.Builder() ofy()
.setClientId(oldTransferData.getGainingClientId()) .save()
.setEventTime(now) .entity(
.setMsg(TransferStatus.SERVER_CANCELLED.getMessage()) new PollMessage.OneTime.Builder()
.setResponseData(ImmutableList.of( .setClientId(oldTransferData.getGainingClientId())
createTransferResponse(newResource, newResource.getTransferData(), now), .setEventTime(now)
createPendingTransferNotificationResponse( .setMsg(TransferStatus.SERVER_CANCELLED.getMessage())
resource, oldTransferData.getTransferRequestTrid(), false, now))) .setResponseData(
.setParent(historyEntry) ImmutableList.of(
.build()); createTransferResponse(newResource, newResource.getTransferData()),
createPendingTransferNotificationResponse(
resource, oldTransferData.getTransferRequestTrid(), false, now)))
.setParent(historyEntry)
.build());
} }
} }

View file

@ -45,6 +45,7 @@ import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.IgnoreSave; import com.googlecode.objectify.annotation.IgnoreSave;
import com.googlecode.objectify.annotation.Index; import com.googlecode.objectify.annotation.Index;
import com.googlecode.objectify.condition.IfNull; import com.googlecode.objectify.condition.IfNull;
import google.registry.flows.ResourceFlowUtils;
import google.registry.model.EppResource; import google.registry.model.EppResource;
import google.registry.model.EppResource.ForeignKeyedEppResource; import google.registry.model.EppResource.ForeignKeyedEppResource;
import google.registry.model.EppResource.ResourceWithTransferData; import google.registry.model.EppResource.ResourceWithTransferData;
@ -377,28 +378,31 @@ public class DomainBase extends EppResource
// exclusive of their ending), and we can just proceed with the transfer. // exclusive of their ending), and we can just proceed with the transfer.
DomainBase domainAtTransferTime = DomainBase domainAtTransferTime =
cloneProjectedAtTime(transferExpirationTime.minusMillis(1)); cloneProjectedAtTime(transferExpirationTime.minusMillis(1));
DateTime expirationDate = transferData.getTransferredRegistrationExpirationTime();
if (expirationDate == null) {
// Extend the registration by the correct number of years from the expiration time
// that was current on the domain right before the transfer, capped at 10 years from
// the moment of the transfer.
expirationDate =
ResourceFlowUtils.computeExDateForApprovalTime(
domainAtTransferTime, transferExpirationTime, transferData.getTransferPeriod());
}
// If we are within an autorenew grace period, the transfer will subsume the autorenew. There // If we are within an autorenew grace period, the transfer will subsume the autorenew. There
// will already be a cancellation written in advance by the transfer request flow, so we don't // will already be a cancellation written in advance by the transfer request flow, so we don't
// need to worry about billing, but we do need to cancel out the expiration time increase. // need to worry about billing, but we do need to cancel out the expiration time increase.
// The transfer period saved in the transfer data will be one year, unless the superuser // The transfer period saved in the transfer data will be one year, unless the superuser
// extension set the transfer period to zero. // extension set the transfer period to zero.
int extraYears = transferData.getTransferPeriod().getValue();
if (domainAtTransferTime.getGracePeriodStatuses().contains(GracePeriodStatus.AUTO_RENEW)) {
extraYears = 0;
}
// Set the expiration, autorenew events, and grace period for the transfer. (Transfer ends // Set the expiration, autorenew events, and grace period for the transfer. (Transfer ends
// all other graces). // all other graces).
Builder builder = domainAtTransferTime.asBuilder() Builder builder =
// Extend the registration by the correct number of years from the expiration time that domainAtTransferTime
// was current on the domain right before the transfer, capped at 10 years from the .asBuilder()
// moment of the transfer. .setRegistrationExpirationTime(expirationDate)
.setRegistrationExpirationTime(extendRegistrationWithCap( // Set the speculatively-written new autorenew events as the domain's autorenew
transferExpirationTime, // events.
domainAtTransferTime.getRegistrationExpirationTime(), .setAutorenewBillingEvent(transferData.getServerApproveAutorenewEvent())
extraYears)) .setAutorenewPollMessage(transferData.getServerApproveAutorenewPollMessage());
// Set the speculatively-written new autorenew events as the domain's autorenew events.
.setAutorenewBillingEvent(transferData.getServerApproveAutorenewEvent())
.setAutorenewPollMessage(transferData.getServerApproveAutorenewPollMessage());
if (transferData.getTransferPeriod().getValue() == 1) { if (transferData.getTransferPeriod().getValue() == 1) {
// Set the grace period using a key to the prescheduled transfer billing event. Not using // Set the grace period using a key to the prescheduled transfer billing event. Not using
// GracePeriod.forBillingEvent() here in order to avoid the actual Datastore fetch. // GracePeriod.forBillingEvent() here in order to avoid the actual Datastore fetch.

View file

@ -30,7 +30,6 @@ import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppcommon.StatusValue;
import google.registry.model.rde.RdeMode; import google.registry.model.rde.RdeMode;
import google.registry.model.transfer.TransferData; import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferStatus;
import google.registry.util.Idn; import google.registry.util.Idn;
import google.registry.xjc.domain.XjcDomainContactAttrType; import google.registry.xjc.domain.XjcDomainContactAttrType;
import google.registry.xjc.domain.XjcDomainContactType; import google.registry.xjc.domain.XjcDomainContactType;
@ -45,7 +44,6 @@ import google.registry.xjc.rgp.XjcRgpStatusType;
import google.registry.xjc.rgp.XjcRgpStatusValueType; import google.registry.xjc.rgp.XjcRgpStatusValueType;
import google.registry.xjc.secdns.XjcSecdnsDsDataType; import google.registry.xjc.secdns.XjcSecdnsDsDataType;
import google.registry.xjc.secdns.XjcSecdnsDsOrKeyType; import google.registry.xjc.secdns.XjcSecdnsDsOrKeyType;
import org.joda.time.DateTime;
/** Utility class that turns {@link DomainBase} as {@link XjcRdeDomainElement}. */ /** Utility class that turns {@link DomainBase} as {@link XjcRdeDomainElement}. */
final class DomainBaseToXjcConverter { final class DomainBaseToXjcConverter {
@ -241,8 +239,7 @@ final class DomainBaseToXjcConverter {
// empty transfer records to get generated for deleted domains. // empty transfer records to get generated for deleted domains.
// TODO(b/33289763): remove the hasGainingAndLosingRegistrars check in February 2017 // TODO(b/33289763): remove the hasGainingAndLosingRegistrars check in February 2017
if (hasGainingAndLosingRegistrars(model)) { if (hasGainingAndLosingRegistrars(model)) {
bean.setTrnData(convertTransferData(model.getTransferData(), bean.setTrnData(convertTransferData(model.getTransferData()));
model.getRegistrationExpirationTime()));
} }
} }
@ -261,8 +258,7 @@ final class DomainBaseToXjcConverter {
} }
/** Converts {@link TransferData} to {@link XjcRdeDomainTransferDataType}. */ /** Converts {@link TransferData} to {@link XjcRdeDomainTransferDataType}. */
private static XjcRdeDomainTransferDataType convertTransferData( private static XjcRdeDomainTransferDataType convertTransferData(TransferData model) {
TransferData model, DateTime domainExpires) {
XjcRdeDomainTransferDataType bean = new XjcRdeDomainTransferDataType(); XjcRdeDomainTransferDataType bean = new XjcRdeDomainTransferDataType();
bean.setTrStatus( bean.setTrStatus(
XjcEppcomTrStatusType.fromValue(model.getTransferStatus().getXmlName())); XjcEppcomTrStatusType.fromValue(model.getTransferStatus().getXmlName()));
@ -270,12 +266,7 @@ final class DomainBaseToXjcConverter {
bean.setAcRr(RdeUtil.makeXjcRdeRrType(model.getLosingClientId())); bean.setAcRr(RdeUtil.makeXjcRdeRrType(model.getLosingClientId()));
bean.setReDate(model.getTransferRequestTime()); bean.setReDate(model.getTransferRequestTime());
bean.setAcDate(model.getPendingTransferExpirationTime()); bean.setAcDate(model.getPendingTransferExpirationTime());
// TODO(b/25084229): fix exDate computation logic. bean.setExDate(model.getTransferredRegistrationExpirationTime());
if (model.getTransferStatus() == TransferStatus.PENDING) {
bean.setExDate(domainExpires.plusYears(1));
} else {
bean.setExDate(domainExpires);
}
return bean; return bean;
} }

View file

@ -118,8 +118,7 @@ public class ResaveEntityActionTest extends ShardableTestCase {
DateTime.parse("2017-01-02T10:11:00Z")), DateTime.parse("2017-01-02T10:11:00Z")),
DateTime.parse("2016-02-06T10:00:00Z"), DateTime.parse("2016-02-06T10:00:00Z"),
DateTime.parse("2016-02-11T10:00:00Z"), DateTime.parse("2016-02-11T10:00:00Z"),
DateTime.parse("2017-01-02T10:11:00Z"), DateTime.parse("2017-01-02T10:11:00Z"));
DateTime.parse("2016-02-06T10:00:00Z"));
clock.advanceOneMilli(); clock.advanceOneMilli();
assertThat(domain.getCurrentSponsorClientId()).isEqualTo("TheRegistrar"); assertThat(domain.getCurrentSponsorClientId()).isEqualTo("TheRegistrar");
runAction(Key.create(domain), DateTime.parse("2016-02-06T10:00:01Z"), ImmutableSortedSet.of()); runAction(Key.create(domain), DateTime.parse("2016-02-06T10:00:01Z"), ImmutableSortedSet.of());

View file

@ -56,6 +56,12 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class) @RunWith(JUnit4.class)
public class EppLifecycleDomainTest extends EppTestCase { public class EppLifecycleDomainTest extends EppTestCase {
private static final ImmutableMap<String, String> DEFAULT_TRANSFER_RESPONSE_PARMS =
ImmutableMap.of(
"REDATE", "2002-05-30T00:00:00Z",
"ACDATE", "2002-06-04T00:00:00Z",
"EXDATE", "2003-06-01T00:04:00Z");
@Rule @Rule
public final AppEngineRule appEngine = public final AppEngineRule appEngine =
AppEngineRule.builder().withDatastore().withTaskQueue().build(); AppEngineRule.builder().withDatastore().withTaskQueue().build();
@ -552,7 +558,7 @@ public class EppLifecycleDomainTest extends EppTestCase {
assertThatLoginSucceeds("TheRegistrar", "password2"); assertThatLoginSucceeds("TheRegistrar", "password2");
assertThatCommand("domain_transfer_request.xml") assertThatCommand("domain_transfer_request.xml")
.atTime("2002-05-30T00:00:00Z") .atTime("2002-05-30T00:00:00Z")
.hasResponse("domain_transfer_response.xml"); .hasResponse("domain_transfer_response.xml", DEFAULT_TRANSFER_RESPONSE_PARMS);
assertThatLogoutSucceeds(); assertThatLogoutSucceeds();
// Log back in as the first registrar and verify things. // Log back in as the first registrar and verify things.
@ -590,7 +596,7 @@ public class EppLifecycleDomainTest extends EppTestCase {
assertThatLoginSucceeds("TheRegistrar", "password2"); assertThatLoginSucceeds("TheRegistrar", "password2");
assertThatCommand("domain_transfer_request.xml") assertThatCommand("domain_transfer_request.xml")
.atTime("2002-05-30T00:00:00Z") .atTime("2002-05-30T00:00:00Z")
.hasResponse("domain_transfer_response.xml"); .hasResponse("domain_transfer_response.xml", DEFAULT_TRANSFER_RESPONSE_PARMS);
assertThatLogoutSucceeds(); assertThatLogoutSucceeds();
// Log back in as the first registrar and verify domain is pending transfer. // Log back in as the first registrar and verify domain is pending transfer.
@ -640,7 +646,7 @@ public class EppLifecycleDomainTest extends EppTestCase {
assertThatLoginSucceeds("TheRegistrar", "password2"); assertThatLoginSucceeds("TheRegistrar", "password2");
assertThatCommand("domain_transfer_request.xml") assertThatCommand("domain_transfer_request.xml")
.atTime("2002-05-30T00:00:00Z") .atTime("2002-05-30T00:00:00Z")
.hasResponse("domain_transfer_response.xml"); .hasResponse("domain_transfer_response.xml", DEFAULT_TRANSFER_RESPONSE_PARMS);
assertThatLogoutSucceeds(); assertThatLogoutSucceeds();
// Log back in as the first registrar and delete then restore the domain while the transfer // Log back in as the first registrar and delete then restore the domain while the transfer
@ -1027,4 +1033,120 @@ public class EppLifecycleDomainTest extends EppTestCase {
assertThatLogoutSucceeds(); assertThatLogoutSucceeds();
} }
@Test
public void testDomainTransfer_duringAutorenewGrace() throws Exception {
// Creation date of fakesite: 2000-06-01T00:04:00.0Z
// Expiration date: 2002-06-01T00:04:00.0Z
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createFakesite();
// Domain info before transfer is requested and before autorenew grace period begins
assertThatCommand("domain_info.xml", ImmutableMap.of("DOMAIN", "fakesite.example"))
.atTime("2001-06-01T00:00:00Z")
.hasResponse("domain_info_response_before_transfer_and_argp.xml");
assertThatCommand("domain_transfer_query_fakesite.xml")
.atTime("2001-06-01T00:00:00Z")
.hasResponse("domain_transfer_query_response_wildcard_not_requested.xml");
// Domain info before transfer is requested, but after autorenew grace period begins
assertThatCommand("domain_info.xml", ImmutableMap.of("DOMAIN", "fakesite.example"))
.atTime("2002-06-02T00:00:00Z")
.hasResponse("domain_info_response_before_transfer_during_argp.xml");
assertThatCommand("domain_transfer_query_fakesite.xml")
.atTime("2002-06-02T00:00:00Z")
.hasResponse("domain_transfer_query_response_wildcard_not_requested.xml");
assertThatLogoutSucceeds();
assertThatLoginSucceeds("TheRegistrar", "password2");
// Request the transfer
assertThatCommand("domain_transfer_request.xml")
.atTime("2002-06-05T00:02:00.0Z")
.hasResponse(
"domain_transfer_response.xml",
ImmutableMap.of(
"REDATE", "2002-06-05T00:02:00Z",
"ACDATE", "2002-06-10T00:02:00Z",
"EXDATE", "2003-06-01T00:04:00Z"));
assertThatLogoutSucceeds();
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
// Domain info right after the transfer is requested
assertThatCommand("domain_info.xml", ImmutableMap.of("DOMAIN", "fakesite.example"))
.atTime("2002-06-07T00:00:00Z")
.hasResponse("domain_info_response_during_transfer_during_argp.xml");
assertThatCommand("domain_transfer_query_fakesite.xml")
.atTime("2002-06-07T00:00:00Z")
.hasResponse(
"domain_transfer_query_response_wildcard.xml",
ImmutableMap.of(
"STATUS", "pending",
"REDATE", "2002-06-05T00:02:00Z",
"ACDATE", "2002-06-10T00:02:00Z",
"EXDATE", "2003-06-01T00:04:00Z"));
assertThatLogoutSucceeds();
assertThatLoginSucceeds("TheRegistrar", "password2");
// Domain info after transfer is implicitly approved, but autorenew grace period is still
// pending
assertThatCommand("domain_info.xml", ImmutableMap.of("DOMAIN", "fakesite.example"))
.atTime("2002-06-11T00:00:00Z")
.hasResponse("domain_info_response_after_transfer_during_argp.xml");
assertThatCommand("domain_transfer_query_fakesite.xml")
.atTime("2002-06-11T00:00:00Z")
.hasResponse(
"domain_transfer_query_response_wildcard.xml",
ImmutableMap.of(
"STATUS", "serverApproved",
"REDATE", "2002-06-05T00:02:00Z",
"ACDATE", "2002-06-10T00:02:00Z",
"EXDATE", "2003-06-01T00:04:00Z"));
// Domain info after the end of autorenew grace period
assertThatCommand("domain_info.xml", ImmutableMap.of("DOMAIN", "fakesite.example"))
.atTime("2002-09-11T00:00:00Z")
.hasResponse("domain_info_response_after_transfer_after_argp.xml");
assertThatCommand("domain_transfer_query_fakesite.xml")
.atTime("2002-09-11T00:00:00Z")
.hasResponse(
"domain_transfer_query_response_wildcard.xml",
ImmutableMap.of(
"STATUS", "serverApproved",
"REDATE", "2002-06-05T00:02:00Z",
"ACDATE", "2002-06-10T00:02:00Z",
"EXDATE", "2003-06-01T00:04:00Z"));
}
@Test
public void testDomainTransfer_queryForServerApproved() throws Exception {
// Creation date of fakesite: 2000-06-01T00:04:00.0Z
// Expiration date: 2002-06-01T00:04:00.0Z
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
createFakesite();
assertThatLogoutSucceeds();
assertThatLoginSucceeds("TheRegistrar", "password2");
assertThatCommand("domain_transfer_request.xml")
.atTime("2001-01-01T00:00:00.0Z")
.hasResponse(
"domain_transfer_response.xml",
ImmutableMap.of(
"REDATE", "2001-01-01T00:00:00Z",
"ACDATE", "2001-01-06T00:00:00Z",
"EXDATE", "2003-06-01T00:04:00Z"));
assertThatLogoutSucceeds();
assertThatLoginSucceeds("NewRegistrar", "foo-BAR2");
// Verify that reID is set correctly.
assertThatCommand("domain_transfer_query_fakesite.xml")
.atTime("2001-01-03T00:00:00Z")
.hasResponse("domain_transfer_query_response_fakesite.xml");
assertThatCommand("domain_transfer_query_fakesite.xml")
.atTime("2001-01-08T00:00:00Z")
.hasResponse("domain_transfer_query_response_completed_fakesite.xml");
}
} }

View file

@ -101,7 +101,6 @@ public class DomainTransferCancelFlowTest
"NewRegistrar", "NewRegistrar",
TRANSFER_REQUEST_TIME, TRANSFER_REQUEST_TIME,
TRANSFER_EXPIRATION_TIME, TRANSFER_EXPIRATION_TIME,
TRANSFER_REQUEST_TIME,
EXTENDED_REGISTRATION_EXPIRATION_TIME)); EXTENDED_REGISTRATION_EXPIRATION_TIME));
assertPollMessages( assertPollMessages(
"TheRegistrar", "TheRegistrar",
@ -111,7 +110,6 @@ public class DomainTransferCancelFlowTest
"TheRegistrar", "TheRegistrar",
TRANSFER_REQUEST_TIME, TRANSFER_REQUEST_TIME,
TRANSFER_EXPIRATION_TIME, TRANSFER_EXPIRATION_TIME,
TRANSFER_REQUEST_TIME,
EXTENDED_REGISTRATION_EXPIRATION_TIME)); EXTENDED_REGISTRATION_EXPIRATION_TIME));
clock.advanceOneMilli(); clock.advanceOneMilli();

View file

@ -94,8 +94,7 @@ public class DomainTransferFlowTestCase<F extends Flow, R extends EppResource>
domain, domain,
TRANSFER_REQUEST_TIME, TRANSFER_REQUEST_TIME,
TRANSFER_EXPIRATION_TIME, TRANSFER_EXPIRATION_TIME,
EXTENDED_REGISTRATION_EXPIRATION_TIME, EXTENDED_REGISTRATION_EXPIRATION_TIME);
TRANSFER_REQUEST_TIME);
} }
/** Adds a domain with no pending transfer on it. */ /** Adds a domain with no pending transfer on it. */

View file

@ -48,8 +48,8 @@ public class DomainTransferQueryFlowTest
setupDomainWithPendingTransfer("example", "tld"); setupDomainWithPendingTransfer("example", "tld");
} }
private void doSuccessfulTest(String commandFilename, String expectedXmlFilename) private void doSuccessfulTest(
throws Exception { String commandFilename, String expectedXmlFilename, int numPollMessages) throws Exception {
setEppInput(commandFilename); setEppInput(commandFilename);
// Replace the ROID in the xml file with the one generated in our test. // Replace the ROID in the xml file with the one generated in our test.
eppLoader.replaceAll("JD1234-REP", contact.getRepoId()); eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
@ -65,7 +65,8 @@ public class DomainTransferQueryFlowTest
getGainingClientAutorenewEvent(), getGainingClientAutorenewEvent(),
getLosingClientAutorenewEvent()); getLosingClientAutorenewEvent());
// Look in the future and make sure the poll messages for implicit ack are there. // Look in the future and make sure the poll messages for implicit ack are there.
assertThat(getPollMessages("NewRegistrar", clock.nowUtc().plusYears(1))).hasSize(1); assertThat(getPollMessages("NewRegistrar", clock.nowUtc().plusYears(1)))
.hasSize(numPollMessages);
assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusYears(1))).hasSize(1); assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusYears(1))).hasSize(1);
} }
@ -80,62 +81,62 @@ public class DomainTransferQueryFlowTest
@Test @Test
public void testSuccess() throws Exception { public void testSuccess() throws Exception {
doSuccessfulTest("domain_transfer_query.xml", "domain_transfer_query_response.xml"); doSuccessfulTest("domain_transfer_query.xml", "domain_transfer_query_response.xml", 1);
} }
@Test @Test
public void testSuccess_sponsoringClient() throws Exception { public void testSuccess_sponsoringClient() throws Exception {
setClientIdForFlow("TheRegistrar"); setClientIdForFlow("TheRegistrar");
doSuccessfulTest("domain_transfer_query.xml", "domain_transfer_query_response.xml"); doSuccessfulTest("domain_transfer_query.xml", "domain_transfer_query_response.xml", 1);
} }
@Test @Test
public void testSuccess_domainAuthInfo() throws Exception { public void testSuccess_domainAuthInfo() throws Exception {
setClientIdForFlow("ClientZ"); setClientIdForFlow("ClientZ");
doSuccessfulTest( doSuccessfulTest(
"domain_transfer_query_domain_authinfo.xml", "domain_transfer_query_response.xml"); "domain_transfer_query_domain_authinfo.xml", "domain_transfer_query_response.xml", 1);
} }
@Test @Test
public void testSuccess_contactAuthInfo() throws Exception { public void testSuccess_contactAuthInfo() throws Exception {
setClientIdForFlow("ClientZ"); setClientIdForFlow("ClientZ");
doSuccessfulTest( doSuccessfulTest(
"domain_transfer_query_contact_authinfo.xml", "domain_transfer_query_response.xml"); "domain_transfer_query_contact_authinfo.xml", "domain_transfer_query_response.xml", 1);
} }
@Test @Test
public void testSuccess_clientApproved() throws Exception { public void testSuccess_clientApproved() throws Exception {
changeTransferStatus(TransferStatus.CLIENT_APPROVED); changeTransferStatus(TransferStatus.CLIENT_APPROVED);
doSuccessfulTest( doSuccessfulTest(
"domain_transfer_query.xml", "domain_transfer_query_response_client_approved.xml"); "domain_transfer_query.xml", "domain_transfer_query_response_client_approved.xml", 1);
} }
@Test @Test
public void testSuccess_clientRejected() throws Exception { public void testSuccess_clientRejected() throws Exception {
changeTransferStatus(TransferStatus.CLIENT_REJECTED); changeTransferStatus(TransferStatus.CLIENT_REJECTED);
doSuccessfulTest( doSuccessfulTest(
"domain_transfer_query.xml", "domain_transfer_query_response_client_rejected.xml"); "domain_transfer_query.xml", "domain_transfer_query_response_client_rejected.xml", 1);
} }
@Test @Test
public void testSuccess_clientCancelled() throws Exception { public void testSuccess_clientCancelled() throws Exception {
changeTransferStatus(TransferStatus.CLIENT_CANCELLED); changeTransferStatus(TransferStatus.CLIENT_CANCELLED);
doSuccessfulTest( doSuccessfulTest(
"domain_transfer_query.xml", "domain_transfer_query_response_client_cancelled.xml"); "domain_transfer_query.xml", "domain_transfer_query_response_client_cancelled.xml", 1);
} }
@Test @Test
public void testSuccess_serverApproved() throws Exception { public void testSuccess_serverApproved() throws Exception {
changeTransferStatus(TransferStatus.SERVER_APPROVED); changeTransferStatus(TransferStatus.SERVER_APPROVED);
doSuccessfulTest( doSuccessfulTest(
"domain_transfer_query.xml", "domain_transfer_query_response_server_approved.xml"); "domain_transfer_query.xml", "domain_transfer_query_response_server_approved.xml", 1);
} }
@Test @Test
public void testSuccess_serverCancelled() throws Exception { public void testSuccess_serverCancelled() throws Exception {
changeTransferStatus(TransferStatus.SERVER_CANCELLED); changeTransferStatus(TransferStatus.SERVER_CANCELLED);
doSuccessfulTest( doSuccessfulTest(
"domain_transfer_query.xml", "domain_transfer_query_response_server_cancelled.xml"); "domain_transfer_query.xml", "domain_transfer_query_response_server_cancelled.xml", 1);
} }
@Test @Test
@ -148,7 +149,7 @@ public class DomainTransferQueryFlowTest
.asBuilder() .asBuilder()
.setRegistrationExpirationTime(domain.getRegistrationExpirationTime().plusYears(9)) .setRegistrationExpirationTime(domain.getRegistrationExpirationTime().plusYears(9))
.build()); .build());
doSuccessfulTest("domain_transfer_query.xml", "domain_transfer_query_response_10_years.xml"); doSuccessfulTest("domain_transfer_query.xml", "domain_transfer_query_response_10_years.xml", 1);
} }
@Test @Test
@ -157,7 +158,7 @@ public class DomainTransferQueryFlowTest
domain = domain =
persistResource(domain.asBuilder().setDeletionTime(clock.nowUtc().plusDays(1)).build()); persistResource(domain.asBuilder().setDeletionTime(clock.nowUtc().plusDays(1)).build());
doSuccessfulTest( doSuccessfulTest(
"domain_transfer_query.xml", "domain_transfer_query_response_server_cancelled.xml"); "domain_transfer_query.xml", "domain_transfer_query_response_server_cancelled.xml", 1);
} }
@Test @Test
@ -237,4 +238,15 @@ public class DomainTransferQueryFlowTest
assertIcannReportingActivityFieldLogged("srs-dom-transfer-query"); assertIcannReportingActivityFieldLogged("srs-dom-transfer-query");
assertTldsFieldLogged("tld"); assertTldsFieldLogged("tld");
} }
@Test
public void testSuccess_serverApproved_afterAutorenews() throws Exception {
// Set the clock to just past the extended registration time. We'd expect the domain to have
// auto-renewed once, but the transfer query response should be the same.
clock.setTo(EXTENDED_REGISTRATION_EXPIRATION_TIME.plusMillis(1));
assertThat(domain.cloneProjectedAtTime(clock.nowUtc()).getRegistrationExpirationTime())
.isEqualTo(EXTENDED_REGISTRATION_EXPIRATION_TIME.plusYears(1));
doSuccessfulTest(
"domain_transfer_query.xml", "domain_transfer_query_response_server_approved.xml", 2);
}
} }

View file

@ -1093,11 +1093,8 @@ public class DomainTransferRequestFlowTest
domain.getAutorenewBillingEvent())) domain.getAutorenewBillingEvent()))
.build()); .build());
clock.advanceOneMilli(); clock.advanceOneMilli();
// Since the autorenew grace period will have ended by the automatic transfer time, subsuming // The response from DomainTransferRequestFlow returns exDate based on if the transfer were to
// will not occur in the server-approve case, so the transfer will add 1 year to the current // occur now.
// expiration time as usual, and no Cancellation will be issued. Note however that if the
// transfer were to be manually approved before the autorenew grace period ends, then the
// DomainTransferApproveFlow will still issue a Cancellation.
doSuccessfulTest( doSuccessfulTest(
"domain_transfer_request.xml", "domain_transfer_request.xml",
"domain_transfer_request_response_autorenew_grace_at_request_only.xml", "domain_transfer_request_response_autorenew_grace_at_request_only.xml",

View file

@ -143,7 +143,6 @@ public class DomainBaseTest extends EntityTestCase {
.setTransferRequestTime(clock.nowUtc().plusDays(1)) .setTransferRequestTime(clock.nowUtc().plusDays(1))
.setTransferStatus(TransferStatus.SERVER_APPROVED) .setTransferStatus(TransferStatus.SERVER_APPROVED)
.setTransferRequestTrid(Trid.create("client-trid", "server-trid")) .setTransferRequestTrid(Trid.create("client-trid", "server-trid"))
.setTransferredRegistrationExpirationTime(clock.nowUtc().plusYears(2))
.build()) .build())
.setDeletePollMessage(onetimePollKey) .setDeletePollMessage(onetimePollKey)
.setAutorenewBillingEvent(recurringBillKey) .setAutorenewBillingEvent(recurringBillKey)

View file

@ -238,106 +238,139 @@ public class DomainBaseToXjcConverterTest {
.setBillingTime(DateTime.parse("1910-01-01T00:00:00Z")) .setBillingTime(DateTime.parse("1910-01-01T00:00:00Z"))
.setParent(historyEntry) .setParent(historyEntry)
.build()); .build());
domain = domain.asBuilder() domain =
.setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("secret"))) domain
.setContacts(ImmutableSet.of( .asBuilder()
DesignatedContact.create(DesignatedContact.Type.ADMIN, Key.create( .setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("secret")))
makeContactResource(clock, "10-Q9JYB4C", "5372808-IRL", .setContacts(
"be that word our sign in parting", "BOFH@cat.みんな"))), ImmutableSet.of(
DesignatedContact.create(DesignatedContact.Type.TECH, Key.create( DesignatedContact.create(
makeContactResource(clock, "11-Q9JYB4C", "5372808-TRL", DesignatedContact.Type.ADMIN,
"bird or fiend!? i shrieked upstarting", "bog@cat.みんな"))))) Key.create(
.setCreationClientId("LawyerCat") makeContactResource(
.setCreationTimeForTest(DateTime.parse("1900-01-01T00:00:00Z")) clock,
.setPersistedCurrentSponsorClientId("GetTheeBack") "10-Q9JYB4C",
.setDsData(ImmutableSet.of(DelegationSignerData.create( "5372808-IRL",
123, 200, 230, base16().decode("1234567890")))) "be that word our sign in parting",
.setFullyQualifiedDomainName(Idn.toASCII("love.みんな")) "BOFH@cat.みんな"))),
.setLastTransferTime(DateTime.parse("1910-01-01T00:00:00Z")) DesignatedContact.create(
.setLastEppUpdateClientId("IntoTheTempest") DesignatedContact.Type.TECH,
.setLastEppUpdateTime(DateTime.parse("1920-01-01T00:00:00Z")) Key.create(
.setNameservers(ImmutableSet.of( makeContactResource(
Key.create( clock,
makeHostResource(clock, "3-Q9JYB4C", "bird.or.devil.みんな", "1.2.3.4")), "11-Q9JYB4C",
Key.create( "5372808-TRL",
makeHostResource(clock, "4-Q9JYB4C", "ns2.cat.みんな", "bad:f00d:cafe::15:beef")))) "bird or fiend!? i shrieked upstarting",
.setRegistrant(Key.create(makeContactResource( "bog@cat.みんな")))))
clock, "12-Q9JYB4C", "5372808-ERL", "(◕‿◕) nevermore", "prophet@evil.みんな"))) .setCreationClientId("LawyerCat")
.setRegistrationExpirationTime(DateTime.parse("1930-01-01T00:00:00Z")) .setCreationTimeForTest(DateTime.parse("1900-01-01T00:00:00Z"))
.setGracePeriods(ImmutableSet.of( .setPersistedCurrentSponsorClientId("GetTheeBack")
GracePeriod.forBillingEvent(GracePeriodStatus.RENEW, .setDsData(
persistResource( ImmutableSet.of(
new BillingEvent.OneTime.Builder() DelegationSignerData.create(123, 200, 230, base16().decode("1234567890"))))
.setReason(Reason.RENEW) .setFullyQualifiedDomainName(Idn.toASCII("love.みんな"))
.setTargetId("love.xn--q9jyb4c") .setLastTransferTime(DateTime.parse("1910-01-01T00:00:00Z"))
.setClientId("TheRegistrar") .setLastEppUpdateClientId("IntoTheTempest")
.setCost(Money.of(USD, 456)) .setLastEppUpdateTime(DateTime.parse("1920-01-01T00:00:00Z"))
.setPeriodYears(2) .setNameservers(
.setEventTime(DateTime.parse("1920-01-01T00:00:00Z")) ImmutableSet.of(
.setBillingTime(DateTime.parse("1920-01-01T00:00:00Z")) Key.create(
.setParent(historyEntry) makeHostResource(clock, "3-Q9JYB4C", "bird.or.devil.みんな", "1.2.3.4")),
.build())), Key.create(
GracePeriod.create( makeHostResource(
GracePeriodStatus.TRANSFER, DateTime.parse("1920-01-01T00:00:00Z"), "foo", null))) clock, "4-Q9JYB4C", "ns2.cat.みんな", "bad:f00d:cafe::15:beef"))))
.setSubordinateHosts(ImmutableSet.of("home.by.horror.haunted")) .setRegistrant(
.setStatusValues(ImmutableSet.of( Key.create(
StatusValue.CLIENT_DELETE_PROHIBITED, makeContactResource(
StatusValue.CLIENT_RENEW_PROHIBITED, clock, "12-Q9JYB4C", "5372808-ERL", "(◕‿◕) nevermore", "prophet@evil.みんな")))
StatusValue.CLIENT_TRANSFER_PROHIBITED, .setRegistrationExpirationTime(DateTime.parse("1930-01-01T00:00:00Z"))
StatusValue.SERVER_UPDATE_PROHIBITED)) .setGracePeriods(
.setAutorenewBillingEvent( ImmutableSet.of(
Key.create(persistResource( GracePeriod.forBillingEvent(
new BillingEvent.Recurring.Builder() GracePeriodStatus.RENEW,
.setReason(Reason.RENEW) persistResource(
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) new BillingEvent.OneTime.Builder()
.setTargetId("lol") .setReason(Reason.RENEW)
.setClientId("TheRegistrar") .setTargetId("love.xn--q9jyb4c")
.setEventTime(END_OF_TIME) .setClientId("TheRegistrar")
.setRecurrenceEndTime(END_OF_TIME) .setCost(Money.of(USD, 456))
.setParent(historyEntry) .setPeriodYears(2)
.build()))) .setEventTime(DateTime.parse("1920-01-01T00:00:00Z"))
.setAutorenewPollMessage( .setBillingTime(DateTime.parse("1920-01-01T00:00:00Z"))
Key.create(persistResource( .setParent(historyEntry)
new PollMessage.Autorenew.Builder() .build())),
.setTargetId("lol") GracePeriod.create(
.setClientId("TheRegistrar") GracePeriodStatus.TRANSFER,
.setEventTime(END_OF_TIME) DateTime.parse("1920-01-01T00:00:00Z"),
.setAutorenewEndTime(END_OF_TIME) "foo",
.setMsg("Domain was auto-renewed.") null)))
.setParent(historyEntry) .setSubordinateHosts(ImmutableSet.of("home.by.horror.haunted"))
.build()))) .setStatusValues(
.setTransferData(new TransferData.Builder() ImmutableSet.of(
.setGainingClientId("gaining") StatusValue.CLIENT_DELETE_PROHIBITED,
.setLosingClientId("losing") StatusValue.CLIENT_RENEW_PROHIBITED,
.setPendingTransferExpirationTime(DateTime.parse("1925-04-20T00:00:00Z")) StatusValue.CLIENT_TRANSFER_PROHIBITED,
.setServerApproveBillingEvent(Key.create(billingEvent)) StatusValue.SERVER_UPDATE_PROHIBITED))
.setServerApproveAutorenewEvent( .setAutorenewBillingEvent(
Key.create(persistResource( Key.create(
new BillingEvent.Recurring.Builder() persistResource(
.setReason(Reason.RENEW) new BillingEvent.Recurring.Builder()
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) .setReason(Reason.RENEW)
.setTargetId("example.xn--q9jyb4c") .setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
.setClientId("TheRegistrar") .setTargetId("lol")
.setEventTime(END_OF_TIME) .setClientId("TheRegistrar")
.setRecurrenceEndTime(END_OF_TIME) .setEventTime(END_OF_TIME)
.setParent(historyEntry) .setRecurrenceEndTime(END_OF_TIME)
.build()))) .setParent(historyEntry)
.setServerApproveAutorenewPollMessage(Key.create(persistResource( .build())))
new Autorenew.Builder() .setAutorenewPollMessage(
.setTargetId("example.xn--q9jyb4c") Key.create(
.setClientId("TheRegistrar") persistResource(
.setEventTime(END_OF_TIME) new PollMessage.Autorenew.Builder()
.setAutorenewEndTime(END_OF_TIME) .setTargetId("lol")
.setMsg("Domain was auto-renewed.") .setClientId("TheRegistrar")
.setParent(historyEntry) .setEventTime(END_OF_TIME)
.build()))) .setAutorenewEndTime(END_OF_TIME)
.setServerApproveEntities(ImmutableSet.of( .setMsg("Domain was auto-renewed.")
Key.create(billingEvent))) .setParent(historyEntry)
.setTransferRequestTime(DateTime.parse("1919-01-01T00:00:00Z")) .build())))
.setTransferStatus(TransferStatus.PENDING) .setTransferData(
.setTransferRequestTrid(Trid.create("client-trid", "server-trid")) new TransferData.Builder()
.build()) .setGainingClientId("gaining")
.build(); .setLosingClientId("losing")
.setPendingTransferExpirationTime(DateTime.parse("1925-04-20T00:00:00Z"))
.setServerApproveBillingEvent(Key.create(billingEvent))
.setServerApproveAutorenewEvent(
Key.create(
persistResource(
new BillingEvent.Recurring.Builder()
.setReason(Reason.RENEW)
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
.setTargetId("example.xn--q9jyb4c")
.setClientId("TheRegistrar")
.setEventTime(END_OF_TIME)
.setRecurrenceEndTime(END_OF_TIME)
.setParent(historyEntry)
.build())))
.setServerApproveAutorenewPollMessage(
Key.create(
persistResource(
new Autorenew.Builder()
.setTargetId("example.xn--q9jyb4c")
.setClientId("TheRegistrar")
.setEventTime(END_OF_TIME)
.setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.")
.setParent(historyEntry)
.build())))
.setServerApproveEntities(ImmutableSet.of(Key.create(billingEvent)))
.setTransferRequestTime(DateTime.parse("1919-01-01T00:00:00Z"))
.setTransferStatus(TransferStatus.PENDING)
.setTransferredRegistrationExpirationTime(
DateTime.parse("1931-01-01T00:00:00Z"))
.setTransferRequestTrid(Trid.create("client-trid", "server-trid"))
.build())
.build();
clock.advanceOneMilli(); clock.advanceOneMilli();
return persistResource(domain); return persistResource(domain);
} }

View file

@ -79,106 +79,131 @@ final class RdeFixtures {
.setBillingTime(DateTime.parse("1990-01-01T00:00:00Z")) .setBillingTime(DateTime.parse("1990-01-01T00:00:00Z"))
.setParent(historyEntry) .setParent(historyEntry)
.build()); .build());
domain = domain.asBuilder() domain =
.setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("secret"))) domain
.setContacts(ImmutableSet.of( .asBuilder()
DesignatedContact.create(DesignatedContact.Type.ADMIN, Key.create( .setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("secret")))
makeContactResource(clock, "5372808-IRL", .setContacts(
"be that word our sign in parting", "BOFH@cat.みんな"))), ImmutableSet.of(
DesignatedContact.create(DesignatedContact.Type.TECH, Key.create( DesignatedContact.create(
makeContactResource(clock, "5372808-TRL", DesignatedContact.Type.ADMIN,
"bird or fiend!? i shrieked upstarting", "bog@cat.みんな"))))) Key.create(
.setCreationClientId("TheRegistrar") makeContactResource(
.setPersistedCurrentSponsorClientId("TheRegistrar") clock,
.setCreationTimeForTest(clock.nowUtc()) "5372808-IRL",
.setDsData(ImmutableSet.of(DelegationSignerData.create( "be that word our sign in parting",
123, 200, 230, base16().decode("1234567890")))) "BOFH@cat.みんな"))),
.setFullyQualifiedDomainName(Idn.toASCII("love." + tld)) DesignatedContact.create(
.setLastTransferTime(DateTime.parse("1990-01-01T00:00:00Z")) DesignatedContact.Type.TECH,
.setLastEppUpdateClientId("IntoTheTempest") Key.create(
.setLastEppUpdateTime(clock.nowUtc()) makeContactResource(
.setIdnTableName("extended_latin") clock,
.setNameservers(ImmutableSet.of( "5372808-TRL",
Key.create( "bird or fiend!? i shrieked upstarting",
makeHostResource(clock, "bird.or.devil.みんな", "1.2.3.4")), "bog@cat.みんな")))))
Key.create( .setCreationClientId("TheRegistrar")
makeHostResource( .setPersistedCurrentSponsorClientId("TheRegistrar")
clock, "ns2.cat.みんな", "bad:f00d:cafe::15:beef")))) .setCreationTimeForTest(clock.nowUtc())
.setRegistrationExpirationTime(DateTime.parse("1994-01-01T00:00:00Z")) .setDsData(
.setGracePeriods(ImmutableSet.of( ImmutableSet.of(
GracePeriod.forBillingEvent(GracePeriodStatus.RENEW, DelegationSignerData.create(123, 200, 230, base16().decode("1234567890"))))
persistResource( .setFullyQualifiedDomainName(Idn.toASCII("love." + tld))
new BillingEvent.OneTime.Builder() .setLastTransferTime(DateTime.parse("1990-01-01T00:00:00Z"))
.setReason(Reason.RENEW) .setLastEppUpdateClientId("IntoTheTempest")
.setTargetId("love." + tld) .setLastEppUpdateTime(clock.nowUtc())
.setClientId("TheRegistrar") .setIdnTableName("extended_latin")
.setCost(Money.of(USD, 456)) .setNameservers(
.setPeriodYears(2) ImmutableSet.of(
.setEventTime(DateTime.parse("1992-01-01T00:00:00Z")) Key.create(makeHostResource(clock, "bird.or.devil.みんな", "1.2.3.4")),
.setBillingTime(DateTime.parse("1992-01-01T00:00:00Z")) Key.create(makeHostResource(clock, "ns2.cat.みんな", "bad:f00d:cafe::15:beef"))))
.setParent(historyEntry) .setRegistrationExpirationTime(DateTime.parse("1994-01-01T00:00:00Z"))
.build())), .setGracePeriods(
GracePeriod.create( ImmutableSet.of(
GracePeriodStatus.TRANSFER, DateTime.parse("1992-01-01T00:00:00Z"), "foo", null))) GracePeriod.forBillingEvent(
.setSubordinateHosts(ImmutableSet.of("home.by.horror.haunted")) GracePeriodStatus.RENEW,
.setStatusValues(ImmutableSet.of( persistResource(
StatusValue.CLIENT_DELETE_PROHIBITED, new BillingEvent.OneTime.Builder()
StatusValue.CLIENT_RENEW_PROHIBITED, .setReason(Reason.RENEW)
StatusValue.CLIENT_TRANSFER_PROHIBITED, .setTargetId("love." + tld)
StatusValue.SERVER_UPDATE_PROHIBITED)) .setClientId("TheRegistrar")
.setAutorenewBillingEvent( .setCost(Money.of(USD, 456))
Key.create(persistResource( .setPeriodYears(2)
new BillingEvent.Recurring.Builder() .setEventTime(DateTime.parse("1992-01-01T00:00:00Z"))
.setReason(Reason.RENEW) .setBillingTime(DateTime.parse("1992-01-01T00:00:00Z"))
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) .setParent(historyEntry)
.setTargetId(tld) .build())),
.setClientId("TheRegistrar") GracePeriod.create(
.setEventTime(END_OF_TIME) GracePeriodStatus.TRANSFER,
.setRecurrenceEndTime(END_OF_TIME) DateTime.parse("1992-01-01T00:00:00Z"),
.setParent(historyEntry) "foo",
.build()))) null)))
.setAutorenewPollMessage( .setSubordinateHosts(ImmutableSet.of("home.by.horror.haunted"))
Key.create(persistSimpleResource( .setStatusValues(
new PollMessage.Autorenew.Builder() ImmutableSet.of(
.setTargetId(tld) StatusValue.CLIENT_DELETE_PROHIBITED,
.setClientId("TheRegistrar") StatusValue.CLIENT_RENEW_PROHIBITED,
.setEventTime(END_OF_TIME) StatusValue.CLIENT_TRANSFER_PROHIBITED,
.setAutorenewEndTime(END_OF_TIME) StatusValue.SERVER_UPDATE_PROHIBITED))
.setMsg("Domain was auto-renewed.") .setAutorenewBillingEvent(
.setParent(historyEntry) Key.create(
.build()))) persistResource(
.setTransferData(new TransferData.Builder() new BillingEvent.Recurring.Builder()
.setGainingClientId("gaining") .setReason(Reason.RENEW)
.setLosingClientId("losing") .setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
.setPendingTransferExpirationTime(DateTime.parse("1993-04-20T00:00:00Z")) .setTargetId(tld)
.setServerApproveBillingEvent(Key.create(billingEvent)) .setClientId("TheRegistrar")
.setServerApproveAutorenewEvent( .setEventTime(END_OF_TIME)
Key.create(persistResource( .setRecurrenceEndTime(END_OF_TIME)
new BillingEvent.Recurring.Builder() .setParent(historyEntry)
.setReason(Reason.RENEW) .build())))
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) .setAutorenewPollMessage(
.setTargetId("example." + tld) Key.create(
.setClientId("TheRegistrar") persistSimpleResource(
.setEventTime(END_OF_TIME) new PollMessage.Autorenew.Builder()
.setRecurrenceEndTime(END_OF_TIME) .setTargetId(tld)
.setParent(historyEntry) .setClientId("TheRegistrar")
.build()))) .setEventTime(END_OF_TIME)
.setServerApproveAutorenewPollMessage(Key.create(persistResource( .setAutorenewEndTime(END_OF_TIME)
new Autorenew.Builder() .setMsg("Domain was auto-renewed.")
.setTargetId("example." + tld) .setParent(historyEntry)
.setClientId("TheRegistrar") .build())))
.setEventTime(END_OF_TIME) .setTransferData(
.setAutorenewEndTime(END_OF_TIME) new TransferData.Builder()
.setMsg("Domain was auto-renewed.") .setGainingClientId("gaining")
.setParent(historyEntry) .setLosingClientId("losing")
.build()))) .setPendingTransferExpirationTime(DateTime.parse("1993-04-20T00:00:00Z"))
.setServerApproveEntities(ImmutableSet.of( .setServerApproveBillingEvent(Key.create(billingEvent))
Key.create(billingEvent))) .setServerApproveAutorenewEvent(
.setTransferRequestTime(DateTime.parse("1991-01-01T00:00:00Z")) Key.create(
.setTransferStatus(TransferStatus.PENDING) persistResource(
.setTransferRequestTrid(Trid.create("client-trid", "server-trid")) new BillingEvent.Recurring.Builder()
.build()) .setReason(Reason.RENEW)
.build(); .setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
.setTargetId("example." + tld)
.setClientId("TheRegistrar")
.setEventTime(END_OF_TIME)
.setRecurrenceEndTime(END_OF_TIME)
.setParent(historyEntry)
.build())))
.setServerApproveAutorenewPollMessage(
Key.create(
persistResource(
new Autorenew.Builder()
.setTargetId("example." + tld)
.setClientId("TheRegistrar")
.setEventTime(END_OF_TIME)
.setAutorenewEndTime(END_OF_TIME)
.setMsg("Domain was auto-renewed.")
.setParent(historyEntry)
.build())))
.setServerApproveEntities(ImmutableSet.of(Key.create(billingEvent)))
.setTransferRequestTime(DateTime.parse("1991-01-01T00:00:00Z"))
.setTransferStatus(TransferStatus.PENDING)
.setTransferredRegistrationExpirationTime(
DateTime.parse("1995-01-01T00:00:00.000Z"))
.setTransferRequestTrid(Trid.create("client-trid", "server-trid"))
.build())
.build();
clock.advanceOneMilli(); clock.advanceOneMilli();
return persistResourceWithCommitLog(domain); return persistResourceWithCommitLog(domain);
} }

View file

@ -399,7 +399,6 @@ public class DatastoreHelper {
String clientId, String clientId,
DateTime requestTime, DateTime requestTime,
DateTime expirationTime, DateTime expirationTime,
DateTime now,
@Nullable DateTime extendedRegistrationExpirationTime) { @Nullable DateTime extendedRegistrationExpirationTime) {
TransferData transferData = TransferData transferData =
createTransferDataBuilder(requestTime, expirationTime) createTransferDataBuilder(requestTime, expirationTime)
@ -409,7 +408,7 @@ public class DatastoreHelper {
.setClientId(clientId) .setClientId(clientId)
.setEventTime(expirationTime) .setEventTime(expirationTime)
.setMsg("Transfer server approved.") .setMsg("Transfer server approved.")
.setResponseData(ImmutableList.of(createTransferResponse(resource, transferData, now))) .setResponseData(ImmutableList.of(createTransferResponse(resource, transferData)))
.setParent(historyEntry) .setParent(historyEntry)
.build(); .build();
} }
@ -458,7 +457,6 @@ public class DatastoreHelper {
"NewRegistrar", "NewRegistrar",
requestTime, requestTime,
expirationTime, expirationTime,
now,
null))), null))),
Key.create(persistResource( Key.create(persistResource(
createPollMessageForImplicitTransfer( createPollMessageForImplicitTransfer(
@ -467,7 +465,6 @@ public class DatastoreHelper {
"TheRegistrar", "TheRegistrar",
requestTime, requestTime,
expirationTime, expirationTime,
now,
null))))) null)))))
.setTransferRequestTrid(Trid.create("transferClient-trid", "transferServer-trid")) .setTransferRequestTrid(Trid.create("transferClient-trid", "transferServer-trid"))
.build()) .build())
@ -538,8 +535,7 @@ public class DatastoreHelper {
DomainBase domain, DomainBase domain,
DateTime requestTime, DateTime requestTime,
DateTime expirationTime, DateTime expirationTime,
DateTime extendedRegistrationExpirationTime, DateTime extendedRegistrationExpirationTime) {
DateTime now) {
HistoryEntry historyEntryDomainTransfer = persistResource( HistoryEntry historyEntryDomainTransfer = persistResource(
new HistoryEntry.Builder() new HistoryEntry.Builder()
.setType(HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST) .setType(HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST)
@ -608,7 +604,6 @@ public class DatastoreHelper {
"NewRegistrar", "NewRegistrar",
requestTime, requestTime,
expirationTime, expirationTime,
now,
extendedRegistrationExpirationTime))), extendedRegistrationExpirationTime))),
Key.create(persistResource( Key.create(persistResource(
createPollMessageForImplicitTransfer( createPollMessageForImplicitTransfer(
@ -617,7 +612,6 @@ public class DatastoreHelper {
"TheRegistrar", "TheRegistrar",
requestTime, requestTime,
expirationTime, expirationTime,
now,
extendedRegistrationExpirationTime))))) extendedRegistrationExpirationTime)))))
.setTransferRequestTrid(Trid.create("transferClient-trid", "transferServer-trid")) .setTransferRequestTrid(Trid.create("transferClient-trid", "transferServer-trid"))
.build()) .build())

View file

@ -12,7 +12,7 @@
<domain:reDate>2000-06-09T22:00:00.0Z</domain:reDate> <domain:reDate>2000-06-09T22:00:00.0Z</domain:reDate>
<domain:acID>TheRegistrar</domain:acID> <domain:acID>TheRegistrar</domain:acID>
<domain:acDate>2000-06-14T22:00:00.0Z</domain:acDate> <domain:acDate>2000-06-14T22:00:00.0Z</domain:acDate>
<domain:exDate>2002-04-26T22:00:00.0Z</domain:exDate> <domain:exDate>2001-04-26T22:00:00.0Z</domain:exDate>
</domain:trnData> </domain:trnData>
</resData> </resData>
<trID> <trID>

View file

@ -12,8 +12,7 @@
<domain:reDate>2000-06-09T22:00:00.0Z</domain:reDate> <domain:reDate>2000-06-09T22:00:00.0Z</domain:reDate>
<domain:acID>TheRegistrar</domain:acID> <domain:acID>TheRegistrar</domain:acID>
<domain:acDate>2000-06-14T22:00:00.0Z</domain:acDate> <domain:acDate>2000-06-14T22:00:00.0Z</domain:acDate>
<!-- TODO(b/25084229): Exdate should be 2001; needs fixing. --> <domain:exDate>2001-06-08T22:00:00.0Z</domain:exDate>
<domain:exDate>2002-06-08T22:00:00.0Z</domain:exDate>
</domain:trnData> </domain:trnData>
</resData> </resData>
<trID> <trID>

View file

@ -0,0 +1,36 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<domain:infData
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>fakesite.example</domain:name>
<domain:roid>IGNORED</domain:roid>
<domain:status s="ok"/>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">sh8013</domain:contact>
<domain:contact type="tech">sh8013</domain:contact>
<domain:ns>
<domain:hostObj>ns1.example.external</domain:hostObj>
<domain:hostObj>ns2.example.external</domain:hostObj>
</domain:ns>
<domain:clID>TheRegistrar</domain:clID>
<domain:crID>NewRegistrar</domain:crID>
<domain:crDate>2000-06-01T00:04:00.0Z</domain:crDate>
<domain:upID>TheRegistrar</domain:upID>
<domain:upDate>2002-06-15T00:02:00.000Z</domain:upDate>
<domain:exDate>2003-06-01T00:04:00.0Z</domain:exDate>
<domain:trDate>2002-06-10T00:02:00.000Z</domain:trDate>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:infData>
</resData>
<trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -0,0 +1,40 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<domain:infData
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>fakesite.example</domain:name>
<domain:roid>IGNORED</domain:roid>
<domain:status s="ok"/>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">sh8013</domain:contact>
<domain:contact type="tech">sh8013</domain:contact>
<domain:ns>
<domain:hostObj>ns1.example.external</domain:hostObj>
<domain:hostObj>ns2.example.external</domain:hostObj>
</domain:ns>
<domain:clID>TheRegistrar</domain:clID>
<domain:crID>NewRegistrar</domain:crID>
<domain:crDate>2000-06-01T00:04:00.0Z</domain:crDate>
<domain:upID>TheRegistrar</domain:upID>
<domain:upDate>2002-06-10T00:02:00.000Z</domain:upDate>
<domain:exDate>2003-06-01T00:04:00.0Z</domain:exDate>
<domain:trDate>2002-06-10T00:02:00.000Z</domain:trDate>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:infData>
</resData>
<extension>
<rgp:infData xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0">
<rgp:rgpStatus s="transferPeriod"/>
</rgp:infData>
</extension> <trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -0,0 +1,35 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<domain:infData
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>fakesite.example</domain:name>
<domain:roid>IGNORED</domain:roid>
<domain:status s="ok"/>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">sh8013</domain:contact>
<domain:contact type="tech">sh8013</domain:contact>
<domain:ns>
<domain:hostObj>ns1.example.external</domain:hostObj>
<domain:hostObj>ns2.example.external</domain:hostObj>
</domain:ns>
<domain:clID>NewRegistrar</domain:clID>
<domain:crID>NewRegistrar</domain:crID>
<domain:crDate>2000-06-01T00:04:00.0Z</domain:crDate>
<domain:upID>NewRegistrar</domain:upID>
<domain:upDate>2000-06-06T00:04:00.000Z</domain:upDate>
<domain:exDate>2002-06-01T00:04:00.0Z</domain:exDate>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:infData>
</resData>
<trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -0,0 +1,39 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<domain:infData
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>fakesite.example</domain:name>
<domain:roid>IGNORED</domain:roid>
<domain:status s="ok"/>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">sh8013</domain:contact>
<domain:contact type="tech">sh8013</domain:contact>
<domain:ns>
<domain:hostObj>ns1.example.external</domain:hostObj>
<domain:hostObj>ns2.example.external</domain:hostObj>
</domain:ns>
<domain:clID>NewRegistrar</domain:clID>
<domain:crID>NewRegistrar</domain:crID>
<domain:crDate>2000-06-01T00:04:00.0Z</domain:crDate>
<domain:upID>NewRegistrar</domain:upID>
<domain:upDate>2002-06-01T00:04:00.000Z</domain:upDate>
<domain:exDate>2003-06-01T00:04:00.0Z</domain:exDate>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:infData>
</resData>
<extension>
<rgp:infData xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0">
<rgp:rgpStatus s="autoRenewPeriod"/>
</rgp:infData>
</extension> <trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -0,0 +1,39 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<domain:infData
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>fakesite.example</domain:name>
<domain:roid>IGNORED</domain:roid>
<domain:status s="pendingTransfer"/>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">sh8013</domain:contact>
<domain:contact type="tech">sh8013</domain:contact>
<domain:ns>
<domain:hostObj>ns1.example.external</domain:hostObj>
<domain:hostObj>ns2.example.external</domain:hostObj>
</domain:ns>
<domain:clID>NewRegistrar</domain:clID>
<domain:crID>NewRegistrar</domain:crID>
<domain:crDate>2000-06-01T00:04:00.0Z</domain:crDate>
<domain:upID>TheRegistrar</domain:upID>
<domain:upDate>2002-06-05T00:02:00.000Z</domain:upDate>
<domain:exDate>2003-06-01T00:04:00.0Z</domain:exDate>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:infData>
</resData>
<extension>
<rgp:infData xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0">
<rgp:rgpStatus s="autoRenewPeriod"/>
</rgp:infData>
</extension> <trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -11,7 +11,7 @@
<domain:reDate>2001-01-01T00:00:00.000Z</domain:reDate> <domain:reDate>2001-01-01T00:00:00.000Z</domain:reDate>
<domain:acID>NewRegistrar</domain:acID> <domain:acID>NewRegistrar</domain:acID>
<domain:acDate>2001-01-06T00:00:00.000Z</domain:acDate> <domain:acDate>2001-01-06T00:00:00.000Z</domain:acDate>
<domain:exDate>2004-06-01T00:04:00.000Z</domain:exDate> <domain:exDate>2003-06-01T00:04:00.000Z</domain:exDate>
</domain:trnData> </domain:trnData>
</resData> </resData>
<trID> <trID>

View file

@ -0,0 +1,22 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<domain:trnData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>fakesite.example</domain:name>
<domain:trStatus>%STATUS%</domain:trStatus>
<domain:reID>TheRegistrar</domain:reID>
<domain:reDate>%REDATE%</domain:reDate>
<domain:acID>NewRegistrar</domain:acID>
<domain:acDate>%ACDATE%</domain:acDate>
<domain:exDate>%EXDATE%</domain:exDate>
</domain:trnData>
</resData>
<trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -0,0 +1,11 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="2002">
<msg>Object has no transfer history</msg>
</result>
<trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>

View file

@ -8,10 +8,10 @@
<domain:name>fakesite.example</domain:name> <domain:name>fakesite.example</domain:name>
<domain:trStatus>pending</domain:trStatus> <domain:trStatus>pending</domain:trStatus>
<domain:reID>TheRegistrar</domain:reID> <domain:reID>TheRegistrar</domain:reID>
<domain:reDate>2002-05-30T00:00:00Z</domain:reDate> <domain:reDate>%REDATE%</domain:reDate>
<domain:acID>NewRegistrar</domain:acID> <domain:acID>NewRegistrar</domain:acID>
<domain:acDate>2002-06-04T00:00:00Z</domain:acDate> <domain:acDate>%ACDATE%</domain:acDate>
<domain:exDate>2003-06-01T00:04:00Z</domain:exDate> <domain:exDate>%EXDATE%</domain:exDate>
</domain:trnData> </domain:trnData>
</resData> </resData>
<trID> <trID>

View file

@ -167,7 +167,7 @@
<rdeDomain:reDate>1991-01-01T00:00:00Z</rdeDomain:reDate> <rdeDomain:reDate>1991-01-01T00:00:00Z</rdeDomain:reDate>
<rdeDomain:acRr>losing</rdeDomain:acRr> <rdeDomain:acRr>losing</rdeDomain:acRr>
<rdeDomain:acDate>1993-04-20T00:00:00Z</rdeDomain:acDate> <rdeDomain:acDate>1993-04-20T00:00:00Z</rdeDomain:acDate>
<rdeDomain:exDate>2001-01-01T00:00:00Z</rdeDomain:exDate> <rdeDomain:exDate>1995-01-01T00:00:00Z</rdeDomain:exDate>
</rdeDomain:trnData> </rdeDomain:trnData>
</rdeDomain:domain> </rdeDomain:domain>