From 1a0dd0e47b481b081ca25f9e223d232cabe55c6d Mon Sep 17 00:00:00 2001 From: sarahcaseybot Date: Wed, 15 Jan 2020 16:43:39 -0500 Subject: [PATCH] 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 --- .../registry/flows/ResourceFlowUtils.java | 26 ++ .../domain/DomainTransferApproveFlow.java | 8 +- .../flows/domain/DomainTransferQueryFlow.java | 12 +- .../domain/DomainTransferRequestFlow.java | 21 +- .../registry/model/ResourceTransferUtils.java | 35 +-- .../registry/model/domain/DomainBase.java | 34 +-- .../rde/DomainBaseToXjcConverter.java | 15 +- .../batch/ResaveEntityActionTest.java | 3 +- .../flows/EppLifecycleDomainTest.java | 128 +++++++++- .../domain/DomainTransferCancelFlowTest.java | 2 - .../domain/DomainTransferFlowTestCase.java | 3 +- .../domain/DomainTransferQueryFlowTest.java | 40 +-- .../domain/DomainTransferRequestFlowTest.java | 7 +- .../registry/model/domain/DomainBaseTest.java | 1 - .../rde/DomainBaseToXjcConverterTest.java | 233 ++++++++++-------- .../java/google/registry/rde/RdeFixtures.java | 225 +++++++++-------- .../registry/testing/DatastoreHelper.java | 10 +- ...sponse_autorenew_grace_at_request_only.xml | 2 +- ...renew_grace_throughout_transfer_window.xml | 3 +- ...nfo_response_after_transfer_after_argp.xml | 36 +++ ...fo_response_after_transfer_during_argp.xml | 40 +++ ...info_response_before_transfer_and_argp.xml | 35 +++ ...o_response_before_transfer_during_argp.xml | 39 +++ ...o_response_during_transfer_during_argp.xml | 39 +++ ...sfer_query_response_completed_fakesite.xml | 2 +- ...omain_transfer_query_response_wildcard.xml | 22 ++ ..._query_response_wildcard_not_requested.xml | 11 + .../flows/domain_transfer_response.xml | 6 +- ...pReduce_withDomain_producesExpectedXml.xml | 2 +- 29 files changed, 725 insertions(+), 315 deletions(-) create mode 100644 core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_after_argp.xml create mode 100644 core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_during_argp.xml create mode 100644 core/src/test/resources/google/registry/flows/domain_info_response_before_transfer_and_argp.xml create mode 100644 core/src/test/resources/google/registry/flows/domain_info_response_before_transfer_during_argp.xml create mode 100644 core/src/test/resources/google/registry/flows/domain_info_response_during_transfer_during_argp.xml create mode 100644 core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard.xml create mode 100644 core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard_not_requested.xml diff --git a/core/src/main/java/google/registry/flows/ResourceFlowUtils.java b/core/src/main/java/google/registry/flows/ResourceFlowUtils.java index d9549ddb2..5b2681877 100644 --- a/core/src/main/java/google/registry/flows/ResourceFlowUtils.java +++ b/core/src/main/java/google/registry/flows/ResourceFlowUtils.java @@ -42,6 +42,8 @@ import google.registry.model.EppResource.ForeignKeyedEppResource; import google.registry.model.EppResource.ResourceWithTransferData; import google.registry.model.contact.ContactResource; 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.StatusValue; 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. */ public static class ResourceDoesNotExistException extends ObjectDoesNotExistException { public ResourceDoesNotExistException(Class type, String targetId) { diff --git a/core/src/main/java/google/registry/flows/domain/DomainTransferApproveFlow.java b/core/src/main/java/google/registry/flows/domain/DomainTransferApproveFlow.java index ae14b7f61..f4c11a713 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainTransferApproveFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainTransferApproveFlow.java @@ -16,6 +16,7 @@ package google.registry.flows.domain; import static com.google.common.collect.Iterables.getOnlyElement; 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.verifyHasPendingTransfer; 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.createTransferResponse; 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.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL; 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. GracePeriod autorenewGrace = getOnlyElement(existingDomain.getGracePeriodsOfType(GracePeriodStatus.AUTO_RENEW), null); - int extraYears = transferData.getTransferPeriod().getValue(); if (autorenewGrace != null) { - extraYears = 0; // 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. // 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 // up deleting the poll message. updateAutorenewRecurrenceEndTime(existingDomain, now); - DateTime newExpirationTime = extendRegistrationWithCap( - now, existingDomain.getRegistrationExpirationTime(), extraYears); + DateTime newExpirationTime = + computeExDateForApprovalTime(existingDomain, now, transferData.getTransferPeriod()); // Create a new autorenew event starting at the expiration time. BillingEvent.Recurring autorenewEvent = new BillingEvent.Recurring.Builder() .setReason(Reason.RENEW) diff --git a/core/src/main/java/google/registry/flows/domain/DomainTransferQueryFlow.java b/core/src/main/java/google/registry/flows/domain/DomainTransferQueryFlow.java index 6ce16eda3..4b92e79b6 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainTransferQueryFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainTransferQueryFlow.java @@ -18,13 +18,13 @@ import static google.registry.flows.FlowUtils.validateClientIsLoggedIn; import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence; import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; 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.ExtensionManager; import google.registry.flows.Flow; import google.registry.flows.FlowModule.ClientId; import google.registry.flows.FlowModule.TargetId; +import google.registry.flows.ResourceFlowUtils; import google.registry.flows.annotations.ReportingSpec; import google.registry.flows.exceptions.NoTransferHistoryToQueryException; import google.registry.flows.exceptions.NotAuthorizedToViewTransferException; @@ -86,10 +86,12 @@ public final class DomainTransferQueryFlow implements Flow { throw new NotAuthorizedToViewTransferException(); } DateTime newExpirationTime = null; - if (transferData.getTransferStatus().isApproved() - || transferData.getTransferStatus().equals(TransferStatus.PENDING)) { - // TODO(b/25084229): fix exDate computation logic. - newExpirationTime = extendRegistrationWithCap(now, domain.getRegistrationExpirationTime(), 1); + if (transferData.getTransferStatus().isApproved()) { + newExpirationTime = transferData.getTransferredRegistrationExpirationTime(); + } else if (transferData.getTransferStatus().equals(TransferStatus.PENDING)) { + newExpirationTime = + ResourceFlowUtils.computeExDateForApprovalTime( + domain, now, domain.getTransferData().getTransferPeriod()); } return responseBuilder .setResData(createTransferResponse(targetId, transferData, newExpirationTime)) diff --git a/core/src/main/java/google/registry/flows/domain/DomainTransferRequestFlow.java b/core/src/main/java/google/registry/flows/domain/DomainTransferRequestFlow.java index 83613dc35..4d3bc7914 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainTransferRequestFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainTransferRequestFlow.java @@ -15,6 +15,7 @@ package google.registry.flows.domain; 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.verifyAuthInfo; 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.createTransferResponse; 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.ofy.ObjectifyService.ofy; 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.FeeTransformResponseExtension; 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.eppcommon.AuthInfo; 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 // policy documentation for transfers subsuming autorenews within the autorenew grace period. - int extraYears = period.getValue(); - DomainBase domainAtTransferTime = - existingDomain.cloneProjectedAtTime(automaticTransferTime); - if (!domainAtTransferTime.getGracePeriodsOfType(GracePeriodStatus.AUTO_RENEW).isEmpty()) { - extraYears = 0; - } + DomainBase domainAtTransferTime = existingDomain.cloneProjectedAtTime(automaticTransferTime); // The new expiration time if there is a server approval. DateTime serverApproveNewExpirationTime = - extendRegistrationWithCap( - automaticTransferTime, - domainAtTransferTime.getRegistrationExpirationTime(), - extraYears); + computeExDateForApprovalTime(domainAtTransferTime, automaticTransferTime, period); // Create speculative entities in anticipation of an automatic server approval. ImmutableSet serverApproveEntities = 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, // 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. - DateTime approveNowExtendedRegistrationTime = extendRegistrationWithCap( - now, - existingDomain.getRegistrationExpirationTime(), - period.getValue()); + DateTime approveNowExtendedRegistrationTime = + computeExDateForApprovalTime(existingDomain, now, period); return createTransferResponse( targetId, newDomain.getTransferData(), approveNowExtendedRegistrationTime); } diff --git a/core/src/main/java/google/registry/model/ResourceTransferUtils.java b/core/src/main/java/google/registry/model/ResourceTransferUtils.java index fcc90dd37..169d7cc5f 100644 --- a/core/src/main/java/google/registry/model/ResourceTransferUtils.java +++ b/core/src/main/java/google/registry/model/ResourceTransferUtils.java @@ -17,7 +17,6 @@ package google.registry.model; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; -import static google.registry.model.domain.DomainBase.extendRegistrationWithCap; import static google.registry.model.ofy.ObjectifyService.ofy; import com.google.common.collect.ImmutableList; @@ -53,24 +52,22 @@ public final class ResourceTransferUtils { TransferStatus.PENDING, TransferStatus.CLIENT_APPROVED, TransferStatus.SERVER_APPROVED); /** - * Create a transfer response using the id and type of this resource and the specified - * {@link TransferData}. + * Create a transfer response using the id and type of this resource and the specified {@link + * TransferData}. */ public static TransferResponse createTransferResponse( - EppResource eppResource, TransferData transferData, DateTime now) { + EppResource eppResource, TransferData transferData) { assertIsContactOrDomain(eppResource); TransferResponse.Builder builder; if (eppResource instanceof ContactResource) { builder = new ContactTransferResponse.Builder().setContactId(eppResource.getForeignKey()); } else { - DomainBase domain = (DomainBase) eppResource; builder = new DomainTransferResponse.Builder() .setFullyQualifiedDomainName(eppResource.getForeignKey()) - // TODO(b/25084229): fix exDate computation logic. .setExtendedRegistrationExpirationTime( ADD_EXDATE_STATUSES.contains(transferData.getTransferStatus()) - ? extendRegistrationWithCap(now, domain.getRegistrationExpirationTime(), 1) + ? transferData.getTransferredRegistrationExpirationTime() : null); } builder.setGainingClientId(transferData.getGainingClientId()) @@ -118,16 +115,20 @@ public final class ResourceTransferUtils { if (resource.getStatusValues().contains(StatusValue.PENDING_TRANSFER)) { TransferData oldTransferData = resource.getTransferData(); ofy().delete().keys(oldTransferData.getServerApproveEntities()); - ofy().save().entity(new PollMessage.OneTime.Builder() - .setClientId(oldTransferData.getGainingClientId()) - .setEventTime(now) - .setMsg(TransferStatus.SERVER_CANCELLED.getMessage()) - .setResponseData(ImmutableList.of( - createTransferResponse(newResource, newResource.getTransferData(), now), - createPendingTransferNotificationResponse( - resource, oldTransferData.getTransferRequestTrid(), false, now))) - .setParent(historyEntry) - .build()); + ofy() + .save() + .entity( + new PollMessage.OneTime.Builder() + .setClientId(oldTransferData.getGainingClientId()) + .setEventTime(now) + .setMsg(TransferStatus.SERVER_CANCELLED.getMessage()) + .setResponseData( + ImmutableList.of( + createTransferResponse(newResource, newResource.getTransferData()), + createPendingTransferNotificationResponse( + resource, oldTransferData.getTransferRequestTrid(), false, now))) + .setParent(historyEntry) + .build()); } } diff --git a/core/src/main/java/google/registry/model/domain/DomainBase.java b/core/src/main/java/google/registry/model/domain/DomainBase.java index b29f239ac..0c2493c5b 100644 --- a/core/src/main/java/google/registry/model/domain/DomainBase.java +++ b/core/src/main/java/google/registry/model/domain/DomainBase.java @@ -45,6 +45,7 @@ import com.googlecode.objectify.annotation.Entity; import com.googlecode.objectify.annotation.IgnoreSave; import com.googlecode.objectify.annotation.Index; import com.googlecode.objectify.condition.IfNull; +import google.registry.flows.ResourceFlowUtils; import google.registry.model.EppResource; import google.registry.model.EppResource.ForeignKeyedEppResource; 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. DomainBase domainAtTransferTime = 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 // 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. // The transfer period saved in the transfer data will be one year, unless the superuser // 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 // all other graces). - Builder builder = domainAtTransferTime.asBuilder() - // 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. - .setRegistrationExpirationTime(extendRegistrationWithCap( - transferExpirationTime, - domainAtTransferTime.getRegistrationExpirationTime(), - extraYears)) - // Set the speculatively-written new autorenew events as the domain's autorenew events. - .setAutorenewBillingEvent(transferData.getServerApproveAutorenewEvent()) - .setAutorenewPollMessage(transferData.getServerApproveAutorenewPollMessage()); + Builder builder = + domainAtTransferTime + .asBuilder() + .setRegistrationExpirationTime(expirationDate) + // Set the speculatively-written new autorenew events as the domain's autorenew + // events. + .setAutorenewBillingEvent(transferData.getServerApproveAutorenewEvent()) + .setAutorenewPollMessage(transferData.getServerApproveAutorenewPollMessage()); if (transferData.getTransferPeriod().getValue() == 1) { // 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. diff --git a/core/src/main/java/google/registry/rde/DomainBaseToXjcConverter.java b/core/src/main/java/google/registry/rde/DomainBaseToXjcConverter.java index 4af3c0c31..61f3718f9 100644 --- a/core/src/main/java/google/registry/rde/DomainBaseToXjcConverter.java +++ b/core/src/main/java/google/registry/rde/DomainBaseToXjcConverter.java @@ -30,7 +30,6 @@ import google.registry.model.domain.secdns.DelegationSignerData; import google.registry.model.eppcommon.StatusValue; import google.registry.model.rde.RdeMode; import google.registry.model.transfer.TransferData; -import google.registry.model.transfer.TransferStatus; import google.registry.util.Idn; import google.registry.xjc.domain.XjcDomainContactAttrType; 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.secdns.XjcSecdnsDsDataType; import google.registry.xjc.secdns.XjcSecdnsDsOrKeyType; -import org.joda.time.DateTime; /** Utility class that turns {@link DomainBase} as {@link XjcRdeDomainElement}. */ final class DomainBaseToXjcConverter { @@ -241,8 +239,7 @@ final class DomainBaseToXjcConverter { // empty transfer records to get generated for deleted domains. // TODO(b/33289763): remove the hasGainingAndLosingRegistrars check in February 2017 if (hasGainingAndLosingRegistrars(model)) { - bean.setTrnData(convertTransferData(model.getTransferData(), - model.getRegistrationExpirationTime())); + bean.setTrnData(convertTransferData(model.getTransferData())); } } @@ -261,8 +258,7 @@ final class DomainBaseToXjcConverter { } /** Converts {@link TransferData} to {@link XjcRdeDomainTransferDataType}. */ - private static XjcRdeDomainTransferDataType convertTransferData( - TransferData model, DateTime domainExpires) { + private static XjcRdeDomainTransferDataType convertTransferData(TransferData model) { XjcRdeDomainTransferDataType bean = new XjcRdeDomainTransferDataType(); bean.setTrStatus( XjcEppcomTrStatusType.fromValue(model.getTransferStatus().getXmlName())); @@ -270,12 +266,7 @@ final class DomainBaseToXjcConverter { bean.setAcRr(RdeUtil.makeXjcRdeRrType(model.getLosingClientId())); bean.setReDate(model.getTransferRequestTime()); bean.setAcDate(model.getPendingTransferExpirationTime()); - // TODO(b/25084229): fix exDate computation logic. - if (model.getTransferStatus() == TransferStatus.PENDING) { - bean.setExDate(domainExpires.plusYears(1)); - } else { - bean.setExDate(domainExpires); - } + bean.setExDate(model.getTransferredRegistrationExpirationTime()); return bean; } diff --git a/core/src/test/java/google/registry/batch/ResaveEntityActionTest.java b/core/src/test/java/google/registry/batch/ResaveEntityActionTest.java index 777f79ea2..a49b3fea2 100644 --- a/core/src/test/java/google/registry/batch/ResaveEntityActionTest.java +++ b/core/src/test/java/google/registry/batch/ResaveEntityActionTest.java @@ -118,8 +118,7 @@ public class ResaveEntityActionTest extends ShardableTestCase { DateTime.parse("2017-01-02T10:11:00Z")), DateTime.parse("2016-02-06T10:00:00Z"), DateTime.parse("2016-02-11T10:00:00Z"), - DateTime.parse("2017-01-02T10:11:00Z"), - DateTime.parse("2016-02-06T10:00:00Z")); + DateTime.parse("2017-01-02T10:11:00Z")); clock.advanceOneMilli(); assertThat(domain.getCurrentSponsorClientId()).isEqualTo("TheRegistrar"); runAction(Key.create(domain), DateTime.parse("2016-02-06T10:00:01Z"), ImmutableSortedSet.of()); diff --git a/core/src/test/java/google/registry/flows/EppLifecycleDomainTest.java b/core/src/test/java/google/registry/flows/EppLifecycleDomainTest.java index 467198d36..82796e32b 100644 --- a/core/src/test/java/google/registry/flows/EppLifecycleDomainTest.java +++ b/core/src/test/java/google/registry/flows/EppLifecycleDomainTest.java @@ -56,6 +56,12 @@ import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class EppLifecycleDomainTest extends EppTestCase { + private static final ImmutableMap 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 public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().withTaskQueue().build(); @@ -552,7 +558,7 @@ public class EppLifecycleDomainTest extends EppTestCase { assertThatLoginSucceeds("TheRegistrar", "password2"); assertThatCommand("domain_transfer_request.xml") .atTime("2002-05-30T00:00:00Z") - .hasResponse("domain_transfer_response.xml"); + .hasResponse("domain_transfer_response.xml", DEFAULT_TRANSFER_RESPONSE_PARMS); assertThatLogoutSucceeds(); // Log back in as the first registrar and verify things. @@ -590,7 +596,7 @@ public class EppLifecycleDomainTest extends EppTestCase { assertThatLoginSucceeds("TheRegistrar", "password2"); assertThatCommand("domain_transfer_request.xml") .atTime("2002-05-30T00:00:00Z") - .hasResponse("domain_transfer_response.xml"); + .hasResponse("domain_transfer_response.xml", DEFAULT_TRANSFER_RESPONSE_PARMS); assertThatLogoutSucceeds(); // 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"); assertThatCommand("domain_transfer_request.xml") .atTime("2002-05-30T00:00:00Z") - .hasResponse("domain_transfer_response.xml"); + .hasResponse("domain_transfer_response.xml", DEFAULT_TRANSFER_RESPONSE_PARMS); assertThatLogoutSucceeds(); // 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(); } + + @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"); + } } diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferCancelFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferCancelFlowTest.java index 9e54a0f7b..303094a71 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainTransferCancelFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainTransferCancelFlowTest.java @@ -101,7 +101,6 @@ public class DomainTransferCancelFlowTest "NewRegistrar", TRANSFER_REQUEST_TIME, TRANSFER_EXPIRATION_TIME, - TRANSFER_REQUEST_TIME, EXTENDED_REGISTRATION_EXPIRATION_TIME)); assertPollMessages( "TheRegistrar", @@ -111,7 +110,6 @@ public class DomainTransferCancelFlowTest "TheRegistrar", TRANSFER_REQUEST_TIME, TRANSFER_EXPIRATION_TIME, - TRANSFER_REQUEST_TIME, EXTENDED_REGISTRATION_EXPIRATION_TIME)); clock.advanceOneMilli(); diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferFlowTestCase.java b/core/src/test/java/google/registry/flows/domain/DomainTransferFlowTestCase.java index 410512504..47b013cf8 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainTransferFlowTestCase.java +++ b/core/src/test/java/google/registry/flows/domain/DomainTransferFlowTestCase.java @@ -94,8 +94,7 @@ public class DomainTransferFlowTestCase domain, TRANSFER_REQUEST_TIME, TRANSFER_EXPIRATION_TIME, - EXTENDED_REGISTRATION_EXPIRATION_TIME, - TRANSFER_REQUEST_TIME); + EXTENDED_REGISTRATION_EXPIRATION_TIME); } /** Adds a domain with no pending transfer on it. */ diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java index 367e94b76..88ca0e78c 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java @@ -48,8 +48,8 @@ public class DomainTransferQueryFlowTest setupDomainWithPendingTransfer("example", "tld"); } - private void doSuccessfulTest(String commandFilename, String expectedXmlFilename) - throws Exception { + private void doSuccessfulTest( + String commandFilename, String expectedXmlFilename, int numPollMessages) throws Exception { setEppInput(commandFilename); // Replace the ROID in the xml file with the one generated in our test. eppLoader.replaceAll("JD1234-REP", contact.getRepoId()); @@ -65,7 +65,8 @@ public class DomainTransferQueryFlowTest getGainingClientAutorenewEvent(), getLosingClientAutorenewEvent()); // 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); } @@ -80,62 +81,62 @@ public class DomainTransferQueryFlowTest @Test 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 public void testSuccess_sponsoringClient() throws Exception { setClientIdForFlow("TheRegistrar"); - doSuccessfulTest("domain_transfer_query.xml", "domain_transfer_query_response.xml"); + doSuccessfulTest("domain_transfer_query.xml", "domain_transfer_query_response.xml", 1); } @Test public void testSuccess_domainAuthInfo() throws Exception { setClientIdForFlow("ClientZ"); 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 public void testSuccess_contactAuthInfo() throws Exception { setClientIdForFlow("ClientZ"); 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 public void testSuccess_clientApproved() throws Exception { changeTransferStatus(TransferStatus.CLIENT_APPROVED); 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 public void testSuccess_clientRejected() throws Exception { changeTransferStatus(TransferStatus.CLIENT_REJECTED); 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 public void testSuccess_clientCancelled() throws Exception { changeTransferStatus(TransferStatus.CLIENT_CANCELLED); 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 public void testSuccess_serverApproved() throws Exception { changeTransferStatus(TransferStatus.SERVER_APPROVED); 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 public void testSuccess_serverCancelled() throws Exception { changeTransferStatus(TransferStatus.SERVER_CANCELLED); 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 @@ -148,7 +149,7 @@ public class DomainTransferQueryFlowTest .asBuilder() .setRegistrationExpirationTime(domain.getRegistrationExpirationTime().plusYears(9)) .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 @@ -157,7 +158,7 @@ public class DomainTransferQueryFlowTest domain = persistResource(domain.asBuilder().setDeletionTime(clock.nowUtc().plusDays(1)).build()); 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 @@ -237,4 +238,15 @@ public class DomainTransferQueryFlowTest assertIcannReportingActivityFieldLogged("srs-dom-transfer-query"); 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); + } } diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java index f8c56fa28..44f86dd65 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java @@ -1093,11 +1093,8 @@ public class DomainTransferRequestFlowTest domain.getAutorenewBillingEvent())) .build()); clock.advanceOneMilli(); - // Since the autorenew grace period will have ended by the automatic transfer time, subsuming - // will not occur in the server-approve case, so the transfer will add 1 year to the current - // 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. + // The response from DomainTransferRequestFlow returns exDate based on if the transfer were to + // occur now. doSuccessfulTest( "domain_transfer_request.xml", "domain_transfer_request_response_autorenew_grace_at_request_only.xml", diff --git a/core/src/test/java/google/registry/model/domain/DomainBaseTest.java b/core/src/test/java/google/registry/model/domain/DomainBaseTest.java index 930268038..61e3f17bc 100644 --- a/core/src/test/java/google/registry/model/domain/DomainBaseTest.java +++ b/core/src/test/java/google/registry/model/domain/DomainBaseTest.java @@ -143,7 +143,6 @@ public class DomainBaseTest extends EntityTestCase { .setTransferRequestTime(clock.nowUtc().plusDays(1)) .setTransferStatus(TransferStatus.SERVER_APPROVED) .setTransferRequestTrid(Trid.create("client-trid", "server-trid")) - .setTransferredRegistrationExpirationTime(clock.nowUtc().plusYears(2)) .build()) .setDeletePollMessage(onetimePollKey) .setAutorenewBillingEvent(recurringBillKey) diff --git a/core/src/test/java/google/registry/rde/DomainBaseToXjcConverterTest.java b/core/src/test/java/google/registry/rde/DomainBaseToXjcConverterTest.java index 660cbdedd..8ccb8b7d0 100644 --- a/core/src/test/java/google/registry/rde/DomainBaseToXjcConverterTest.java +++ b/core/src/test/java/google/registry/rde/DomainBaseToXjcConverterTest.java @@ -238,106 +238,139 @@ public class DomainBaseToXjcConverterTest { .setBillingTime(DateTime.parse("1910-01-01T00:00:00Z")) .setParent(historyEntry) .build()); - domain = domain.asBuilder() - .setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("secret"))) - .setContacts(ImmutableSet.of( - DesignatedContact.create(DesignatedContact.Type.ADMIN, Key.create( - makeContactResource(clock, "10-Q9JYB4C", "5372808-IRL", - "be that word our sign in parting", "BOFH@cat.みんな"))), - DesignatedContact.create(DesignatedContact.Type.TECH, Key.create( - makeContactResource(clock, "11-Q9JYB4C", "5372808-TRL", - "bird or fiend!? i shrieked upstarting", "bog@cat.みんな"))))) - .setCreationClientId("LawyerCat") - .setCreationTimeForTest(DateTime.parse("1900-01-01T00:00:00Z")) - .setPersistedCurrentSponsorClientId("GetTheeBack") - .setDsData(ImmutableSet.of(DelegationSignerData.create( - 123, 200, 230, base16().decode("1234567890")))) - .setFullyQualifiedDomainName(Idn.toASCII("love.みんな")) - .setLastTransferTime(DateTime.parse("1910-01-01T00:00:00Z")) - .setLastEppUpdateClientId("IntoTheTempest") - .setLastEppUpdateTime(DateTime.parse("1920-01-01T00:00:00Z")) - .setNameservers(ImmutableSet.of( - Key.create( - makeHostResource(clock, "3-Q9JYB4C", "bird.or.devil.みんな", "1.2.3.4")), - Key.create( - makeHostResource(clock, "4-Q9JYB4C", "ns2.cat.みんな", "bad:f00d:cafe::15:beef")))) - .setRegistrant(Key.create(makeContactResource( - clock, "12-Q9JYB4C", "5372808-ERL", "(◕‿◕) nevermore", "prophet@evil.みんな"))) - .setRegistrationExpirationTime(DateTime.parse("1930-01-01T00:00:00Z")) - .setGracePeriods(ImmutableSet.of( - GracePeriod.forBillingEvent(GracePeriodStatus.RENEW, - persistResource( - new BillingEvent.OneTime.Builder() - .setReason(Reason.RENEW) - .setTargetId("love.xn--q9jyb4c") - .setClientId("TheRegistrar") - .setCost(Money.of(USD, 456)) - .setPeriodYears(2) - .setEventTime(DateTime.parse("1920-01-01T00:00:00Z")) - .setBillingTime(DateTime.parse("1920-01-01T00:00:00Z")) - .setParent(historyEntry) - .build())), - GracePeriod.create( - GracePeriodStatus.TRANSFER, DateTime.parse("1920-01-01T00:00:00Z"), "foo", null))) - .setSubordinateHosts(ImmutableSet.of("home.by.horror.haunted")) - .setStatusValues(ImmutableSet.of( - StatusValue.CLIENT_DELETE_PROHIBITED, - StatusValue.CLIENT_RENEW_PROHIBITED, - StatusValue.CLIENT_TRANSFER_PROHIBITED, - StatusValue.SERVER_UPDATE_PROHIBITED)) - .setAutorenewBillingEvent( - Key.create(persistResource( - new BillingEvent.Recurring.Builder() - .setReason(Reason.RENEW) - .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) - .setTargetId("lol") - .setClientId("TheRegistrar") - .setEventTime(END_OF_TIME) - .setRecurrenceEndTime(END_OF_TIME) - .setParent(historyEntry) - .build()))) - .setAutorenewPollMessage( - Key.create(persistResource( - new PollMessage.Autorenew.Builder() - .setTargetId("lol") - .setClientId("TheRegistrar") - .setEventTime(END_OF_TIME) - .setAutorenewEndTime(END_OF_TIME) - .setMsg("Domain was auto-renewed.") - .setParent(historyEntry) - .build()))) - .setTransferData(new TransferData.Builder() - .setGainingClientId("gaining") - .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) - .setTransferRequestTrid(Trid.create("client-trid", "server-trid")) - .build()) - .build(); + domain = + domain + .asBuilder() + .setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("secret"))) + .setContacts( + ImmutableSet.of( + DesignatedContact.create( + DesignatedContact.Type.ADMIN, + Key.create( + makeContactResource( + clock, + "10-Q9JYB4C", + "5372808-IRL", + "be that word our sign in parting", + "BOFH@cat.みんな"))), + DesignatedContact.create( + DesignatedContact.Type.TECH, + Key.create( + makeContactResource( + clock, + "11-Q9JYB4C", + "5372808-TRL", + "bird or fiend!? i shrieked upstarting", + "bog@cat.みんな"))))) + .setCreationClientId("LawyerCat") + .setCreationTimeForTest(DateTime.parse("1900-01-01T00:00:00Z")) + .setPersistedCurrentSponsorClientId("GetTheeBack") + .setDsData( + ImmutableSet.of( + DelegationSignerData.create(123, 200, 230, base16().decode("1234567890")))) + .setFullyQualifiedDomainName(Idn.toASCII("love.みんな")) + .setLastTransferTime(DateTime.parse("1910-01-01T00:00:00Z")) + .setLastEppUpdateClientId("IntoTheTempest") + .setLastEppUpdateTime(DateTime.parse("1920-01-01T00:00:00Z")) + .setNameservers( + ImmutableSet.of( + Key.create( + makeHostResource(clock, "3-Q9JYB4C", "bird.or.devil.みんな", "1.2.3.4")), + Key.create( + makeHostResource( + clock, "4-Q9JYB4C", "ns2.cat.みんな", "bad:f00d:cafe::15:beef")))) + .setRegistrant( + Key.create( + makeContactResource( + clock, "12-Q9JYB4C", "5372808-ERL", "(◕‿◕) nevermore", "prophet@evil.みんな"))) + .setRegistrationExpirationTime(DateTime.parse("1930-01-01T00:00:00Z")) + .setGracePeriods( + ImmutableSet.of( + GracePeriod.forBillingEvent( + GracePeriodStatus.RENEW, + persistResource( + new BillingEvent.OneTime.Builder() + .setReason(Reason.RENEW) + .setTargetId("love.xn--q9jyb4c") + .setClientId("TheRegistrar") + .setCost(Money.of(USD, 456)) + .setPeriodYears(2) + .setEventTime(DateTime.parse("1920-01-01T00:00:00Z")) + .setBillingTime(DateTime.parse("1920-01-01T00:00:00Z")) + .setParent(historyEntry) + .build())), + GracePeriod.create( + GracePeriodStatus.TRANSFER, + DateTime.parse("1920-01-01T00:00:00Z"), + "foo", + null))) + .setSubordinateHosts(ImmutableSet.of("home.by.horror.haunted")) + .setStatusValues( + ImmutableSet.of( + StatusValue.CLIENT_DELETE_PROHIBITED, + StatusValue.CLIENT_RENEW_PROHIBITED, + StatusValue.CLIENT_TRANSFER_PROHIBITED, + StatusValue.SERVER_UPDATE_PROHIBITED)) + .setAutorenewBillingEvent( + Key.create( + persistResource( + new BillingEvent.Recurring.Builder() + .setReason(Reason.RENEW) + .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) + .setTargetId("lol") + .setClientId("TheRegistrar") + .setEventTime(END_OF_TIME) + .setRecurrenceEndTime(END_OF_TIME) + .setParent(historyEntry) + .build()))) + .setAutorenewPollMessage( + Key.create( + persistResource( + new PollMessage.Autorenew.Builder() + .setTargetId("lol") + .setClientId("TheRegistrar") + .setEventTime(END_OF_TIME) + .setAutorenewEndTime(END_OF_TIME) + .setMsg("Domain was auto-renewed.") + .setParent(historyEntry) + .build()))) + .setTransferData( + new TransferData.Builder() + .setGainingClientId("gaining") + .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(); return persistResource(domain); } diff --git a/core/src/test/java/google/registry/rde/RdeFixtures.java b/core/src/test/java/google/registry/rde/RdeFixtures.java index 486d88b65..3aa2d6d0f 100644 --- a/core/src/test/java/google/registry/rde/RdeFixtures.java +++ b/core/src/test/java/google/registry/rde/RdeFixtures.java @@ -79,106 +79,131 @@ final class RdeFixtures { .setBillingTime(DateTime.parse("1990-01-01T00:00:00Z")) .setParent(historyEntry) .build()); - domain = domain.asBuilder() - .setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("secret"))) - .setContacts(ImmutableSet.of( - DesignatedContact.create(DesignatedContact.Type.ADMIN, Key.create( - makeContactResource(clock, "5372808-IRL", - "be that word our sign in parting", "BOFH@cat.みんな"))), - DesignatedContact.create(DesignatedContact.Type.TECH, Key.create( - makeContactResource(clock, "5372808-TRL", - "bird or fiend!? i shrieked upstarting", "bog@cat.みんな"))))) - .setCreationClientId("TheRegistrar") - .setPersistedCurrentSponsorClientId("TheRegistrar") - .setCreationTimeForTest(clock.nowUtc()) - .setDsData(ImmutableSet.of(DelegationSignerData.create( - 123, 200, 230, base16().decode("1234567890")))) - .setFullyQualifiedDomainName(Idn.toASCII("love." + tld)) - .setLastTransferTime(DateTime.parse("1990-01-01T00:00:00Z")) - .setLastEppUpdateClientId("IntoTheTempest") - .setLastEppUpdateTime(clock.nowUtc()) - .setIdnTableName("extended_latin") - .setNameservers(ImmutableSet.of( - Key.create( - makeHostResource(clock, "bird.or.devil.みんな", "1.2.3.4")), - Key.create( - makeHostResource( - clock, "ns2.cat.みんな", "bad:f00d:cafe::15:beef")))) - .setRegistrationExpirationTime(DateTime.parse("1994-01-01T00:00:00Z")) - .setGracePeriods(ImmutableSet.of( - GracePeriod.forBillingEvent(GracePeriodStatus.RENEW, - persistResource( - new BillingEvent.OneTime.Builder() - .setReason(Reason.RENEW) - .setTargetId("love." + tld) - .setClientId("TheRegistrar") - .setCost(Money.of(USD, 456)) - .setPeriodYears(2) - .setEventTime(DateTime.parse("1992-01-01T00:00:00Z")) - .setBillingTime(DateTime.parse("1992-01-01T00:00:00Z")) - .setParent(historyEntry) - .build())), - GracePeriod.create( - GracePeriodStatus.TRANSFER, DateTime.parse("1992-01-01T00:00:00Z"), "foo", null))) - .setSubordinateHosts(ImmutableSet.of("home.by.horror.haunted")) - .setStatusValues(ImmutableSet.of( - StatusValue.CLIENT_DELETE_PROHIBITED, - StatusValue.CLIENT_RENEW_PROHIBITED, - StatusValue.CLIENT_TRANSFER_PROHIBITED, - StatusValue.SERVER_UPDATE_PROHIBITED)) - .setAutorenewBillingEvent( - Key.create(persistResource( - new BillingEvent.Recurring.Builder() - .setReason(Reason.RENEW) - .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) - .setTargetId(tld) - .setClientId("TheRegistrar") - .setEventTime(END_OF_TIME) - .setRecurrenceEndTime(END_OF_TIME) - .setParent(historyEntry) - .build()))) - .setAutorenewPollMessage( - Key.create(persistSimpleResource( - new PollMessage.Autorenew.Builder() - .setTargetId(tld) - .setClientId("TheRegistrar") - .setEventTime(END_OF_TIME) - .setAutorenewEndTime(END_OF_TIME) - .setMsg("Domain was auto-renewed.") - .setParent(historyEntry) - .build()))) - .setTransferData(new TransferData.Builder() - .setGainingClientId("gaining") - .setLosingClientId("losing") - .setPendingTransferExpirationTime(DateTime.parse("1993-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." + 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) - .setTransferRequestTrid(Trid.create("client-trid", "server-trid")) - .build()) - .build(); + domain = + domain + .asBuilder() + .setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("secret"))) + .setContacts( + ImmutableSet.of( + DesignatedContact.create( + DesignatedContact.Type.ADMIN, + Key.create( + makeContactResource( + clock, + "5372808-IRL", + "be that word our sign in parting", + "BOFH@cat.みんな"))), + DesignatedContact.create( + DesignatedContact.Type.TECH, + Key.create( + makeContactResource( + clock, + "5372808-TRL", + "bird or fiend!? i shrieked upstarting", + "bog@cat.みんな"))))) + .setCreationClientId("TheRegistrar") + .setPersistedCurrentSponsorClientId("TheRegistrar") + .setCreationTimeForTest(clock.nowUtc()) + .setDsData( + ImmutableSet.of( + DelegationSignerData.create(123, 200, 230, base16().decode("1234567890")))) + .setFullyQualifiedDomainName(Idn.toASCII("love." + tld)) + .setLastTransferTime(DateTime.parse("1990-01-01T00:00:00Z")) + .setLastEppUpdateClientId("IntoTheTempest") + .setLastEppUpdateTime(clock.nowUtc()) + .setIdnTableName("extended_latin") + .setNameservers( + ImmutableSet.of( + Key.create(makeHostResource(clock, "bird.or.devil.みんな", "1.2.3.4")), + Key.create(makeHostResource(clock, "ns2.cat.みんな", "bad:f00d:cafe::15:beef")))) + .setRegistrationExpirationTime(DateTime.parse("1994-01-01T00:00:00Z")) + .setGracePeriods( + ImmutableSet.of( + GracePeriod.forBillingEvent( + GracePeriodStatus.RENEW, + persistResource( + new BillingEvent.OneTime.Builder() + .setReason(Reason.RENEW) + .setTargetId("love." + tld) + .setClientId("TheRegistrar") + .setCost(Money.of(USD, 456)) + .setPeriodYears(2) + .setEventTime(DateTime.parse("1992-01-01T00:00:00Z")) + .setBillingTime(DateTime.parse("1992-01-01T00:00:00Z")) + .setParent(historyEntry) + .build())), + GracePeriod.create( + GracePeriodStatus.TRANSFER, + DateTime.parse("1992-01-01T00:00:00Z"), + "foo", + null))) + .setSubordinateHosts(ImmutableSet.of("home.by.horror.haunted")) + .setStatusValues( + ImmutableSet.of( + StatusValue.CLIENT_DELETE_PROHIBITED, + StatusValue.CLIENT_RENEW_PROHIBITED, + StatusValue.CLIENT_TRANSFER_PROHIBITED, + StatusValue.SERVER_UPDATE_PROHIBITED)) + .setAutorenewBillingEvent( + Key.create( + persistResource( + new BillingEvent.Recurring.Builder() + .setReason(Reason.RENEW) + .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) + .setTargetId(tld) + .setClientId("TheRegistrar") + .setEventTime(END_OF_TIME) + .setRecurrenceEndTime(END_OF_TIME) + .setParent(historyEntry) + .build()))) + .setAutorenewPollMessage( + Key.create( + persistSimpleResource( + new PollMessage.Autorenew.Builder() + .setTargetId(tld) + .setClientId("TheRegistrar") + .setEventTime(END_OF_TIME) + .setAutorenewEndTime(END_OF_TIME) + .setMsg("Domain was auto-renewed.") + .setParent(historyEntry) + .build()))) + .setTransferData( + new TransferData.Builder() + .setGainingClientId("gaining") + .setLosingClientId("losing") + .setPendingTransferExpirationTime(DateTime.parse("1993-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." + 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(); return persistResourceWithCommitLog(domain); } diff --git a/core/src/test/java/google/registry/testing/DatastoreHelper.java b/core/src/test/java/google/registry/testing/DatastoreHelper.java index eb390807b..3cc552a0b 100644 --- a/core/src/test/java/google/registry/testing/DatastoreHelper.java +++ b/core/src/test/java/google/registry/testing/DatastoreHelper.java @@ -399,7 +399,6 @@ public class DatastoreHelper { String clientId, DateTime requestTime, DateTime expirationTime, - DateTime now, @Nullable DateTime extendedRegistrationExpirationTime) { TransferData transferData = createTransferDataBuilder(requestTime, expirationTime) @@ -409,7 +408,7 @@ public class DatastoreHelper { .setClientId(clientId) .setEventTime(expirationTime) .setMsg("Transfer server approved.") - .setResponseData(ImmutableList.of(createTransferResponse(resource, transferData, now))) + .setResponseData(ImmutableList.of(createTransferResponse(resource, transferData))) .setParent(historyEntry) .build(); } @@ -458,7 +457,6 @@ public class DatastoreHelper { "NewRegistrar", requestTime, expirationTime, - now, null))), Key.create(persistResource( createPollMessageForImplicitTransfer( @@ -467,7 +465,6 @@ public class DatastoreHelper { "TheRegistrar", requestTime, expirationTime, - now, null))))) .setTransferRequestTrid(Trid.create("transferClient-trid", "transferServer-trid")) .build()) @@ -538,8 +535,7 @@ public class DatastoreHelper { DomainBase domain, DateTime requestTime, DateTime expirationTime, - DateTime extendedRegistrationExpirationTime, - DateTime now) { + DateTime extendedRegistrationExpirationTime) { HistoryEntry historyEntryDomainTransfer = persistResource( new HistoryEntry.Builder() .setType(HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST) @@ -608,7 +604,6 @@ public class DatastoreHelper { "NewRegistrar", requestTime, expirationTime, - now, extendedRegistrationExpirationTime))), Key.create(persistResource( createPollMessageForImplicitTransfer( @@ -617,7 +612,6 @@ public class DatastoreHelper { "TheRegistrar", requestTime, expirationTime, - now, extendedRegistrationExpirationTime))))) .setTransferRequestTrid(Trid.create("transferClient-trid", "transferServer-trid")) .build()) diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_autorenew_grace_at_request_only.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_autorenew_grace_at_request_only.xml index e430886f7..16d42003f 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_autorenew_grace_at_request_only.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_autorenew_grace_at_request_only.xml @@ -12,7 +12,7 @@ 2000-06-09T22:00:00.0Z TheRegistrar 2000-06-14T22:00:00.0Z - 2002-04-26T22:00:00.0Z + 2001-04-26T22:00:00.0Z diff --git a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_autorenew_grace_throughout_transfer_window.xml b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_autorenew_grace_throughout_transfer_window.xml index 4e0689ae8..291ff32b1 100644 --- a/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_autorenew_grace_throughout_transfer_window.xml +++ b/core/src/test/resources/google/registry/flows/domain/domain_transfer_request_response_autorenew_grace_throughout_transfer_window.xml @@ -12,8 +12,7 @@ 2000-06-09T22:00:00.0Z TheRegistrar 2000-06-14T22:00:00.0Z - - 2002-06-08T22:00:00.0Z + 2001-06-08T22:00:00.0Z diff --git a/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_after_argp.xml b/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_after_argp.xml new file mode 100644 index 000000000..cfeaca84b --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_after_argp.xml @@ -0,0 +1,36 @@ + + + + Command completed successfully + + + + fakesite.example + IGNORED + + jd1234 + sh8013 + sh8013 + + ns1.example.external + ns2.example.external + + TheRegistrar + NewRegistrar + 2000-06-01T00:04:00.0Z + TheRegistrar + 2002-06-15T00:02:00.000Z + 2003-06-01T00:04:00.0Z + 2002-06-10T00:02:00.000Z + + 2fooBAR + + + + + ABC-12345 + server-trid + + + \ No newline at end of file diff --git a/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_during_argp.xml b/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_during_argp.xml new file mode 100644 index 000000000..af57c2d8d --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain_info_response_after_transfer_during_argp.xml @@ -0,0 +1,40 @@ + + + + Command completed successfully + + + + fakesite.example + IGNORED + + jd1234 + sh8013 + sh8013 + + ns1.example.external + ns2.example.external + + TheRegistrar + NewRegistrar + 2000-06-01T00:04:00.0Z + TheRegistrar + 2002-06-10T00:02:00.000Z + 2003-06-01T00:04:00.0Z + 2002-06-10T00:02:00.000Z + + 2fooBAR + + + + + + + + + ABC-12345 + server-trid + + + \ No newline at end of file diff --git a/core/src/test/resources/google/registry/flows/domain_info_response_before_transfer_and_argp.xml b/core/src/test/resources/google/registry/flows/domain_info_response_before_transfer_and_argp.xml new file mode 100644 index 000000000..20b0b2b1b --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain_info_response_before_transfer_and_argp.xml @@ -0,0 +1,35 @@ + + + + Command completed successfully + + + + fakesite.example + IGNORED + + jd1234 + sh8013 + sh8013 + + ns1.example.external + ns2.example.external + + NewRegistrar + NewRegistrar + 2000-06-01T00:04:00.0Z + NewRegistrar + 2000-06-06T00:04:00.000Z + 2002-06-01T00:04:00.0Z + + 2fooBAR + + + + + ABC-12345 + server-trid + + + diff --git a/core/src/test/resources/google/registry/flows/domain_info_response_before_transfer_during_argp.xml b/core/src/test/resources/google/registry/flows/domain_info_response_before_transfer_during_argp.xml new file mode 100644 index 000000000..0784a91b8 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain_info_response_before_transfer_during_argp.xml @@ -0,0 +1,39 @@ + + + + Command completed successfully + + + + fakesite.example + IGNORED + + jd1234 + sh8013 + sh8013 + + ns1.example.external + ns2.example.external + + NewRegistrar + NewRegistrar + 2000-06-01T00:04:00.0Z + NewRegistrar + 2002-06-01T00:04:00.000Z + 2003-06-01T00:04:00.0Z + + 2fooBAR + + + + + + + + + ABC-12345 + server-trid + + + \ No newline at end of file diff --git a/core/src/test/resources/google/registry/flows/domain_info_response_during_transfer_during_argp.xml b/core/src/test/resources/google/registry/flows/domain_info_response_during_transfer_during_argp.xml new file mode 100644 index 000000000..d238eef15 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain_info_response_during_transfer_during_argp.xml @@ -0,0 +1,39 @@ + + + + Command completed successfully + + + + fakesite.example + IGNORED + + jd1234 + sh8013 + sh8013 + + ns1.example.external + ns2.example.external + + NewRegistrar + NewRegistrar + 2000-06-01T00:04:00.0Z + TheRegistrar + 2002-06-05T00:02:00.000Z + 2003-06-01T00:04:00.0Z + + 2fooBAR + + + + + + + + + ABC-12345 + server-trid + + + \ No newline at end of file diff --git a/core/src/test/resources/google/registry/flows/domain_transfer_query_response_completed_fakesite.xml b/core/src/test/resources/google/registry/flows/domain_transfer_query_response_completed_fakesite.xml index 42f9f6e39..8a6861d3b 100644 --- a/core/src/test/resources/google/registry/flows/domain_transfer_query_response_completed_fakesite.xml +++ b/core/src/test/resources/google/registry/flows/domain_transfer_query_response_completed_fakesite.xml @@ -11,7 +11,7 @@ 2001-01-01T00:00:00.000Z NewRegistrar 2001-01-06T00:00:00.000Z - 2004-06-01T00:04:00.000Z + 2003-06-01T00:04:00.000Z diff --git a/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard.xml b/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard.xml new file mode 100644 index 000000000..bb38fca6d --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard.xml @@ -0,0 +1,22 @@ + + + + Command completed successfully + + + + fakesite.example + %STATUS% + TheRegistrar + %REDATE% + NewRegistrar + %ACDATE% + %EXDATE% + + + + ABC-12345 + server-trid + + + \ No newline at end of file diff --git a/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard_not_requested.xml b/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard_not_requested.xml new file mode 100644 index 000000000..054cdb4a2 --- /dev/null +++ b/core/src/test/resources/google/registry/flows/domain_transfer_query_response_wildcard_not_requested.xml @@ -0,0 +1,11 @@ + + + + Object has no transfer history + + + ABC-12345 + server-trid + + + \ No newline at end of file diff --git a/core/src/test/resources/google/registry/flows/domain_transfer_response.xml b/core/src/test/resources/google/registry/flows/domain_transfer_response.xml index aaa677e8a..b07d33323 100644 --- a/core/src/test/resources/google/registry/flows/domain_transfer_response.xml +++ b/core/src/test/resources/google/registry/flows/domain_transfer_response.xml @@ -8,10 +8,10 @@ fakesite.example pending TheRegistrar - 2002-05-30T00:00:00Z + %REDATE% NewRegistrar - 2002-06-04T00:00:00Z - 2003-06-01T00:04:00Z + %ACDATE% + %EXDATE% diff --git a/core/src/test/resources/google/registry/rde/testMapReduce_withDomain_producesExpectedXml.xml b/core/src/test/resources/google/registry/rde/testMapReduce_withDomain_producesExpectedXml.xml index fd9a69de5..ddaf015ca 100644 --- a/core/src/test/resources/google/registry/rde/testMapReduce_withDomain_producesExpectedXml.xml +++ b/core/src/test/resources/google/registry/rde/testMapReduce_withDomain_producesExpectedXml.xml @@ -167,7 +167,7 @@ 1991-01-01T00:00:00Z losing 1993-04-20T00:00:00Z - 2001-01-01T00:00:00Z + 1995-01-01T00:00:00Z