From 9174855a47b3e31ca76f89ca0b6c5ec6cbab2e8e Mon Sep 17 00:00:00 2001 From: cgoldfeder Date: Fri, 10 Mar 2017 10:05:26 -0800 Subject: [PATCH] Remove the ofy().load() inside of HostResource.cloneProjectedAtTime In fact, completely eviscerate cloneProjectedAtTime (to be removed in a followup CL) in favor of doing the projection of transfers and the loading of values from the superordinate domain at call sites. This is one of the issues that blocked the memcache audit work, since the load inside of cloneProjectedAtTime could not be controlled by the caller. Note: fixed a minor bug where a subordinate host created after its superordinate domain was last transferred should have lastTransferTime==null but was previously reporting the domain's lastTransferTime. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=149769125 --- docs/flows.md | 4 +- .../batch/DeleteContactsAndHostsAction.java | 13 +- .../registry/flows/ResourceFlowUtils.java | 4 +- .../flows/contact/ContactCreateFlow.java | 2 +- .../flows/domain/DomainAllocateFlow.java | 2 +- .../domain/DomainApplicationCreateFlow.java | 2 +- .../flows/domain/DomainCreateFlow.java | 2 +- .../registry/flows/host/HostCreateFlow.java | 6 +- .../registry/flows/host/HostDeleteFlow.java | 10 +- .../registry/flows/host/HostFlowUtils.java | 6 +- .../registry/flows/host/HostInfoFlow.java | 25 +- .../registry/flows/host/HostUpdateFlow.java | 112 ++++--- java/google/registry/model/EppResource.java | 10 +- .../registry/model/EppResourceUtils.java | 2 +- .../model/contact/ContactResource.java | 8 +- .../registry/model/domain/DomainBase.java | 4 + .../registry/model/host/HostResource.java | 62 ++-- .../registry/rdap/RdapJsonFormatter.java | 17 +- .../rde/HostResourceToXjcConverter.java | 50 ++- java/google/registry/rde/RdeMarshaller.java | 11 +- .../google/registry/rde/RdeStagingMapper.java | 15 +- .../XjcToContactResourceConverter.java | 2 +- .../imports/XjcToDomainResourceConverter.java | 2 +- .../imports/XjcToHostResourceConverter.java | 10 +- .../tools/GenerateEscrowDepositCommand.java | 10 +- .../whois/NameserverWhoisResponse.java | 9 +- .../flows/contact/ContactInfoFlowTest.java | 2 +- .../domain/DomainApplicationInfoFlowTest.java | 2 +- .../flows/domain/DomainInfoFlowTest.java | 2 +- .../domain/DomainTransferApproveFlowTest.java | 65 ---- .../domain/DomainTransferCancelFlowTest.java | 1 - .../domain/DomainTransferFlowTestCase.java | 11 +- .../domain/DomainTransferRejectFlowTest.java | 1 - .../domain/DomainTransferRequestFlowTest.java | 20 -- .../flows/host/HostDeleteFlowTest.java | 121 ++++++- .../registry/flows/host/HostInfoFlowTest.java | 6 +- .../flows/host/HostUpdateFlowTest.java | 303 +++++++++++++++--- .../registry/model/EppResourceUtilsTest.java | 14 +- .../model/contact/ContactResourceTest.java | 2 +- .../model/domain/DomainApplicationTest.java | 8 +- .../model/domain/DomainResourceTest.java | 8 +- .../registry/model/host/HostResourceTest.java | 230 ++++++------- .../registry/rdap/RdapJsonFormatterTest.java | 42 +++ .../rdap/testdata/rdapjson_domain_full.json | 2 +- .../rdapjson_domain_no_nameservers.json | 2 +- .../testdata/rdapjson_domain_summary.json | 2 +- .../rdapjson_host_pending_transfer.json | 27 ++ .../ContactResourceToXjcConverterTest.java | 2 +- .../rde/DomainResourceToXjcConverterTest.java | 6 +- .../rde/HostResourceToXjcConverterTest.java | 86 ++++- .../google/registry/rde/RdeFixtures.java | 6 +- .../rde/imports/RdeHostImportActionTest.java | 12 +- .../rde/imports/RdeImportUtilsTest.java | 2 +- .../XjcToHostResourceConverterTest.java | 2 +- .../testing/AbstractDomainBaseSubject.java | 7 + .../testing/AbstractEppResourceSubject.java | 7 +- .../testing/ContactResourceSubject.java | 8 + .../registry/testing/DatastoreHelper.java | 12 +- .../testing/FullFieldsTestEntityHelper.java | 2 +- .../tools/GenerateAuctionDataCommandTest.java | 2 +- .../GenerateEscrowDepositCommandTest.java | 2 +- .../registry/tools/MutatingCommandTest.java | 2 +- .../UpdateApplicationStatusCommandTest.java | 2 +- .../tools/UpdateClaimsNoticeCommandTest.java | 2 +- .../registry/tools/UpdateSmdCommandTest.java | 2 +- .../whois/DomainWhoisResponseTest.java | 2 +- .../whois/NameserverWhoisResponseTest.java | 4 +- 67 files changed, 970 insertions(+), 471 deletions(-) create mode 100644 javatests/google/registry/rdap/testdata/rdapjson_host_pending_transfer.json diff --git a/docs/flows.md b/docs/flows.md index 6bf53d42e..64664856b 100644 --- a/docs/flows.md +++ b/docs/flows.md @@ -965,16 +965,18 @@ are enqueued to update DNS accordingly. * Host rename from external to subordinate must also add an IP addresses. * 2004 * The specified status value cannot be set by clients. + * Host names are limited to 253 characters. * Cannot add IP addresses to an external host. * Host rename from subordinate to external must also remove all IP addresses. * 2005 - * Invalid host name. * Host names must be in lower-case. * Host names must be in normalized format. * Host names must be puny-coded. + * Invalid host name. * 2201 * The specified resource belongs to another client. + * Domain for host is sponsored by another registrar. * 2302 * Host with specified name already exists. * 2303 diff --git a/java/google/registry/batch/DeleteContactsAndHostsAction.java b/java/google/registry/batch/DeleteContactsAndHostsAction.java index 7fb6ce362..52ed03090 100644 --- a/java/google/registry/batch/DeleteContactsAndHostsAction.java +++ b/java/google/registry/batch/DeleteContactsAndHostsAction.java @@ -276,9 +276,18 @@ public class DeleteContactsAndHostsAction implements Runnable { if (!doesResourceStateAllowDeletion(resource, now)) { return DeletionResult.create(Type.ERRORED, ""); } - + // Contacts and external hosts have a direct client id. For subordinate hosts it needs to be + // read off of the superordinate domain. + String resourceClientId = resource.getPersistedCurrentSponsorClientId(); + if (resource instanceof HostResource && ((HostResource) resource).isSubordinate()) { + resourceClientId = + ofy().load().key(((HostResource) resource).getSuperordinateDomain()).now() + .cloneProjectedAtTime(now) + .getCurrentSponsorClientId(); + } boolean requestedByCurrentOwner = - resource.getCurrentSponsorClientId().equals(deletionRequest.requestingClientId()); + resourceClientId.equals(deletionRequest.requestingClientId()); + boolean deleteAllowed = hasNoActiveReferences && (requestedByCurrentOwner || deletionRequest.isSuperuser()); diff --git a/java/google/registry/flows/ResourceFlowUtils.java b/java/google/registry/flows/ResourceFlowUtils.java index 67c1edc82..0ef6e65b4 100644 --- a/java/google/registry/flows/ResourceFlowUtils.java +++ b/java/google/registry/flows/ResourceFlowUtils.java @@ -139,7 +139,7 @@ public final class ResourceFlowUtils { /** Check that the given clientId corresponds to the owner of given resource. */ public static void verifyResourceOwnership(String myClientId, EppResource resource) throws EppException { - if (!myClientId.equals(resource.getCurrentSponsorClientId())) { + if (!myClientId.equals(resource.getPersistedCurrentSponsorClientId())) { throw new ResourceNotOwnedException(); } } @@ -264,7 +264,7 @@ public final class ResourceFlowUtils { B builder = ResourceFlowUtils.resolvePendingTransfer(resource, transferStatus, now); return builder .setLastTransferTime(now) - .setCurrentSponsorClientId(resource.getTransferData().getGainingClientId()) + .setPersistedCurrentSponsorClientId(resource.getTransferData().getGainingClientId()) .build(); } diff --git a/java/google/registry/flows/contact/ContactCreateFlow.java b/java/google/registry/flows/contact/ContactCreateFlow.java index ed85fcd53..279deda11 100644 --- a/java/google/registry/flows/contact/ContactCreateFlow.java +++ b/java/google/registry/flows/contact/ContactCreateFlow.java @@ -72,7 +72,7 @@ public final class ContactCreateFlow implements TransactionalFlow { .setContactId(targetId) .setAuthInfo(command.getAuthInfo()) .setCreationClientId(clientId) - .setCurrentSponsorClientId(clientId) + .setPersistedCurrentSponsorClientId(clientId) .setRepoId(createRepoId(ObjectifyService.allocateId(), roidSuffix)) .setFaxNumber(command.getFax()) .setVoiceNumber(command.getVoice()) diff --git a/java/google/registry/flows/domain/DomainAllocateFlow.java b/java/google/registry/flows/domain/DomainAllocateFlow.java index f5d5060cf..51deff155 100644 --- a/java/google/registry/flows/domain/DomainAllocateFlow.java +++ b/java/google/registry/flows/domain/DomainAllocateFlow.java @@ -155,7 +155,7 @@ public class DomainAllocateFlow implements TransactionalFlow { DateTime registrationExpirationTime = leapSafeAddYears(now, years); DomainResource newDomain = new DomainResource.Builder() .setCreationClientId(clientId) - .setCurrentSponsorClientId(clientId) + .setPersistedCurrentSponsorClientId(clientId) .setRepoId(repoId) .setIdnTableName(validateDomainNameWithIdnTables(domainName)) .setRegistrationExpirationTime(registrationExpirationTime) diff --git a/java/google/registry/flows/domain/DomainApplicationCreateFlow.java b/java/google/registry/flows/domain/DomainApplicationCreateFlow.java index 88398ed6f..9ce807a1b 100644 --- a/java/google/registry/flows/domain/DomainApplicationCreateFlow.java +++ b/java/google/registry/flows/domain/DomainApplicationCreateFlow.java @@ -234,7 +234,7 @@ public final class DomainApplicationCreateFlow implements TransactionalFlow { DomainApplication newApplication = new DomainApplication.Builder() .setCreationTrid(trid) .setCreationClientId(clientId) - .setCurrentSponsorClientId(clientId) + .setPersistedCurrentSponsorClientId(clientId) .setRepoId(createDomainRepoId(ObjectifyService.allocateId(), tld)) .setLaunchNotice(launchCreate == null ? null : launchCreate.getNotice()) .setIdnTableName(idnTableName) diff --git a/java/google/registry/flows/domain/DomainCreateFlow.java b/java/google/registry/flows/domain/DomainCreateFlow.java index 59e886d21..d68b581cc 100644 --- a/java/google/registry/flows/domain/DomainCreateFlow.java +++ b/java/google/registry/flows/domain/DomainCreateFlow.java @@ -266,7 +266,7 @@ public class DomainCreateFlow implements TransactionalFlow { } DomainResource newDomain = new DomainResource.Builder() .setCreationClientId(clientId) - .setCurrentSponsorClientId(clientId) + .setPersistedCurrentSponsorClientId(clientId) .setRepoId(repoId) .setIdnTableName(validateDomainNameWithIdnTables(domainName)) .setRegistrationExpirationTime(registrationExpirationTime) diff --git a/java/google/registry/flows/host/HostCreateFlow.java b/java/google/registry/flows/host/HostCreateFlow.java index b33392cea..09a0330a4 100644 --- a/java/google/registry/flows/host/HostCreateFlow.java +++ b/java/google/registry/flows/host/HostCreateFlow.java @@ -18,7 +18,7 @@ import static google.registry.flows.FlowUtils.validateClientIsLoggedIn; import static google.registry.flows.ResourceFlowUtils.verifyResourceDoesNotExist; import static google.registry.flows.host.HostFlowUtils.lookupSuperordinateDomain; import static google.registry.flows.host.HostFlowUtils.validateHostName; -import static google.registry.flows.host.HostFlowUtils.verifyDomainIsSameRegistrar; +import static google.registry.flows.host.HostFlowUtils.verifySuperordinateDomainOwnership; import static google.registry.model.EppResourceUtils.createRepoId; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.util.CollectionUtils.isNullOrEmpty; @@ -98,7 +98,7 @@ public final class HostCreateFlow implements TransactionalFlow { // we can detect error conditions earlier. Optional superordinateDomain = lookupSuperordinateDomain(validateHostName(targetId), now); - verifyDomainIsSameRegistrar(superordinateDomain.orNull(), clientId); + verifySuperordinateDomainOwnership(clientId, superordinateDomain.orNull()); boolean willBeSubordinate = superordinateDomain.isPresent(); boolean hasIpAddresses = !isNullOrEmpty(command.getInetAddresses()); if (willBeSubordinate != hasIpAddresses) { @@ -109,7 +109,7 @@ public final class HostCreateFlow implements TransactionalFlow { } HostResource newHost = new Builder() .setCreationClientId(clientId) - .setCurrentSponsorClientId(clientId) + .setPersistedCurrentSponsorClientId(clientId) .setFullyQualifiedHostName(targetId) .setInetAddresses(command.getInetAddresses()) .setRepoId(createRepoId(ObjectifyService.allocateId(), roidSuffix)) diff --git a/java/google/registry/flows/host/HostDeleteFlow.java b/java/google/registry/flows/host/HostDeleteFlow.java index 8c6df3f0e..864771b02 100644 --- a/java/google/registry/flows/host/HostDeleteFlow.java +++ b/java/google/registry/flows/host/HostDeleteFlow.java @@ -33,6 +33,7 @@ import google.registry.flows.FlowModule.Superuser; import google.registry.flows.FlowModule.TargetId; import google.registry.flows.TransactionalFlow; import google.registry.flows.async.AsyncFlowEnqueuer; +import google.registry.model.EppResource; import google.registry.model.domain.DomainBase; import google.registry.model.domain.metadata.MetadataExtension; import google.registry.model.eppcommon.StatusValue; @@ -93,7 +94,14 @@ public final class HostDeleteFlow implements TransactionalFlow { HostResource existingHost = loadAndVerifyExistence(HostResource.class, targetId, now); verifyNoDisallowedStatuses(existingHost, DISALLOWED_STATUSES); if (!isSuperuser) { - verifyResourceOwnership(clientId, existingHost); + // Hosts transfer with their superordinate domains, so for hosts with a superordinate domain, + // the client id, needs to be read off of it. + EppResource owningResource = + existingHost.isSubordinate() + ? ofy().load().key(existingHost.getSuperordinateDomain()).now() + .cloneProjectedAtTime(now) + : existingHost; + verifyResourceOwnership(clientId, owningResource); } asyncFlowEnqueuer.enqueueAsyncDelete(existingHost, clientId, isSuperuser); HostResource newHost = diff --git a/java/google/registry/flows/host/HostFlowUtils.java b/java/google/registry/flows/host/HostFlowUtils.java index 06243b9a0..520e6b093 100644 --- a/java/google/registry/flows/host/HostFlowUtils.java +++ b/java/google/registry/flows/host/HostFlowUtils.java @@ -111,9 +111,9 @@ public class HostFlowUtils { } /** Ensure that the superordinate domain is sponsored by the provided clientId. */ - static void verifyDomainIsSameRegistrar( - DomainResource superordinateDomain, - String clientId) throws EppException { + static void verifySuperordinateDomainOwnership( + String clientId, + DomainResource superordinateDomain) throws EppException { if (superordinateDomain != null && !clientId.equals(superordinateDomain.getCurrentSponsorClientId())) { throw new HostDomainNotOwnedException(); diff --git a/java/google/registry/flows/host/HostInfoFlow.java b/java/google/registry/flows/host/HostInfoFlow.java index b0aafaefa..e5b3d5fb6 100644 --- a/java/google/registry/flows/host/HostInfoFlow.java +++ b/java/google/registry/flows/host/HostInfoFlow.java @@ -18,6 +18,7 @@ import static google.registry.flows.FlowUtils.validateClientIsLoggedIn; import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence; import static google.registry.flows.host.HostFlowUtils.validateHostName; import static google.registry.model.EppResourceUtils.isLinked; +import static google.registry.model.ofy.ObjectifyService.ofy; import com.google.common.collect.ImmutableSet; import com.googlecode.objectify.Key; @@ -26,9 +27,11 @@ 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.model.domain.DomainResource; import google.registry.model.eppcommon.StatusValue; import google.registry.model.eppoutput.EppResponse; import google.registry.model.host.HostInfoData; +import google.registry.model.host.HostInfoData.Builder; import google.registry.model.host.HostResource; import google.registry.util.Clock; import javax.inject.Inject; @@ -66,18 +69,34 @@ public final class HostInfoFlow implements Flow { if (isLinked(Key.create(host), now)) { statusValues.add(StatusValue.LINKED); } + Builder hostInfoDataBuilder = HostInfoData.newBuilder(); + // Hosts transfer with their superordinate domains, so for hosts with a superordinate domain, + // the client id, last transfer time, and pending transfer status need to be read off of it. If + // there is no superordinate domain, the host's own values for these fields will be correct. + if (host.isSubordinate()) { + DomainResource superordinateDomain = + ofy().load().key(host.getSuperordinateDomain()).now().cloneProjectedAtTime(now); + hostInfoDataBuilder + .setCurrentSponsorClientId(superordinateDomain.getCurrentSponsorClientId()) + .setLastTransferTime(host.computeLastTransferTime(superordinateDomain)); + if (superordinateDomain.getStatusValues().contains(StatusValue.PENDING_TRANSFER)) { + statusValues.add(StatusValue.PENDING_TRANSFER); + } + } else { + hostInfoDataBuilder + .setCurrentSponsorClientId(host.getPersistedCurrentSponsorClientId()) + .setLastTransferTime(host.getLastTransferTime()); + } return responseBuilder - .setResData(HostInfoData.newBuilder() + .setResData(hostInfoDataBuilder .setFullyQualifiedHostName(host.getFullyQualifiedHostName()) .setRepoId(host.getRepoId()) .setStatusValues(statusValues.build()) .setInetAddresses(host.getInetAddresses()) - .setCurrentSponsorClientId(host.getCurrentSponsorClientId()) .setCreationClientId(host.getCreationClientId()) .setCreationTime(host.getCreationTime()) .setLastEppUpdateClientId(host.getLastEppUpdateClientId()) .setLastEppUpdateTime(host.getLastEppUpdateTime()) - .setLastTransferTime(host.getLastTransferTime()) .build()) .build(); } diff --git a/java/google/registry/flows/host/HostUpdateFlow.java b/java/google/registry/flows/host/HostUpdateFlow.java index bac86100e..5e33a6bb4 100644 --- a/java/google/registry/flows/host/HostUpdateFlow.java +++ b/java/google/registry/flows/host/HostUpdateFlow.java @@ -24,7 +24,7 @@ import static google.registry.flows.ResourceFlowUtils.verifyNoDisallowedStatuses import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership; import static google.registry.flows.host.HostFlowUtils.lookupSuperordinateDomain; import static google.registry.flows.host.HostFlowUtils.validateHostName; -import static google.registry.flows.host.HostFlowUtils.verifyDomainIsSameRegistrar; +import static google.registry.flows.host.HostFlowUtils.verifySuperordinateDomainOwnership; import static google.registry.model.index.ForeignKeyIndex.loadAndGetKey; import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.util.CollectionUtils.isNullOrEmpty; @@ -45,6 +45,7 @@ import google.registry.flows.FlowModule.TargetId; import google.registry.flows.TransactionalFlow; import google.registry.flows.async.AsyncFlowEnqueuer; import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException; +import google.registry.model.EppResource; import google.registry.model.ImmutableObject; import google.registry.model.domain.DomainResource; import google.registry.model.domain.metadata.MetadataExtension; @@ -80,11 +81,13 @@ import org.joda.time.DateTime; * @error {@link google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException} * @error {@link google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException} * @error {@link google.registry.flows.exceptions.ResourceStatusProhibitsOperationException} - * @error {@link HostFlowUtils.HostNameTooShallowException} - * @error {@link HostFlowUtils.InvalidHostNameException} + * @error {@link HostFlowUtils.HostDomainNotOwnedException} * @error {@link HostFlowUtils.HostNameNotLowerCaseException} * @error {@link HostFlowUtils.HostNameNotNormalizedException} * @error {@link HostFlowUtils.HostNameNotPunyCodedException} + * @error {@link HostFlowUtils.HostNameTooLongException} + * @error {@link HostFlowUtils.HostNameTooShallowException} + * @error {@link HostFlowUtils.InvalidHostNameException} * @error {@link HostFlowUtils.SuperordinateDomainDoesNotExistException} * @error {@link CannotAddIpToExternalHostException} * @error {@link CannotRemoveSubordinateHostLastIpException} @@ -128,10 +131,14 @@ public final class HostUpdateFlow implements TransactionalFlow { boolean isHostRename = suppliedNewHostName != null; String oldHostName = targetId; String newHostName = firstNonNull(suppliedNewHostName, oldHostName); + DomainResource oldSuperordinateDomain = existingHost.isSubordinate() + ? ofy().load().key(existingHost.getSuperordinateDomain()).now().cloneProjectedAtTime(now) + : null; // Note that lookupSuperordinateDomain calls cloneProjectedAtTime on the domain for us. Optional newSuperordinateDomain = lookupSuperordinateDomain(validateHostName(newHostName), now); - verifyUpdateAllowed(command, existingHost, newSuperordinateDomain.orNull()); + EppResource owningResource = firstNonNull(oldSuperordinateDomain, existingHost); + verifyUpdateAllowed(command, existingHost, newSuperordinateDomain.orNull(), owningResource); if (isHostRename && loadAndGetKey(HostResource.class, newHostName, now) != null) { throw new HostAlreadyExistsException(newHostName); } @@ -139,13 +146,27 @@ public final class HostUpdateFlow implements TransactionalFlow { AddRemove remove = command.getInnerRemove(); checkSameValuesNotAddedAndRemoved(add.getStatusValues(), remove.getStatusValues()); checkSameValuesNotAddedAndRemoved(add.getInetAddresses(), remove.getInetAddresses()); - Key newSuperordinateDomainKey = - newSuperordinateDomain.isPresent() ? Key.create(newSuperordinateDomain.get()) : null; + Key newSuperordinateDomainKey = newSuperordinateDomain.isPresent() + ? Key.create(newSuperordinateDomain.get()) + : null; // If the superordinateDomain field is changing, set the lastSuperordinateChange to now. DateTime lastSuperordinateChange = Objects.equals(newSuperordinateDomainKey, existingHost.getSuperordinateDomain()) ? existingHost.getLastSuperordinateChange() : now; + // Compute afresh the last transfer time to handle any superordinate domain transfer that may + // have just completed. This is only critical for updates that rename a host away from its + // current superordinate domain, where we must "freeze" the last transfer time, but it's easiest + // to just update it unconditionally. + DateTime lastTransferTime = existingHost.computeLastTransferTime(oldSuperordinateDomain); + // Copy the clientId onto the host. This is only really needed when the host will be external, + // since external hosts store their own clientId. For subordinate hosts the canonical clientId + // comes from the superordinate domain, but we might as well update the persisted value. For + // non-superusers this is the flow clientId, but for superusers it might not be, so compute it. + String newPersistedClientId = + newSuperordinateDomain.isPresent() + ? newSuperordinateDomain.get().getCurrentSponsorClientId() + : owningResource.getPersistedCurrentSponsorClientId(); HostResource newHost = existingHost.asBuilder() .setFullyQualifiedHostName(newHostName) .addStatusValues(add.getStatusValues()) @@ -156,9 +177,9 @@ public final class HostUpdateFlow implements TransactionalFlow { .setLastEppUpdateClientId(clientId) .setSuperordinateDomain(newSuperordinateDomainKey) .setLastSuperordinateChange(lastSuperordinateChange) - .build() - // Rely on the host's cloneProjectedAtTime() method to handle setting of transfer data. - .cloneProjectedAtTime(now); + .setLastTransferTime(lastTransferTime) + .setPersistedCurrentSponsorClientId(newPersistedClientId) + .build(); verifyHasIpsIffIsExternal(command, existingHost, newHost); ImmutableSet.Builder entitiesToSave = new ImmutableSet.Builder<>(); entitiesToSave.add(newHost); @@ -181,32 +202,37 @@ public final class HostUpdateFlow implements TransactionalFlow { } private void verifyUpdateAllowed( - Update command, HostResource existingResource, DomainResource superordinateDomain) - throws EppException { + Update command, + HostResource existingHost, + DomainResource newSuperordinateDomain, + EppResource owningResource) + throws EppException { if (!isSuperuser) { - verifyResourceOwnership(clientId, existingResource); + // Verify that the host belongs to this registrar, either directly or because it is currently + // subordinate to a domain owned by this registrar. + verifyResourceOwnership(clientId, owningResource); + // Verify that the new superordinate domain belongs to this registrar. + verifySuperordinateDomainOwnership(clientId, newSuperordinateDomain); ImmutableSet statusesToAdd = command.getInnerAdd().getStatusValues(); ImmutableSet statusesToRemove = command.getInnerRemove().getStatusValues(); // If the resource is marked with clientUpdateProhibited, and this update does not clear that - // status, then the update must be disallowed (unless a superuser is requesting the change). - if (!isSuperuser - && existingResource.getStatusValues().contains(StatusValue.CLIENT_UPDATE_PROHIBITED) + // status, then the update must be disallowed. + if (existingHost.getStatusValues().contains(StatusValue.CLIENT_UPDATE_PROHIBITED) && !statusesToRemove.contains(StatusValue.CLIENT_UPDATE_PROHIBITED)) { throw new ResourceHasClientUpdateProhibitedException(); } verifyAllStatusesAreClientSettable(union(statusesToAdd, statusesToRemove)); } - verifyDomainIsSameRegistrar(superordinateDomain, clientId); - verifyNoDisallowedStatuses(existingResource, DISALLOWED_STATUSES); + verifyNoDisallowedStatuses(existingHost, DISALLOWED_STATUSES); } private void verifyHasIpsIffIsExternal( - Update command, HostResource existingResource, HostResource newResource) throws EppException { - boolean wasSubordinate = existingResource.isSubordinate(); + Update command, HostResource existingHost, HostResource newHost) throws EppException { + boolean wasSubordinate = existingHost.isSubordinate(); boolean wasExternal = !wasSubordinate; - boolean willBeSubordinate = newResource.isSubordinate(); + boolean willBeSubordinate = newHost.isSubordinate(); boolean willBeExternal = !willBeSubordinate; - boolean newResourceHasIps = !isNullOrEmpty(newResource.getInetAddresses()); + boolean newHostHasIps = !isNullOrEmpty(newHost.getInetAddresses()); boolean commandAddsIps = !isNullOrEmpty(command.getInnerAdd().getInetAddresses()); // These checks are order-dependent. For example a subordinate-to-external rename that adds new // ips should hit the first exception, whereas one that only fails to remove the existing ips @@ -214,61 +240,61 @@ public final class HostUpdateFlow implements TransactionalFlow { if (willBeExternal && commandAddsIps) { throw new CannotAddIpToExternalHostException(); } - if (wasSubordinate && willBeExternal && newResourceHasIps) { + if (wasSubordinate && willBeExternal && newHostHasIps) { throw new RenameHostToExternalRemoveIpException(); } if (wasExternal && willBeSubordinate && !commandAddsIps) { throw new RenameHostToSubordinateRequiresIpException(); } - if (willBeSubordinate && !newResourceHasIps) { + if (willBeSubordinate && !newHostHasIps) { throw new CannotRemoveSubordinateHostLastIpException(); } } - private void enqueueTasks(HostResource existingResource, HostResource newResource) { + private void enqueueTasks(HostResource existingHost, HostResource newHost) { // Only update DNS for subordinate hosts. External hosts have no glue to write, so they // are only written as NS records from the referencing domain. - if (existingResource.isSubordinate()) { - dnsQueue.addHostRefreshTask(existingResource.getFullyQualifiedHostName()); + if (existingHost.isSubordinate()) { + dnsQueue.addHostRefreshTask(existingHost.getFullyQualifiedHostName()); } // In case of a rename, there are many updates we need to queue up. if (((Update) resourceCommand).getInnerChange().getFullyQualifiedHostName() != null) { // If the renamed host is also subordinate, then we must enqueue an update to write the new // glue. - if (newResource.isSubordinate()) { - dnsQueue.addHostRefreshTask(newResource.getFullyQualifiedHostName()); + if (newHost.isSubordinate()) { + dnsQueue.addHostRefreshTask(newHost.getFullyQualifiedHostName()); } // We must also enqueue updates for all domains that use this host as their nameserver so // that their NS records can be updated to point at the new name. - asyncFlowEnqueuer.enqueueAsyncDnsRefresh(existingResource); + asyncFlowEnqueuer.enqueueAsyncDnsRefresh(existingHost); } } - private void updateSuperordinateDomains(HostResource existingResource, HostResource newResource) { - if (existingResource.isSubordinate() - && newResource.isSubordinate() + private static void updateSuperordinateDomains(HostResource existingHost, HostResource newHost) { + if (existingHost.isSubordinate() + && newHost.isSubordinate() && Objects.equals( - existingResource.getSuperordinateDomain(), - newResource.getSuperordinateDomain())) { + existingHost.getSuperordinateDomain(), + newHost.getSuperordinateDomain())) { ofy().save().entity( - ofy().load().key(existingResource.getSuperordinateDomain()).now().asBuilder() - .removeSubordinateHost(existingResource.getFullyQualifiedHostName()) - .addSubordinateHost(newResource.getFullyQualifiedHostName()) + ofy().load().key(existingHost.getSuperordinateDomain()).now().asBuilder() + .removeSubordinateHost(existingHost.getFullyQualifiedHostName()) + .addSubordinateHost(newHost.getFullyQualifiedHostName()) .build()); return; } - if (existingResource.isSubordinate()) { + if (existingHost.isSubordinate()) { ofy().save().entity( - ofy().load().key(existingResource.getSuperordinateDomain()).now() + ofy().load().key(existingHost.getSuperordinateDomain()).now() .asBuilder() - .removeSubordinateHost(existingResource.getFullyQualifiedHostName()) + .removeSubordinateHost(existingHost.getFullyQualifiedHostName()) .build()); } - if (newResource.isSubordinate()) { + if (newHost.isSubordinate()) { ofy().save().entity( - ofy().load().key(newResource.getSuperordinateDomain()).now() + ofy().load().key(newHost.getSuperordinateDomain()).now() .asBuilder() - .addSubordinateHost(newResource.getFullyQualifiedHostName()) + .addSubordinateHost(newHost.getFullyQualifiedHostName()) .build()); } } diff --git a/java/google/registry/model/EppResource.java b/java/google/registry/model/EppResource.java index fe0ad5ad8..c80d16c27 100644 --- a/java/google/registry/model/EppResource.java +++ b/java/google/registry/model/EppResource.java @@ -130,7 +130,13 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable { return lastEppUpdateClientId; } - public final String getCurrentSponsorClientId() { + /** + * Get the stored value of {@link #currentSponsorClientId}. + * + *

For subordinate hosts, this value may not represent the actual current client id, which is + * the client id of the superordinate host. For all other resources this is the true client id. + */ + public final String getPersistedCurrentSponsorClientId() { return currentSponsorClientId; } @@ -218,7 +224,7 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable { } /** Set the current sponsoring registrar. */ - public B setCurrentSponsorClientId(String currentSponsorClientId) { + public B setPersistedCurrentSponsorClientId(String currentSponsorClientId) { getInstance().currentSponsorClientId = currentSponsorClientId; return thisCastToDerived(); } diff --git a/java/google/registry/model/EppResourceUtils.java b/java/google/registry/model/EppResourceUtils.java index f7dc445e6..89045bcf5 100644 --- a/java/google/registry/model/EppResourceUtils.java +++ b/java/google/registry/model/EppResourceUtils.java @@ -207,7 +207,7 @@ public final class EppResourceUtils { .setServerApproveAutorenewPollMessage(null) .build()) .setLastTransferTime(transferData.getPendingTransferExpirationTime()) - .setCurrentSponsorClientId(transferData.getGainingClientId()); + .setPersistedCurrentSponsorClientId(transferData.getGainingClientId()); } /** diff --git a/java/google/registry/model/contact/ContactResource.java b/java/google/registry/model/contact/ContactResource.java index 56424df78..7664a7b40 100644 --- a/java/google/registry/model/contact/ContactResource.java +++ b/java/google/registry/model/contact/ContactResource.java @@ -47,8 +47,8 @@ import org.joda.time.DateTime; @ReportedOn @Entity @ExternalMessagingName("contact") -public class ContactResource extends EppResource - implements ForeignKeyedEppResource, ResourceWithTransferData { +public class ContactResource extends EppResource implements + ForeignKeyedEppResource, ResourceWithTransferData { /** * Unique identifier for this contact. @@ -144,6 +144,10 @@ public class ContactResource extends EppResource return disclose; } + public final String getCurrentSponsorClientId() { + return getPersistedCurrentSponsorClientId(); + } + @Override public final TransferData getTransferData() { return Optional.fromNullable(transferData).or(TransferData.EMPTY); diff --git a/java/google/registry/model/domain/DomainBase.java b/java/google/registry/model/domain/DomainBase.java index 559fb1ef9..d96bbcc6b 100644 --- a/java/google/registry/model/domain/DomainBase.java +++ b/java/google/registry/model/domain/DomainBase.java @@ -128,6 +128,10 @@ public abstract class DomainBase extends EppResource { return nullToEmptyImmutableCopy(nsHosts); } + public final String getCurrentSponsorClientId() { + return getPersistedCurrentSponsorClientId(); + } + /** Loads and returns the fully qualified host names of all linked nameservers. */ public ImmutableSortedSet loadNameserverFullyQualifiedHostNames() { return FluentIterable.from(ofy().load().keys(getNameservers()).values()) diff --git a/java/google/registry/model/host/HostResource.java b/java/google/registry/model/host/HostResource.java index 7caaba54c..9621af625 100644 --- a/java/google/registry/model/host/HostResource.java +++ b/java/google/registry/model/host/HostResource.java @@ -17,7 +17,6 @@ package google.registry.model.host; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.Sets.difference; import static com.google.common.collect.Sets.union; -import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.Ofy.RECOMMENDED_MEMCACHE_EXPIRATION; import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy; import static google.registry.util.DateTimeUtils.START_OF_TIME; @@ -36,11 +35,10 @@ import google.registry.model.EppResource.ForeignKeyedEppResource; import google.registry.model.annotations.ExternalMessagingName; import google.registry.model.annotations.ReportedOn; import google.registry.model.domain.DomainResource; -import google.registry.model.eppcommon.StatusValue; import google.registry.model.transfer.TransferData; -import google.registry.model.transfer.TransferStatus; import java.net.InetAddress; import java.util.Set; +import javax.annotation.Nullable; import org.joda.time.DateTime; /** @@ -122,37 +120,41 @@ public class HostResource extends EppResource implements ForeignKeyedEppResource return fullyQualifiedHostName; } + @Deprecated @Override public HostResource cloneProjectedAtTime(DateTime now) { - Builder builder = this.asBuilder(); + return this; + } - if (superordinateDomain == null) { - // If this was a subordinate host to a domain that was being transferred, there might be a - // pending transfer still extant, so remove it. - builder.removeStatusValue(StatusValue.PENDING_TRANSFER); - } else { - // For hosts with superordinate domains, the client id, last transfer time, and transfer - // status value need to be read off the domain projected to the correct time. - DomainResource domainAtTime = ofy().load().key(superordinateDomain).now() - .cloneProjectedAtTime(now); - builder.setCurrentSponsorClientId(domainAtTime.getCurrentSponsorClientId()); - // If the superordinate domain's last transfer time is what is relevant, because the host's - // superordinate domain was last changed less recently than the domain's last transfer, then - // use the last transfer time on the domain. - if (Optional.fromNullable(lastSuperordinateChange).or(START_OF_TIME) - .isBefore(Optional.fromNullable(domainAtTime.getLastTransferTime()).or(START_OF_TIME))) { - builder.setLastTransferTime(domainAtTime.getLastTransferTime()); - } - // Copy the transfer status from the superordinate domain onto the host, because the host's - // doesn't matter and the superordinate domain always has the canonical data. - TransferStatus domainTransferStatus = domainAtTime.getTransferData().getTransferStatus(); - if (TransferStatus.PENDING.equals(domainTransferStatus)) { - builder.addStatusValue(StatusValue.PENDING_TRANSFER); - } else { - builder.removeStatusValue(StatusValue.PENDING_TRANSFER); - } + /** + * Compute the correct last transfer time for this host given its loaded superordinate domain. + * + *

Hosts can move between superordinate domains, so to know which lastTransferTime is correct + * we need to know if the host was attached to this superordinate the last time that the + * superordinate was transferred. If the last superordinate change was before this time, then the + * host was attached to this superordinate domain during that transfer. + * + *

If the host is not subordinate the domain can be null and we just return last transfer time. + * + * @param superordinateDomain the loaded superordinate domain, which must match the key in + * the {@link #superordinateDomain} field. Passing it as a parameter allows the caller to + * control the degree of consistency used to load it. + */ + public DateTime computeLastTransferTime(@Nullable DomainResource superordinateDomain) { + if (!isSubordinate()) { + checkArgument(superordinateDomain == null); + return getLastTransferTime(); } - return builder.build(); + checkArgument( + superordinateDomain != null + && Key.create(superordinateDomain).equals(getSuperordinateDomain())); + DateTime lastSuperordinateChange = + Optional.fromNullable(getLastSuperordinateChange()).or(getCreationTime()); + DateTime lastTransferOfCurrentSuperordinate = + Optional.fromNullable(superordinateDomain.getLastTransferTime()).or(START_OF_TIME); + return (lastSuperordinateChange.isBefore(lastTransferOfCurrentSuperordinate)) + ? superordinateDomain.getLastTransferTime() + : getLastTransferTime(); } @Override diff --git a/java/google/registry/rdap/RdapJsonFormatter.java b/java/google/registry/rdap/RdapJsonFormatter.java index 46e1b3a62..fc30f323d 100644 --- a/java/google/registry/rdap/RdapJsonFormatter.java +++ b/java/google/registry/rdap/RdapJsonFormatter.java @@ -553,10 +553,19 @@ public class RdapJsonFormatter { if (hasUnicodeComponents(hostResource.getFullyQualifiedHostName())) { jsonBuilder.put("unicodeName", Idn.toUnicode(hostResource.getFullyQualifiedHostName())); } - jsonBuilder.put("status", makeStatusValueList( - isLinked(Key.create(hostResource), now) - ? union(hostResource.getStatusValues(), StatusValue.LINKED) - : hostResource.getStatusValues())); + + ImmutableSet.Builder statuses = new ImmutableSet.Builder<>(); + statuses.addAll(hostResource.getStatusValues()); + if (isLinked(Key.create(hostResource), now)) { + statuses.add(StatusValue.LINKED); + } + if (hostResource.isSubordinate() + && ofy().load().key(hostResource.getSuperordinateDomain()).now().cloneProjectedAtTime(now) + .getStatusValues() + .contains(StatusValue.PENDING_TRANSFER)) { + statuses.add(StatusValue.PENDING_TRANSFER); + } + jsonBuilder.put("status", makeStatusValueList(statuses.build())); jsonBuilder.put("links", ImmutableList.of( makeLink("nameserver", hostResource.getFullyQualifiedHostName(), linkBase))); List> remarks; diff --git a/java/google/registry/rde/HostResourceToXjcConverter.java b/java/google/registry/rde/HostResourceToXjcConverter.java index d2bf6ccc6..b699d246f 100644 --- a/java/google/registry/rde/HostResourceToXjcConverter.java +++ b/java/google/registry/rde/HostResourceToXjcConverter.java @@ -14,7 +14,11 @@ package google.registry.rde; +import static com.google.common.base.Preconditions.checkArgument; + import com.google.common.net.InetAddresses; +import com.googlecode.objectify.Key; +import google.registry.model.domain.DomainResource; import google.registry.model.eppcommon.StatusValue; import google.registry.model.host.HostResource; import google.registry.xjc.host.XjcHostAddrType; @@ -25,28 +29,62 @@ import google.registry.xjc.rdehost.XjcRdeHost; import google.registry.xjc.rdehost.XjcRdeHostElement; import java.net.Inet6Address; import java.net.InetAddress; +import org.joda.time.DateTime; /** Utility class that turns {@link HostResource} as {@link XjcRdeHostElement}. */ final class HostResourceToXjcConverter { - /** Converts {@link HostResource} to {@link XjcRdeHostElement}. */ - static XjcRdeHostElement convert(HostResource host) { - return new XjcRdeHostElement(convertHost(host)); + /** Converts a subordinate {@link HostResource} to {@link XjcRdeHostElement}. */ + static XjcRdeHostElement convertSubordinate( + HostResource host, DomainResource superordinateDomain) { + checkArgument(Key.create(superordinateDomain).equals(host.getSuperordinateDomain())); + return new XjcRdeHostElement(convertSubordinateHost(host, superordinateDomain)); + } + + /** Converts an external {@link HostResource} to {@link XjcRdeHostElement}. */ + static XjcRdeHostElement convertExternal(HostResource host) { + checkArgument(!host.isSubordinate()); + return new XjcRdeHostElement(convertExternalHost(host)); } /** Converts {@link HostResource} to {@link XjcRdeHost}. */ - static XjcRdeHost convertHost(HostResource model) { + static XjcRdeHost convertSubordinateHost(HostResource model, DomainResource superordinateDomain) { + XjcRdeHost bean = convertHostCommon( + model, + superordinateDomain.getCurrentSponsorClientId(), + model.computeLastTransferTime(superordinateDomain)); + if (superordinateDomain.getStatusValues().contains(StatusValue.PENDING_TRANSFER)) { + bean.getStatuses().add(convertStatusValue(StatusValue.PENDING_TRANSFER)); + } + return bean; + } + + /** Converts {@link HostResource} to {@link XjcRdeHost}. */ + static XjcRdeHost convertExternalHost(HostResource model) { + return convertHostCommon( + model, + model.getPersistedCurrentSponsorClientId(), + model.getLastTransferTime()); + } + + private static XjcRdeHost convertHostCommon( + HostResource model, String clientId, DateTime lastTransferTime) { XjcRdeHost bean = new XjcRdeHost(); bean.setName(model.getFullyQualifiedHostName()); bean.setRoid(model.getRepoId()); - bean.setClID(model.getCurrentSponsorClientId()); - bean.setTrDate(model.getLastTransferTime()); bean.setCrDate(model.getCreationTime()); bean.setUpDate(model.getLastEppUpdateTime()); bean.setCrRr(RdeAdapter.convertRr(model.getCreationClientId(), null)); bean.setUpRr(RdeAdapter.convertRr(model.getLastEppUpdateClientId(), null)); bean.setCrRr(RdeAdapter.convertRr(model.getCreationClientId(), null)); + bean.setClID(clientId); + bean.setTrDate(lastTransferTime); for (StatusValue status : model.getStatusValues()) { + // TODO(b/34844887): Remove when PENDING_TRANSFER is not persisted on host resources. + if (status.equals(StatusValue.PENDING_TRANSFER)) { + continue; + } + // TODO(cgoldfeder): Add in LINKED status if applicable. bean.getStatuses().add(convertStatusValue(status)); } for (InetAddress addr : model.getInetAddresses()) { diff --git a/java/google/registry/rde/RdeMarshaller.java b/java/google/registry/rde/RdeMarshaller.java index 227e7ada4..4a9c20907 100644 --- a/java/google/registry/rde/RdeMarshaller.java +++ b/java/google/registry/rde/RdeMarshaller.java @@ -117,9 +117,16 @@ public final class RdeMarshaller implements Serializable { } /** Turns {@link HostResource} object into an XML fragment. */ - public DepositFragment marshalHost(HostResource host) { + public DepositFragment marshalSubordinateHost( + HostResource host, DomainResource superordinateDomain) { return marshalResource(RdeResourceType.HOST, host, - HostResourceToXjcConverter.convert(host)); + HostResourceToXjcConverter.convertSubordinate(host, superordinateDomain)); + } + + /** Turns {@link HostResource} object into an XML fragment. */ + public DepositFragment marshalExternalHost(HostResource host) { + return marshalResource(RdeResourceType.HOST, host, + HostResourceToXjcConverter.convertExternal(host)); } /** Turns {@link Registrar} object into an XML fragment. */ diff --git a/java/google/registry/rde/RdeStagingMapper.java b/java/google/registry/rde/RdeStagingMapper.java index 91ecebaff..6385742ee 100644 --- a/java/google/registry/rde/RdeStagingMapper.java +++ b/java/google/registry/rde/RdeStagingMapper.java @@ -15,6 +15,7 @@ package google.registry.rde; import static com.google.common.base.Strings.nullToEmpty; +import static google.registry.model.EppResourceUtils.loadAtPointInTime; import static google.registry.model.ofy.ObjectifyService.ofy; import com.google.appengine.tools.mapreduce.Mapper; @@ -28,7 +29,6 @@ import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Maps; import com.googlecode.objectify.Result; import google.registry.model.EppResource; -import google.registry.model.EppResourceUtils; import google.registry.model.contact.ContactResource; import google.registry.model.domain.DomainResource; import google.registry.model.host.HostResource; @@ -77,7 +77,7 @@ public final class RdeStagingMapper extends Mapper>() { @Override public Result apply(DateTime input) { - return EppResourceUtils.loadAtPointInTime(resource, input); + return loadAtPointInTime(resource, input); }})); // Convert resource to an XML fragment for each watermark/mode pair lazily and cache the result. @@ -167,7 +167,14 @@ public final class RdeStagingMapper extends Mapper domain = new DomainResource.Builder() .setRepoId("1-".concat(Ascii.toUpperCase(tld))) .setFullyQualifiedDomainName(label + "." + tld) - .setCurrentSponsorClientId("TheRegistrar") + .setPersistedCurrentSponsorClientId("TheRegistrar") .setCreationClientId("TheRegistrar") .setCreationTimeForTest(DateTime.parse("1999-04-03T22:00:00.0Z")) .setRegistrationExpirationTime(REGISTRATION_EXPIRATION_TIME) @@ -158,7 +157,7 @@ public class DomainTransferFlowTestCase new HostResource.Builder() .setRepoId("2-".concat(Ascii.toUpperCase(tld))) .setFullyQualifiedHostName("ns1." + label + "." + tld) - .setCurrentSponsorClientId("TheRegistrar") + .setPersistedCurrentSponsorClientId("TheRegistrar") .setCreationClientId("TheRegistrar") .setCreationTimeForTest(DateTime.parse("1999-04-03T22:00:00.0Z")) .setSuperordinateDomain(Key.create(domain)) @@ -220,12 +219,6 @@ public class DomainTransferFlowTestCase assertThat(transferData.getServerApproveEntities()).isEmpty(); } - protected void assertTransferFailed(HostResource resource) { - assertAboutEppResources().that(resource) - .doesNotHaveStatusValue(StatusValue.PENDING_TRANSFER).and() - .hasCurrentSponsorClientId("TheRegistrar"); - } - /** Adds a domain that has a pending transfer on it from TheRegistrar to NewRegistrar. */ protected void setupDomainWithPendingTransfer(String label, String tld) throws Exception { setupDomain(label, tld); diff --git a/javatests/google/registry/flows/domain/DomainTransferRejectFlowTest.java b/javatests/google/registry/flows/domain/DomainTransferRejectFlowTest.java index c0c90a299..2da17830b 100644 --- a/javatests/google/registry/flows/domain/DomainTransferRejectFlowTest.java +++ b/javatests/google/registry/flows/domain/DomainTransferRejectFlowTest.java @@ -84,7 +84,6 @@ public class DomainTransferRejectFlowTest // Transfer should have been rejected. Verify correct fields were set. domain = reloadResourceByForeignKey(); assertTransferFailed(domain, TransferStatus.CLIENT_REJECTED); - assertTransferFailed(reloadResourceAndCloneAtTime(subordinateHost, clock.nowUtc())); assertAboutDomains().that(domain) .hasRegistrationExpirationTime(originalExpirationTime).and() .hasLastTransferTimeNotEqualTo(clock.nowUtc()).and() diff --git a/javatests/google/registry/flows/domain/DomainTransferRequestFlowTest.java b/javatests/google/registry/flows/domain/DomainTransferRequestFlowTest.java index 27349d3ce..85d7f1f0e 100644 --- a/javatests/google/registry/flows/domain/DomainTransferRequestFlowTest.java +++ b/javatests/google/registry/flows/domain/DomainTransferRequestFlowTest.java @@ -24,7 +24,6 @@ import static google.registry.testing.DatastoreHelper.getPollMessages; import static google.registry.testing.DatastoreHelper.persistActiveContact; import static google.registry.testing.DatastoreHelper.persistResource; import static google.registry.testing.DomainResourceSubject.assertAboutDomains; -import static google.registry.testing.GenericEppResourceSubject.assertAboutEppResources; import static google.registry.testing.HistoryEntrySubject.assertAboutHistoryEntries; import static google.registry.testing.HostResourceSubject.assertAboutHosts; import static google.registry.util.DateTimeUtils.START_OF_TIME; @@ -64,7 +63,6 @@ import google.registry.model.domain.GracePeriod; import google.registry.model.domain.rgp.GracePeriodStatus; import google.registry.model.eppcommon.AuthInfo.PasswordAuth; import google.registry.model.eppcommon.StatusValue; -import google.registry.model.host.HostResource; import google.registry.model.poll.PendingActionNotificationResponse; import google.registry.model.poll.PollMessage; import google.registry.model.registrar.Registrar; @@ -126,12 +124,6 @@ public class DomainTransferRequestFlowTest .hasStatusValue(StatusValue.PENDING_TRANSFER); } - private void assertTransferRequested(HostResource host) throws Exception { - assertAboutEppResources().that(host) - .hasCurrentSponsorClientId("TheRegistrar").and() - .hasStatusValue(StatusValue.PENDING_TRANSFER); - } - private void assertTransferApproved(DomainResource domain) { DateTime afterAutoAck = clock.nowUtc().plus(Registry.get(domain.getTld()).getAutomaticTransferLength()); @@ -143,15 +135,6 @@ public class DomainTransferRequestFlowTest .doesNotHaveStatusValue(StatusValue.PENDING_TRANSFER); } - private void assertTransferApproved(HostResource host) { - DateTime afterAutoAck = - clock.nowUtc().plus(Registry.get(domain.getTld()).getAutomaticTransferLength()); - assertAboutHosts().that(host) - .hasCurrentSponsorClientId("NewRegistrar").and() - .hasLastTransferTime(afterAutoAck).and() - .doesNotHaveStatusValue(StatusValue.PENDING_TRANSFER); - } - /** * Runs a successful test. The extraExpectedBillingEvents parameter consists of cancellation * billing event builders that have had all of their attributes set except for the parent history @@ -183,7 +166,6 @@ public class DomainTransferRequestFlowTest int registrationYears = domain.getTransferData().getExtendedRegistrationYears(); subordinateHost = reloadResourceAndCloneAtTime(subordinateHost, clock.nowUtc()); assertTransferRequested(domain); - assertTransferRequested(subordinateHost); assertAboutDomains().that(domain) .hasPendingTransferExpirationTime(implicitTransferTime).and() .hasOneHistoryEntryEachOfTypes( @@ -252,8 +234,6 @@ public class DomainTransferRequestFlowTest null), transferBillingEvent)); assertTransferApproved(domainAfterAutomaticTransfer); - assertTransferApproved( - subordinateHost.cloneProjectedAtTime(implicitTransferTime)); // Two poll messages on the gaining registrar's side at the expected expiration time: a // (OneTime) transfer approved message, and an Autorenew poll message. diff --git a/javatests/google/registry/flows/host/HostDeleteFlowTest.java b/javatests/google/registry/flows/host/HostDeleteFlowTest.java index 4dfd0f509..5b534a65f 100644 --- a/javatests/google/registry/flows/host/HostDeleteFlowTest.java +++ b/javatests/google/registry/flows/host/HostDeleteFlowTest.java @@ -35,9 +35,14 @@ import google.registry.flows.exceptions.ResourceToDeleteIsReferencedException; import google.registry.flows.host.HostFlowUtils.HostNameNotLowerCaseException; import google.registry.flows.host.HostFlowUtils.HostNameNotNormalizedException; import google.registry.flows.host.HostFlowUtils.HostNameNotPunyCodedException; +import google.registry.model.domain.DomainResource; import google.registry.model.eppcommon.StatusValue; import google.registry.model.host.HostResource; +import google.registry.model.registry.Registry; import google.registry.model.reporting.HistoryEntry; +import google.registry.model.transfer.TransferData; +import google.registry.model.transfer.TransferStatus; +import org.joda.time.DateTime; import org.junit.Before; import org.junit.Test; @@ -52,7 +57,7 @@ public class HostDeleteFlowTest extends ResourceFlowTestCase exception) throws Exception { persistResource( - newHostResource(getUniqueIdFromCommand()).asBuilder() + newHostResource("ns1.example.tld").asBuilder() .setStatusValues(ImmutableSet.of(statusValue)) .build()); thrown.expect(exception); @@ -61,13 +66,13 @@ public class HostDeleteFlowTest extends ResourceFlowTestCaseThe transfer is from "TheRegistrar" to "NewRegistrar". + */ + private DomainResource createDomainWithServerApprovedTransfer(String domainName) { + DateTime now = clock.nowUtc(); + DateTime requestTime = now.minusDays(1).minus(Registry.DEFAULT_AUTOMATIC_TRANSFER_LENGTH); + DateTime transferExpirationTime = now.minusDays(1); + return newDomainResource(domainName).asBuilder() + .setPersistedCurrentSponsorClientId("TheRegistrar") + .addStatusValue(StatusValue.PENDING_TRANSFER) + .setTransferData(new TransferData.Builder() + .setTransferStatus(TransferStatus.PENDING) + .setGainingClientId("NewRegistrar") + .setTransferRequestTime(requestTime) + .setLosingClientId("TheRegistrar") + .setPendingTransferExpirationTime(transferExpirationTime) + .setExtendedRegistrationYears(1) + .build()) + .build(); + } + /** Alias for better readability. */ private String oldHostName() throws Exception { return getUniqueIdFromCommand(); @@ -149,8 +179,7 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase oldFkiAfterRename = - ForeignKeyIndex.load( - HostResource.class, oldHostName(), clock.nowUtc()); + ForeignKeyIndex.load(HostResource.class, oldHostName(), clock.nowUtc()); assertThat(oldFkiAfterRename).isNull(); } @@ -171,18 +200,40 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase192.0.2.22", "1080:0:0:0:8:800:200C:417A"); createTld("tld"); + DateTime now = clock.nowUtc(); + DateTime oneDayAgo = now.minusDays(1); DomainResource domain = persistResource(newDomainResource("example.tld") .asBuilder() .setSubordinateHosts(ImmutableSet.of(oldHostName())) + .setLastTransferTime(oneDayAgo) .build()); HostResource oldHost = persistActiveSubordinateHost(oldHostName(), domain); assertThat(domain.getSubordinateHosts()).containsExactly("ns1.example.tld"); HostResource renamedHost = doSuccessfulTest(); assertAboutHosts().that(renamedHost) .hasSuperordinateDomain(Key.create(domain)).and() - .hasLastSuperordinateChange(oldHost.getLastSuperordinateChange()); + .hasLastSuperordinateChange(oldHost.getLastSuperordinateChange()).and() + .hasPersistedCurrentSponsorClientId("TheRegistrar").and() + .hasLastTransferTime(oneDayAgo); DomainResource reloadedDomain = - ofy().load().entity(domain).now().cloneProjectedAtTime(clock.nowUtc()); + ofy().load().entity(domain).now().cloneProjectedAtTime(now); assertThat(reloadedDomain.getSubordinateHosts()).containsExactly("ns2.example.tld"); assertDnsTasksEnqueued("ns1.example.tld", "ns2.example.tld"); } @@ -231,7 +287,9 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase192.0.2.22", + null); + sessionMetadata.setClientId("TheRegistrar"); + createTld("tld"); + persistResource(newDomainResource("example.tld").asBuilder() + .setPersistedCurrentSponsorClientId("NewRegistar") + .build()); + HostResource host = persistActiveHost("ns1.example.foo"); + assertAboutHosts().that(host).hasPersistedCurrentSponsorClientId("TheRegistrar"); + + thrown.expect(HostDomainNotOwnedException.class); + runFlow(); + } + + @Test + public void testFailure_newSuperordinateWasTransferredToDifferentRegistrar() throws Exception { + setEppHostUpdateInput( + "ns1.example.foo", + "ns2.example.tld", + "192.0.2.22", + null); + sessionMetadata.setClientId("TheRegistrar"); + createTld("tld"); + // The domain will belong to NewRegistrar after cloneProjectedAtTime is called. + DomainResource domain = persistResource(createDomainWithServerApprovedTransfer("example.tld")); + assertAboutDomains().that(domain).hasPersistedCurrentSponsorClientId("TheRegistrar"); + HostResource host = persistActiveHost("ns1.example.foo"); + assertAboutHosts().that(host).hasPersistedCurrentSponsorClientId("TheRegistrar"); + + thrown.expect(HostDomainNotOwnedException.class); + runFlow(); + } + + @Test + public void testSuccess_newSuperordinateWasTransferredToCorrectRegistrar() throws Exception { + setEppHostUpdateInput( + "ns1.example.foo", + "ns2.example.tld", + "192.0.2.22", + null); + sessionMetadata.setClientId("NewRegistrar"); + createTld("tld"); + // The domain will belong to NewRegistrar after cloneProjectedAtTime is called. + DomainResource domain = persistResource(createDomainWithServerApprovedTransfer("example.tld")); + assertAboutDomains().that(domain).hasPersistedCurrentSponsorClientId("TheRegistrar"); + persistResource(newHostResource("ns1.example.foo").asBuilder() + .setPersistedCurrentSponsorClientId("NewRegistrar") + .build()); + + clock.advanceOneMilli(); + runFlowAssertResponse(readFile("host_update_response.xml")); + } + private void doFailingHostNameTest( String hostName, Class exception) throws Exception { @@ -941,6 +1141,19 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase element that contains the identifier of the registrar + // that created the domain name object. An OPTIONAL client attribute + // is used to specify the client that performed the operation. + // This will always be null for us since we track each registrar as a separate client. + assertThat(bean.getCrRr().getValue()).isEqualTo("LawyerCat"); + assertThat(bean.getCrRr().getClient()).isNull(); + + assertThat(bean.getName()).isEqualTo("ns1.love.foobar"); + + assertThat(bean.getRoid()).isEqualTo("2-roid"); + + assertThat(bean.getStatuses()).hasSize(2); + XjcHostStatusType status0 = bean.getStatuses().get(0); + assertThat(status0.getS()).isEqualTo(XjcHostStatusValueType.OK); + assertThat(status0.getValue()).isNull(); + assertThat(status0.getLang()).isEqualTo("en"); + + assertThat(bean.getUpDate()).isEqualTo(DateTime.parse("1920-01-01T00:00:00Z")); + + assertThat(bean.getUpRr().getValue()).isEqualTo("CeilingCat"); + assertThat(bean.getUpRr().getClient()).isNull(); + + // Values that should have been copied from the superordinate domain. + assertThat(bean.getClID()).isEqualTo("LeisureDog"); + assertThat(bean.getTrDate()).isEqualTo(DateTime.parse("2010-01-01T00:00:00Z")); + XjcHostStatusType status1 = bean.getStatuses().get(1); + assertThat(status1.getS()).isEqualTo(XjcHostStatusValueType.PENDING_TRANSFER); + assertThat(status1.getValue()).isNull(); + assertThat(status1.getLang()).isEqualTo("en"); + } + + @Test + public void testConvertExternalHost() throws Exception { + XjcRdeHost bean = HostResourceToXjcConverter.convertExternalHost( + new HostResource.Builder() + .setCreationClientId("LawyerCat") + .setCreationTimeForTest(DateTime.parse("1900-01-01T00:00:00Z")) + .setPersistedCurrentSponsorClientId("BusinessCat") .setFullyQualifiedHostName("ns1.love.lol") .setInetAddresses(ImmutableSet.of(InetAddresses.forString("127.0.0.1"))) .setLastTransferTime(DateTime.parse("1910-01-01T00:00:00Z")) @@ -95,7 +159,6 @@ public class HostResourceToXjcConverterTest { assertThat(bean.getStatuses()).hasSize(1); assertThat(bean.getStatuses().get(0).getS()).isEqualTo(XjcHostStatusValueType.OK); - assertThat(bean.getStatuses().get(0).getS().toString()).isEqualTo("OK"); assertThat(bean.getStatuses().get(0).getValue()).isNull(); assertThat(bean.getStatuses().get(0).getLang()).isEqualTo("en"); @@ -108,12 +171,12 @@ public class HostResourceToXjcConverterTest { } @Test - public void testConvertIpv6() throws Exception { - XjcRdeHost bean = HostResourceToXjcConverter.convertHost( + public void testConvertExternalHost_ipv6() throws Exception { + XjcRdeHost bean = HostResourceToXjcConverter.convertExternalHost( new HostResource.Builder() .setCreationClientId("LawyerCat") .setCreationTimeForTest(DateTime.parse("1900-01-01T00:00:00Z")) - .setCurrentSponsorClientId("BusinessCat") + .setPersistedCurrentSponsorClientId("BusinessCat") .setFullyQualifiedHostName("ns1.love.lol") .setInetAddresses(ImmutableSet.of(InetAddresses.forString("cafe::abba"))) .setLastTransferTime(DateTime.parse("1910-01-01T00:00:00Z")) @@ -130,11 +193,11 @@ public class HostResourceToXjcConverterTest { @Test public void testHostStatusValueIsInvalid() throws Exception { thrown.expect(IllegalArgumentException.class); - HostResourceToXjcConverter.convertHost( + HostResourceToXjcConverter.convertExternalHost( new HostResource.Builder() .setCreationClientId("LawyerCat") .setCreationTimeForTest(DateTime.parse("1900-01-01T00:00:00Z")) - .setCurrentSponsorClientId("BusinessCat") + .setPersistedCurrentSponsorClientId("BusinessCat") .setFullyQualifiedHostName("ns1.love.lol") .setInetAddresses(ImmutableSet.of(InetAddresses.forString("cafe::abba"))) .setLastTransferTime(DateTime.parse("1910-01-01T00:00:00Z")) @@ -148,11 +211,11 @@ public class HostResourceToXjcConverterTest { @Test public void testMarshal() throws Exception { // Bean! Bean! Bean! - XjcRdeHostElement bean = HostResourceToXjcConverter.convert( + XjcRdeHostElement bean = HostResourceToXjcConverter.convertExternal( new HostResource.Builder() .setCreationClientId("LawyerCat") .setCreationTimeForTest(DateTime.parse("1900-01-01T00:00:00Z")) - .setCurrentSponsorClientId("BusinessCat") + .setPersistedCurrentSponsorClientId("BusinessCat") .setFullyQualifiedHostName("ns1.love.lol") .setInetAddresses(ImmutableSet.of(InetAddresses.forString("cafe::abba"))) .setLastTransferTime(DateTime.parse("1910-01-01T00:00:00Z")) @@ -163,5 +226,4 @@ public class HostResourceToXjcConverterTest { .build()); marshalStrict(bean, new ByteArrayOutputStream(), UTF_8); } - } diff --git a/javatests/google/registry/rde/RdeFixtures.java b/javatests/google/registry/rde/RdeFixtures.java index 46d6f0259..f2386e835 100644 --- a/javatests/google/registry/rde/RdeFixtures.java +++ b/javatests/google/registry/rde/RdeFixtures.java @@ -90,7 +90,7 @@ final class RdeFixtures { makeContactResource(clock, "5372808-TRL", "bird or fiend!? i shrieked upstarting", "bog@cat.みんな"))))) .setCreationClientId("TheRegistrar") - .setCurrentSponsorClientId("TheRegistrar") + .setPersistedCurrentSponsorClientId("TheRegistrar") .setCreationTimeForTest(clock.nowUtc()) .setDsData(ImmutableSet.of(DelegationSignerData.create( 123, 200, 230, base16().decode("1234567890")))) @@ -194,7 +194,7 @@ final class RdeFixtures { .setRepoId(generateNewContactHostRoid()) .setEmailAddress(email) .setStatusValues(ImmutableSet.of(StatusValue.OK)) - .setCurrentSponsorClientId("GetTheeBack") + .setPersistedCurrentSponsorClientId("GetTheeBack") .setCreationClientId("GetTheeBack") .setCreationTimeForTest(clock.nowUtc()) .setInternationalizedPostalInfo(new PostalInfo.Builder() @@ -227,7 +227,7 @@ final class RdeFixtures { .setRepoId(generateNewContactHostRoid()) .setCreationClientId("LawyerCat") .setCreationTimeForTest(clock.nowUtc()) - .setCurrentSponsorClientId("BusinessCat") + .setPersistedCurrentSponsorClientId("BusinessCat") .setFullyQualifiedHostName(Idn.toASCII(fqhn)) .setInetAddresses(ImmutableSet.of(InetAddresses.forString(ip))) .setLastTransferTime(DateTime.parse("1910-01-01T00:00:00Z")) diff --git a/javatests/google/registry/rde/imports/RdeHostImportActionTest.java b/javatests/google/registry/rde/imports/RdeHostImportActionTest.java index b26b9d8a6..8ad0f5824 100644 --- a/javatests/google/registry/rde/imports/RdeHostImportActionTest.java +++ b/javatests/google/registry/rde/imports/RdeHostImportActionTest.java @@ -16,7 +16,6 @@ package google.registry.rde.imports; import static com.google.common.truth.Truth.assertThat; import static google.registry.model.ofy.ObjectifyService.ofy; -import static google.registry.testing.DatastoreHelper.createTld; import static google.registry.testing.DatastoreHelper.getHistoryEntries; import static google.registry.testing.DatastoreHelper.newHostResource; import static google.registry.testing.DatastoreHelper.persistResource; @@ -67,7 +66,6 @@ public class RdeHostImportActionTest extends MapreduceTestCaseabsent(), Optional.absent()); action = new RdeHostImportAction( @@ -106,12 +104,12 @@ public class RdeHostImportActionTest extends MapreduceTestCase hasCurrentSponsorClientId(String clientId) { + return hasValue( + clientId, + actual().getCurrentSponsorClientId(), + "has currentSponsorClientId"); + } } diff --git a/javatests/google/registry/testing/AbstractEppResourceSubject.java b/javatests/google/registry/testing/AbstractEppResourceSubject.java index 75b648142..0b514708f 100644 --- a/javatests/google/registry/testing/AbstractEppResourceSubject.java +++ b/javatests/google/registry/testing/AbstractEppResourceSubject.java @@ -172,11 +172,12 @@ abstract class AbstractEppResourceSubject "has lastEppUpdateClientId"); } - public And hasCurrentSponsorClientId(String clientId) { + + public And hasPersistedCurrentSponsorClientId(String clientId) { return hasValue( clientId, - actual().getCurrentSponsorClientId(), - "has currentSponsorClientId"); + actual().getPersistedCurrentSponsorClientId(), + "has persisted currentSponsorClientId"); } public And isActiveAt(DateTime time) { diff --git a/javatests/google/registry/testing/ContactResourceSubject.java b/javatests/google/registry/testing/ContactResourceSubject.java index 0991e63da..3fc7dbf0a 100644 --- a/javatests/google/registry/testing/ContactResourceSubject.java +++ b/javatests/google/registry/testing/ContactResourceSubject.java @@ -175,6 +175,14 @@ public final class ContactResourceSubject actual().getLastTransferTime(), "lastTransferTime"); } + + public And hasCurrentSponsorClientId(String clientId) { + return hasValue( + clientId, + actual().getCurrentSponsorClientId(), + "has currentSponsorClientId"); + } + public static DelegatedVerb assertAboutContacts() { return assertAbout(new SubjectFactory()); } diff --git a/javatests/google/registry/testing/DatastoreHelper.java b/javatests/google/registry/testing/DatastoreHelper.java index 037ff46cd..9c2963da9 100644 --- a/javatests/google/registry/testing/DatastoreHelper.java +++ b/javatests/google/registry/testing/DatastoreHelper.java @@ -116,7 +116,7 @@ public class DatastoreHelper { return new HostResource.Builder() .setFullyQualifiedHostName(hostName) .setCreationClientId("TheRegistrar") - .setCurrentSponsorClientId("TheRegistrar") + .setPersistedCurrentSponsorClientId("TheRegistrar") .setCreationTimeForTest(START_OF_TIME) .setRepoId(generateNewContactHostRoid()) .build(); @@ -146,7 +146,7 @@ public class DatastoreHelper { .setRepoId(repoId) .setFullyQualifiedDomainName(domainName) .setCreationClientId("TheRegistrar") - .setCurrentSponsorClientId("TheRegistrar") + .setPersistedCurrentSponsorClientId("TheRegistrar") .setCreationTimeForTest(START_OF_TIME) .setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("2fooBAR"))) .setRegistrant(contactKey) @@ -186,7 +186,7 @@ public class DatastoreHelper { return new DomainApplication.Builder() .setRepoId(repoId) .setFullyQualifiedDomainName(domainName) - .setCurrentSponsorClientId("TheRegistrar") + .setPersistedCurrentSponsorClientId("TheRegistrar") .setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("2fooBAR"))) .setRegistrant(contactKey) .setContacts(ImmutableSet.of( @@ -223,7 +223,7 @@ public class DatastoreHelper { .setRepoId(repoId) .setContactId(contactId) .setCreationClientId("TheRegistrar") - .setCurrentSponsorClientId("TheRegistrar") + .setPersistedCurrentSponsorClientId("TheRegistrar") .setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("2fooBAR"))) .setCreationTimeForTest(START_OF_TIME) .build(); @@ -486,7 +486,7 @@ public class DatastoreHelper { .build()); return persistResource( contact.asBuilder() - .setCurrentSponsorClientId("TheRegistrar") + .setPersistedCurrentSponsorClientId("TheRegistrar") .addStatusValue(StatusValue.PENDING_TRANSFER) .setTransferData(createTransferDataBuilder(requestTime, expirationTime) .setPendingTransferExpirationTime(now.plus(getContactAutomaticTransferLength())) @@ -571,7 +571,7 @@ public class DatastoreHelper { Builder transferDataBuilder = createTransferDataBuilder( requestTime, expirationTime, extendedRegistrationYears); return persistResource(domain.asBuilder() - .setCurrentSponsorClientId("TheRegistrar") + .setPersistedCurrentSponsorClientId("TheRegistrar") .addStatusValue(StatusValue.PENDING_TRANSFER) .setTransferData(transferDataBuilder .setPendingTransferExpirationTime(expirationTime) diff --git a/javatests/google/registry/testing/FullFieldsTestEntityHelper.java b/javatests/google/registry/testing/FullFieldsTestEntityHelper.java index daa0a3b65..eff412fb7 100644 --- a/javatests/google/registry/testing/FullFieldsTestEntityHelper.java +++ b/javatests/google/registry/testing/FullFieldsTestEntityHelper.java @@ -225,7 +225,7 @@ public final class FullFieldsTestEntityHelper { .setLastEppUpdateTime(DateTime.parse("2009-05-29T20:13:00Z")) .setCreationTimeForTest(DateTime.parse("2000-10-08T00:45:00Z")) .setRegistrationExpirationTime(DateTime.parse("2110-10-08T00:44:59Z")) - .setCurrentSponsorClientId(registrar.getClientId()) + .setPersistedCurrentSponsorClientId(registrar.getClientId()) .setStatusValues(ImmutableSet.of( StatusValue.CLIENT_DELETE_PROHIBITED, StatusValue.CLIENT_RENEW_PROHIBITED, diff --git a/javatests/google/registry/tools/GenerateAuctionDataCommandTest.java b/javatests/google/registry/tools/GenerateAuctionDataCommandTest.java index 7e7cb8a8d..9dc63dfd6 100644 --- a/javatests/google/registry/tools/GenerateAuctionDataCommandTest.java +++ b/javatests/google/registry/tools/GenerateAuctionDataCommandTest.java @@ -167,7 +167,7 @@ public class GenerateAuctionDataCommandTest extends CommandTestCase { createTld("xn--q9jyb4c"); domainApplication = persistResource(newDomainApplication("test-validate.xn--q9jyb4c") .asBuilder() - .setCurrentSponsorClientId("TheRegistrar") + .setPersistedCurrentSponsorClientId("TheRegistrar") .setEncodedSignedMarks(ImmutableList.of(EncodedSignedMark.create("base64", "garbage"))) .build()); command.tmchUtils = diff --git a/javatests/google/registry/whois/DomainWhoisResponseTest.java b/javatests/google/registry/whois/DomainWhoisResponseTest.java index f83cd3a5e..a458acba2 100644 --- a/javatests/google/registry/whois/DomainWhoisResponseTest.java +++ b/javatests/google/registry/whois/DomainWhoisResponseTest.java @@ -218,7 +218,7 @@ public class DomainWhoisResponseTest { .setLastEppUpdateTime(DateTime.parse("2009-05-29T20:13:00Z")) .setCreationTimeForTest(DateTime.parse("2000-10-08T00:45:00Z")) .setRegistrationExpirationTime(DateTime.parse("2010-10-08T00:44:59Z")) - .setCurrentSponsorClientId("NewRegistrar") + .setPersistedCurrentSponsorClientId("NewRegistrar") .setStatusValues(ImmutableSet.of( StatusValue.CLIENT_DELETE_PROHIBITED, StatusValue.CLIENT_RENEW_PROHIBITED, diff --git a/javatests/google/registry/whois/NameserverWhoisResponseTest.java b/javatests/google/registry/whois/NameserverWhoisResponseTest.java index 070050247..ef6e9ab01 100644 --- a/javatests/google/registry/whois/NameserverWhoisResponseTest.java +++ b/javatests/google/registry/whois/NameserverWhoisResponseTest.java @@ -61,7 +61,7 @@ public class NameserverWhoisResponseTest { hostResource1 = new HostResource.Builder() .setFullyQualifiedHostName("ns1.example.tld") - .setCurrentSponsorClientId("example") + .setPersistedCurrentSponsorClientId("example") .setInetAddresses(ImmutableSet.of( InetAddresses.forString("192.0.2.123"), InetAddresses.forString("2001:0DB8::1"))) @@ -70,7 +70,7 @@ public class NameserverWhoisResponseTest { hostResource2 = new HostResource.Builder() .setFullyQualifiedHostName("ns2.example.tld") - .setCurrentSponsorClientId("example") + .setPersistedCurrentSponsorClientId("example") .setInetAddresses(ImmutableSet.of( InetAddresses.forString("192.0.2.123"), InetAddresses.forString("2001:0DB8::1")))