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
This commit is contained in:
cgoldfeder 2017-03-10 10:05:26 -08:00 committed by Ben McIlwain
parent 1f000b94e6
commit 9174855a47
67 changed files with 970 additions and 471 deletions

View file

@ -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

View file

@ -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());

View file

@ -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.<R, B>resolvePendingTransfer(resource, transferStatus, now);
return builder
.setLastTransferTime(now)
.setCurrentSponsorClientId(resource.getTransferData().getGainingClientId())
.setPersistedCurrentSponsorClientId(resource.getTransferData().getGainingClientId())
.build();
}

View file

@ -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())

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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<DomainResource> 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))

View file

@ -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 =

View file

@ -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();

View file

@ -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();
}

View file

@ -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<DomainResource> 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<DomainResource> newSuperordinateDomainKey =
newSuperordinateDomain.isPresent() ? Key.create(newSuperordinateDomain.get()) : null;
Key<DomainResource> 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<ImmutableObject> 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<StatusValue> statusesToAdd = command.getInnerAdd().getStatusValues();
ImmutableSet<StatusValue> 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());
}
}

View file

@ -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}.
*
* <p>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();
}

View file

@ -207,7 +207,7 @@ public final class EppResourceUtils {
.setServerApproveAutorenewPollMessage(null)
.build())
.setLastTransferTime(transferData.getPendingTransferExpirationTime())
.setCurrentSponsorClientId(transferData.getGainingClientId());
.setPersistedCurrentSponsorClientId(transferData.getGainingClientId());
}
/**

View file

@ -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);

View file

@ -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<String> loadNameserverFullyQualifiedHostNames() {
return FluentIterable.from(ofy().load().keys(getNameservers()).values())

View file

@ -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.
*
* <p>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.
*
* <p>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

View file

@ -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<StatusValue> 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<ImmutableMap<String, Object>> remarks;

View file

@ -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()) {

View file

@ -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. */

View file

@ -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<EppResource, PendingDeposit,
// Skip prober data.
if (nullToEmpty(resource.getCreationClientId()).startsWith("prober-")
|| nullToEmpty(resource.getCurrentSponsorClientId()).startsWith("prober-")
|| nullToEmpty(resource.getPersistedCurrentSponsorClientId()).startsWith("prober-")
|| nullToEmpty(resource.getLastEppUpdateClientId()).startsWith("prober-")) {
return;
}
@ -110,7 +110,7 @@ public final class RdeStagingMapper extends Mapper<EppResource, PendingDeposit,
new Function<DateTime, Result<EppResource>>() {
@Override
public Result<EppResource> 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<EppResource, PendingDeposit,
cache.put(WatermarkModePair.create(watermark, RdeMode.THIN), result);
return result;
} else if (resource instanceof HostResource) {
result = Optional.of(marshaller.marshalHost((HostResource) resource));
HostResource host = (HostResource) resource;
result = Optional.of(host.isSubordinate()
? marshaller.marshalSubordinateHost(
host,
// Note that loadAtPointInTime() does cloneProjectedAtTime(watermark) for us.
loadAtPointInTime(
ofy().load().key(host.getSuperordinateDomain()).now(), watermark).now())
: marshaller.marshalExternalHost(host));
cache.put(WatermarkModePair.create(watermark, RdeMode.FULL), result);
cache.put(WatermarkModePair.create(watermark, RdeMode.THIN), result);
return result;

View file

@ -98,7 +98,7 @@ final class XjcToContactResourceConverter extends XjcToEppResourceConverter {
.setInternationalizedPostalInfo(
getPostalInfoOfType(contact.getPostalInfos(), XjcContactPostalInfoEnumType.INT))
.setContactId(contact.getId())
.setCurrentSponsorClientId(contact.getClID())
.setPersistedCurrentSponsorClientId(contact.getClID())
.setCreationClientId(contact.getCrRr() == null ? null : contact.getCrRr().getValue())
.setLastEppUpdateClientId(contact.getUpRr() == null ? null : contact.getUpRr().getValue())
.setCreationTime(contact.getCrDate())

View file

@ -189,7 +189,7 @@ final class XjcToDomainResourceConverter extends XjcToEppResourceConverter {
.setFullyQualifiedDomainName(canonicalizeDomainName(domain.getName()))
.setRepoId(domain.getRoid())
.setIdnTableName(domain.getIdnTableId())
.setCurrentSponsorClientId(domain.getClID())
.setPersistedCurrentSponsorClientId(domain.getClID())
.setCreationClientId(domain.getCrRr().getValue())
.setCreationTime(domain.getCrDate())
.setAutorenewPollMessage(Key.create(autoRenewPollMessage))

View file

@ -14,7 +14,7 @@
package google.registry.rde.imports;
import static com.google.common.base.Predicates.equalTo;
import static com.google.common.base.Predicates.in;
import static com.google.common.base.Predicates.not;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.rde.imports.RdeImportUtils.generateTridForImport;
@ -56,6 +56,9 @@ public class XjcToHostResourceConverter extends XjcToEppResourceConverter {
};
static HostResource convert(XjcRdeHost host) {
// TODO(b/35384052): Handle subordinate hosts correctly by setting superordinateDomaina and
// lastSuperordinateChange fields.
// First create and save history entry
ofy().save().entity(
new HistoryEntry.Builder()
@ -72,7 +75,7 @@ public class XjcToHostResourceConverter extends XjcToEppResourceConverter {
return new HostResource.Builder()
.setFullyQualifiedHostName(canonicalizeDomainName(host.getName()))
.setRepoId(host.getRoid())
.setCurrentSponsorClientId(host.getClID())
.setPersistedCurrentSponsorClientId(host.getClID())
.setLastTransferTime(host.getTrDate())
.setCreationTime(host.getCrDate())
.setLastEppUpdateTime(host.getUpDate())
@ -82,7 +85,8 @@ public class XjcToHostResourceConverter extends XjcToEppResourceConverter {
FluentIterable.from(host.getStatuses())
.transform(STATUS_VALUE_CONVERTER)
// LINKED is implicit and should not be imported onto the new host.
.filter(not(equalTo(StatusValue.LINKED)))
// PENDING_TRANSFER is a property of the superordinate host.
.filter(not(in(ImmutableSet.of(StatusValue.LINKED, StatusValue.PENDING_TRANSFER))))
.toSet())
.setInetAddresses(ImmutableSet.copyOf(Lists.transform(host.getAddrs(), ADDR_CONVERTER)))
.build();

View file

@ -14,6 +14,7 @@
package google.registry.tools;
import static google.registry.model.EppResourceUtils.loadAtPointInTime;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.registry.Registries.assertTldExists;
import static java.nio.charset.StandardCharsets.UTF_8;
@ -132,7 +133,14 @@ final class GenerateEscrowDepositCommand implements RemoteApiCommand {
}
frag = marshaller.marshalDomain(domain, mode);
} else if (resource instanceof HostResource) {
frag = marshaller.marshalHost((HostResource) resource);
HostResource host = (HostResource) resource;
frag = host.isSubordinate()
? marshaller.marshalSubordinateHost(
host,
// Note that loadAtPointInTime() does cloneProjectedAtTime(watermark) for us.
loadAtPointInTime(
ofy().load().key(host.getSuperordinateDomain()).now(), watermark).now())
: marshaller.marshalExternalHost(host);
} else {
continue; // Surprise polymorphic entities, e.g. DomainApplication.
}

View file

@ -15,6 +15,7 @@
package google.registry.whois;
import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.model.ofy.ObjectifyService.ofy;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
@ -46,7 +47,13 @@ final class NameserverWhoisResponse extends WhoisResponseImpl {
BasicEmitter emitter = new BasicEmitter();
for (int i = 0; i < hosts.size(); i++) {
HostResource host = hosts.get(i);
Registrar registrar = getRegistrar(host.getCurrentSponsorClientId());
String clientId =
host.isSubordinate()
? ofy().load().key(host.getSuperordinateDomain()).now()
.cloneProjectedAtTime(getTimestamp())
.getCurrentSponsorClientId()
: host.getPersistedCurrentSponsorClientId();
Registrar registrar = getRegistrar(clientId);
emitter
.emitField("Server Name", maybeFormatHostname(
host.getFullyQualifiedHostName(), preferUnicode))

View file

@ -74,7 +74,7 @@ public class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, C
.setPhoneNumber("+1.7035555556")
.build())
.setEmailAddress("jdoe@example.com")
.setCurrentSponsorClientId("TheRegistrar")
.setPersistedCurrentSponsorClientId("TheRegistrar")
.setCreationClientId("NewRegistrar")
.setLastEppUpdateClientId("NewRegistrar")
.setCreationTimeForTest(DateTime.parse("1999-04-03T22:00:00.0Z"))

View file

@ -93,7 +93,7 @@ public class DomainApplicationInfoFlowTest
.setRepoId("123-TLD")
.setFullyQualifiedDomainName("example.tld")
.setPhase(LaunchPhase.SUNRUSH)
.setCurrentSponsorClientId("NewRegistrar")
.setPersistedCurrentSponsorClientId("NewRegistrar")
.setCreationClientId("TheRegistrar")
.setLastEppUpdateClientId("NewRegistrar")
.setCreationTimeForTest(DateTime.parse("1999-04-03T22:00:00.0Z"))

View file

@ -91,7 +91,7 @@ public class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Dom
domain = persistResource(new DomainResource.Builder()
.setFullyQualifiedDomainName(domainName)
.setRepoId("2FF-TLD")
.setCurrentSponsorClientId("NewRegistrar")
.setPersistedCurrentSponsorClientId("NewRegistrar")
.setCreationClientId("TheRegistrar")
.setLastEppUpdateClientId("NewRegistrar")
.setCreationTimeForTest(DateTime.parse("1999-04-03T22:00:00.0Z"))

View file

@ -16,7 +16,6 @@ package google.registry.flows.domain;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.testing.DatastoreHelper.assertBillingEventsForResource;
import static google.registry.testing.DatastoreHelper.createTld;
@ -27,7 +26,6 @@ import static google.registry.testing.DatastoreHelper.getPollMessages;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.DomainResourceSubject.assertAboutDomains;
import static google.registry.testing.HistoryEntrySubject.assertAboutHistoryEntries;
import static google.registry.testing.HostResourceSubject.assertAboutHosts;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.joda.money.CurrencyUnit.USD;
@ -55,7 +53,6 @@ import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppcommon.Trid;
import google.registry.model.host.HostResource;
import google.registry.model.poll.PendingActionNotificationResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.registrar.Registrar;
@ -107,13 +104,6 @@ public class DomainTransferApproveFlowTest
.doesNotHaveStatusValue(StatusValue.PENDING_TRANSFER);
}
private void assertTransferApproved(HostResource host) {
assertAboutHosts().that(host)
.hasCurrentSponsorClientId("NewRegistrar").and()
.hasLastTransferTime(clock.nowUtc()).and()
.doesNotHaveStatusValue(StatusValue.PENDING_TRANSFER);
}
private void setEppLoader(String commandFilename) {
setEppInput(commandFilename);
// Replace the ROID in the xml file with the one generated in our test.
@ -161,7 +151,6 @@ public class DomainTransferApproveFlowTest
assertAboutDomains().that(domain).hasRegistrationExpirationTime(expectedExpirationTime);
assertThat(ofy().load().key(domain.getAutorenewBillingEvent()).now().getEventTime())
.isEqualTo(expectedExpirationTime);
assertTransferApproved(reloadResourceAndCloneAtTime(subordinateHost, clock.nowUtc()));
// We expect three billing events: one for the transfer, a closed autorenew for the losing
// client and an open autorenew for the gaining client that begins at the new expiration time.
BillingEvent.OneTime transferBillingEvent = new BillingEvent.OneTime.Builder()
@ -287,60 +276,6 @@ public class DomainTransferApproveFlowTest
"domain_transfer_approve_response_net.xml");
}
@Test
public void testSuccess_lastTransferTime_reflectedOnSubordinateHost() throws Exception {
domain = reloadResourceByForeignKey();
// Set an older last transfer time on the subordinate host.
subordinateHost = persistResource(
subordinateHost.asBuilder()
.setLastTransferTime(DateTime.parse("2000-02-03T22:00:00.0Z"))
.build());
doSuccessfulTest("tld", "domain_transfer_approve.xml", "domain_transfer_approve_response.xml");
subordinateHost = loadByForeignKey(
HostResource.class, subordinateHost.getFullyQualifiedHostName(), clock.nowUtc());
// Verify that the host's last transfer time is now that of when the superordinate domain was
// transferred.
assertThat(subordinateHost.getLastTransferTime()).isEqualTo(clock.nowUtc());
}
@Test
public void testSuccess_lastTransferTime_overridesExistingOnSubordinateHost() throws Exception {
domain = reloadResourceByForeignKey();
// Set an older last transfer time on the subordinate host.
subordinateHost = persistResource(
subordinateHost.asBuilder()
.setLastTransferTime(DateTime.parse("2000-02-03T22:00:00.0Z"))
.setLastSuperordinateChange(DateTime.parse("2000-03-03T22:00:00.0Z"))
.build());
doSuccessfulTest("tld", "domain_transfer_approve.xml", "domain_transfer_approve_response.xml");
subordinateHost = loadByForeignKey(
HostResource.class, subordinateHost.getFullyQualifiedHostName(), clock.nowUtc());
// Verify that the host's last transfer time is now that of when the superordinate domain was
// transferred.
assertThat(subordinateHost.getLastTransferTime()).isEqualTo(clock.nowUtc());
}
@Test
public void testSuccess_lastTransferTime_overridesExistingOnSubordinateHostWithNullTransferTime()
throws Exception {
domain = reloadResourceByForeignKey();
// Set an older last transfer time on the subordinate host.
subordinateHost = persistResource(
subordinateHost.asBuilder()
.setLastTransferTime(null)
.setLastSuperordinateChange(DateTime.parse("2000-03-03T22:00:00.0Z"))
.build());
doSuccessfulTest("tld", "domain_transfer_approve.xml", "domain_transfer_approve_response.xml");
subordinateHost = loadByForeignKey(
HostResource.class, subordinateHost.getFullyQualifiedHostName(), clock.nowUtc());
// Verify that the host's last transfer time is now that of when the superordinate domain was
// transferred.
assertThat(subordinateHost.getLastTransferTime()).isEqualTo(clock.nowUtc());
}
@Test
public void testSuccess_domainAuthInfo() throws Exception {
doSuccessfulTest(

View file

@ -113,7 +113,6 @@ public class DomainTransferCancelFlowTest
assertAboutDomains().that(domain)
.hasRegistrationExpirationTime(originalExpirationTime).and()
.hasLastTransferTimeNotEqualTo(clock.nowUtc());
assertTransferFailed(reloadResourceAndCloneAtTime(subordinateHost, clock.nowUtc()));
assertAboutDomains().that(domain).hasOneHistoryEntryEachOfTypes(
HistoryEntry.Type.DOMAIN_CREATE,
HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST,

View file

@ -24,7 +24,6 @@ import static google.registry.testing.DatastoreHelper.persistActiveContact;
import static google.registry.testing.DatastoreHelper.persistDomainWithPendingTransfer;
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.util.DateTimeUtils.END_OF_TIME;
import com.google.common.base.Ascii;
@ -113,7 +112,7 @@ public class DomainTransferFlowTestCase<F extends Flow, R extends EppResource>
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<F extends Flow, R extends EppResource>
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<F extends Flow, R extends EppResource>
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);

View file

@ -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()

View file

@ -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.

View file

@ -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<HostDeleteFlow, Hos
private void doFailingStatusTest(StatusValue statusValue, Class<? extends Exception> 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 ResourceFlowTestCase<HostDeleteFlow, Hos
@Test
public void testDryRun() throws Exception {
persistActiveHost(getUniqueIdFromCommand());
persistActiveHost("ns1.example.tld");
dryRunFlowAssertResponse(readFile("host_delete_response.xml"));
}
@Test
public void testSuccess() throws Exception {
persistActiveHost(getUniqueIdFromCommand());
persistActiveHost("ns1.example.tld");
clock.advanceOneMilli();
assertTransactionalFlow(true);
runFlowAssertResponse(readFile("host_delete_response.xml"));
@ -83,18 +88,14 @@ public class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, Hos
@Test
public void testFailure_neverExisted() throws Exception {
thrown.expect(
ResourceDoesNotExistException.class,
String.format("(%s)", getUniqueIdFromCommand()));
thrown.expect(ResourceDoesNotExistException.class, "(ns1.example.tld)");
runFlow();
}
@Test
public void testFailure_existedButWasDeleted() throws Exception {
persistDeletedHost(getUniqueIdFromCommand(), clock.nowUtc().minusDays(1));
thrown.expect(
ResourceDoesNotExistException.class,
String.format("(%s)", getUniqueIdFromCommand()));
persistDeletedHost("ns1.example.tld", clock.nowUtc().minusDays(1));
thrown.expect(ResourceDoesNotExistException.class, "(ns1.example.tld)");
runFlow();
}
@ -119,7 +120,7 @@ public class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, Hos
@Test
public void testFailure_unauthorizedClient() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
persistActiveHost(getUniqueIdFromCommand());
persistActiveHost("ns1.example.tld");
thrown.expect(ResourceNotOwnedException.class);
runFlow();
}
@ -127,7 +128,7 @@ public class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, Hos
@Test
public void testSuccess_superuserUnauthorizedClient() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
persistActiveHost(getUniqueIdFromCommand());
persistActiveHost("ns1.example.tld");
clock.advanceOneMilli();
runFlowAssertResponse(
CommitMode.LIVE, UserPrivileges.SUPERUSER, readFile("host_delete_response.xml"));
@ -141,12 +142,104 @@ public class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, Hos
assertNoDnsTasksEnqueued();
}
@Test
public void testSuccess_authorizedClientReadFromSuperordinate() throws Exception {
sessionMetadata.setClientId("TheRegistrar");
createTld("tld");
DomainResource domain = persistResource(
newDomainResource("example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("TheRegistrar")
.build());
persistResource(
newHostResource("ns1.example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("NewRegistrar") // Shouldn't hurt.
.setSuperordinateDomain(Key.create(domain))
.build());
clock.advanceOneMilli();
runFlowAssertResponse(readFile("host_delete_response.xml"));
}
@Test
public void testFailure_unauthorizedClientReadFromSuperordinate() throws Exception {
sessionMetadata.setClientId("TheRegistrar");
createTld("tld");
DomainResource domain = persistResource(
newDomainResource("example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("NewRegistrar")
.build());
persistResource(
newHostResource("ns1.example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("TheRegistrar") // Shouldn't help.
.setSuperordinateDomain(Key.create(domain))
.build());
thrown.expect(ResourceNotOwnedException.class);
runFlow();
}
@Test
public void testSuccess_authorizedClientReadFromTransferredSuperordinate() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
createTld("tld");
// Setup a transfer that should have been server approved a day ago.
DateTime now = clock.nowUtc();
DateTime requestTime = now.minusDays(1).minus(Registry.DEFAULT_AUTOMATIC_TRANSFER_LENGTH);
DateTime transferExpirationTime = now.minusDays(1);
DomainResource domain = persistResource(newDomainResource("example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("NewRegistrar") // Shouldn't hurt.
.addStatusValue(StatusValue.PENDING_TRANSFER)
.setTransferData(new TransferData.Builder()
.setTransferStatus(TransferStatus.PENDING)
.setGainingClientId("NewRegistrar")
.setTransferRequestTime(requestTime)
.setLosingClientId("TheRegistrar")
.setPendingTransferExpirationTime(transferExpirationTime)
.setExtendedRegistrationYears(1)
.build())
.build());
persistResource(
newHostResource("ns1.example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("TheRegistrar") // Shouldn't hurt.
.setSuperordinateDomain(Key.create(domain))
.build());
clock.advanceOneMilli();
runFlowAssertResponse(readFile("host_delete_response.xml"));
}
@Test
public void testFailure_unauthorizedClientReadFromTransferredSuperordinate() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
createTld("tld");
// Setup a transfer that should have been server approved a day ago.
DateTime now = clock.nowUtc();
DateTime requestTime = now.minusDays(1).minus(Registry.DEFAULT_AUTOMATIC_TRANSFER_LENGTH);
DateTime transferExpirationTime = now.minusDays(1);
DomainResource domain = persistResource(newDomainResource("example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("NewRegistrar") // Shouldn't help.
.addStatusValue(StatusValue.PENDING_TRANSFER)
.setTransferData(new TransferData.Builder()
.setTransferStatus(TransferStatus.PENDING)
.setGainingClientId("TheRegistrar")
.setTransferRequestTime(requestTime)
.setLosingClientId("NewRegistrar")
.setPendingTransferExpirationTime(transferExpirationTime)
.setExtendedRegistrationYears(1)
.build())
.build());
persistResource(
newHostResource("ns1.example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("NewRegistrar") // Shouldn't help.
.setSuperordinateDomain(Key.create(domain))
.build());
thrown.expect(ResourceNotOwnedException.class);
runFlow();
}
@Test
public void testFailure_failfastWhenLinkedToDomain() throws Exception {
createTld("tld");
persistResource(newDomainResource("example.tld").asBuilder()
.setNameservers(ImmutableSet.of(
Key.create(persistActiveHost(getUniqueIdFromCommand()))))
Key.create(persistActiveHost("ns1.example.tld"))))
.build());
thrown.expect(ResourceToDeleteIsReferencedException.class);
runFlow();
@ -157,7 +250,7 @@ public class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, Hos
createTld("tld");
persistResource(newDomainApplication("example.tld").asBuilder()
.setNameservers(ImmutableSet.of(
Key.create(persistActiveHost(getUniqueIdFromCommand()))))
Key.create(persistActiveHost("ns1.example.tld"))))
.build());
thrown.expect(ResourceToDeleteIsReferencedException.class);
runFlow();

View file

@ -53,14 +53,14 @@ public class HostInfoFlowTest extends ResourceFlowTestCase<HostInfoFlow, HostRes
new HostResource.Builder()
.setFullyQualifiedHostName(getUniqueIdFromCommand())
.setRepoId("1FF-FOOBAR")
.setCurrentSponsorClientId("my sponsor")
.setPersistedCurrentSponsorClientId("my sponsor")
.setStatusValues(
ImmutableSet.of(StatusValue.CLIENT_UPDATE_PROHIBITED))
.setInetAddresses(ImmutableSet.of(
InetAddresses.forString("192.0.2.2"),
InetAddresses.forString("1080:0:0:0:8:800:200C:417A"),
InetAddresses.forString("192.0.2.29")))
.setCurrentSponsorClientId("TheRegistrar")
.setPersistedCurrentSponsorClientId("TheRegistrar")
.setCreationClientId("NewRegistrar")
.setLastEppUpdateClientId("NewRegistrar")
.setCreationTimeForTest(DateTime.parse("1999-04-03T22:00:00.0Z"))
@ -105,7 +105,7 @@ public class HostInfoFlowTest extends ResourceFlowTestCase<HostInfoFlow, HostRes
newDomainResource("parent.foobar").asBuilder()
.setRepoId("BEEF-FOOBAR")
.setLastTransferTime(domainTransferTime)
.setCurrentSponsorClientId("superclientid")
.setPersistedCurrentSponsorClientId("superclientid")
.build());
persistResource(
persistHostResource().asBuilder()

View file

@ -29,6 +29,7 @@ import static google.registry.testing.DatastoreHelper.persistActiveHost;
import static google.registry.testing.DatastoreHelper.persistActiveSubordinateHost;
import static google.registry.testing.DatastoreHelper.persistDeletedHost;
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;
@ -37,6 +38,7 @@ import static google.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued;
import static google.registry.testing.TaskQueueHelper.assertTasksEnqueued;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.InetAddresses;
@ -49,9 +51,11 @@ import google.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
import google.registry.flows.ResourceFlowUtils.StatusNotClientSettableException;
import google.registry.flows.exceptions.ResourceHasClientUpdateProhibitedException;
import google.registry.flows.exceptions.ResourceStatusProhibitsOperationException;
import google.registry.flows.host.HostFlowUtils.HostDomainNotOwnedException;
import google.registry.flows.host.HostFlowUtils.HostNameNotLowerCaseException;
import google.registry.flows.host.HostFlowUtils.HostNameNotNormalizedException;
import google.registry.flows.host.HostFlowUtils.HostNameNotPunyCodedException;
import google.registry.flows.host.HostFlowUtils.HostNameTooLongException;
import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException;
import google.registry.flows.host.HostFlowUtils.InvalidHostNameException;
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException;
@ -64,7 +68,10 @@ import google.registry.model.domain.DomainResource;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource;
import google.registry.model.index.ForeignKeyIndex;
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 google.registry.testing.TaskQueueHelper.TaskMatcher;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
@ -94,6 +101,29 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
createTld("xn--q9jyb4c");
}
/**
* Setup a domain with a transfer that should have been server approved a day ago.
*
* <p>The 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<HostUpdateFlow, Hos
assertThat(oldFkiBeforeRename.getResourceKey()).isEqualTo(Key.create(renamedHost));
assertThat(oldFkiBeforeRename.getDeletionTime()).isEqualTo(clock.nowUtc());
ForeignKeyIndex<HostResource> 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 ResourceFlowTestCase<HostUpdateFlow, Hos
}
@Test
public void testSuccess_nameUnchanged() throws Exception {
public void testSuccess_nameUnchanged_superordinateDomainNeverTransferred() throws Exception {
setEppInput("host_update_name_unchanged.xml");
createTld("tld");
DomainResource domain = persistActiveDomain("example.tld");
HostResource oldHost = persistActiveSubordinateHost(oldHostName(), domain);
clock.advanceOneMilli();
runFlowAssertResponse(readFile("host_update_response.xml"));
// The example xml doesn't do a host rename, so reloading the host should work.
assertAboutHosts().that(reloadResourceByForeignKey())
.hasLastSuperordinateChange(oldHost.getLastSuperordinateChange()).and()
.hasSuperordinateDomain(Key.create(domain)).and()
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(null).and()
.hasOnlyOneHistoryEntryWhich()
.hasType(HistoryEntry.Type.HOST_UPDATE);
assertDnsTasksEnqueued("ns1.example.tld");
}
@Test
public void testSuccess_nameUnchanged_superordinateDomainWasTransferred() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
setEppInput("host_update_name_unchanged.xml");
createTld("tld");
// Create a domain that will belong to NewRegistrar after cloneProjectedAtTime is called.
DomainResource domain = persistResource(createDomainWithServerApprovedTransfer("example.tld"));
HostResource oldHost = persistActiveSubordinateHost(oldHostName(), domain);
clock.advanceOneMilli();
runFlowAssertResponse(readFile("host_update_response.xml"));
// The example xml doesn't do a host rename, so reloading the host should work.
assertAboutHosts().that(reloadResourceByForeignKey())
.hasLastSuperordinateChange(oldHost.getLastSuperordinateChange()).and()
.hasSuperordinateDomain(Key.create(domain)).and()
.hasPersistedCurrentSponsorClientId("NewRegistrar").and()
.hasLastTransferTime(domain.getTransferData().getPendingTransferExpirationTime()).and()
.hasOnlyOneHistoryEntryWhich()
.hasType(HistoryEntry.Type.HOST_UPDATE);
assertDnsTasksEnqueued("ns1.example.tld");
@ -196,18 +247,23 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
"<host:addr ip=\"v4\">192.0.2.22</host:addr>",
"<host:addr ip=\"v6\">1080:0:0:0:8:800:200C:417A</host:addr>");
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 ResourceFlowTestCase<HostUpdateFlow, Hos
DateTime now = clock.nowUtc();
assertAboutHosts().that(renamedHost)
.hasSuperordinateDomain(Key.create(example)).and()
.hasLastSuperordinateChange(now);
.hasLastSuperordinateChange(now).and()
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(null);
assertThat(ofy().load().entity(foo).now().cloneProjectedAtTime(now).getSubordinateHosts())
.isEmpty();
assertThat(ofy().load().entity(example).now().cloneProjectedAtTime(now).getSubordinateHosts())
@ -252,15 +310,16 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
.setSubordinateHosts(ImmutableSet.of(oldHostName()))
.build());
DomainResource tldDomain = persistActiveDomain("example.tld");
HostResource oldHost = persistActiveSubordinateHost(oldHostName(), fooDomain);
assertThat(oldHost.getCurrentSponsorClientId()).isEqualTo("TheRegistrar");
persistActiveSubordinateHost(oldHostName(), fooDomain);
assertThat(fooDomain.getSubordinateHosts()).containsExactly("ns1.example.foo");
assertThat(tldDomain.getSubordinateHosts()).isEmpty();
HostResource renamedHost = doSuccessfulTest();
DateTime now = clock.nowUtc();
assertAboutHosts().that(renamedHost)
.hasSuperordinateDomain(Key.create(tldDomain)).and()
.hasLastSuperordinateChange(now);
.hasLastSuperordinateChange(now).and()
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(null);
DomainResource reloadedFooDomain =
ofy().load().entity(fooDomain).now().cloneProjectedAtTime(now);
assertThat(reloadedFooDomain.getSubordinateHosts()).isEmpty();
@ -268,12 +327,6 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
ofy().load().entity(tldDomain).now().cloneProjectedAtTime(now);
assertThat(reloadedTldDomain.getSubordinateHosts()).containsExactly("ns2.example.tld");
assertDnsTasksEnqueued("ns1.example.foo", "ns2.example.tld");
// Ensure that the client id is read off the domain because this is a subordinate host now.
persistResource(
tldDomain.asBuilder().setCurrentSponsorClientId("it_should_be_this").build());
assertThat(
renamedHost.cloneProjectedAtTime(clock.nowUtc().plusMinutes(1)).getCurrentSponsorClientId())
.isEqualTo("it_should_be_this");
}
@Test
@ -288,18 +341,21 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
.setSubordinateHosts(ImmutableSet.of(oldHostName()))
.build());
assertThat(domain.getCurrentSponsorClientId()).isEqualTo("TheRegistrar");
DateTime oneDayAgo = clock.nowUtc().minusDays(1);
HostResource oldHost = persistResource(
persistActiveSubordinateHost(oldHostName(), domain).asBuilder()
.setCurrentSponsorClientId("ClientThatShouldBeSupersededByDomainClient")
.setPersistedCurrentSponsorClientId("ClientThatShouldBeSupersededByDomainClient")
.setLastTransferTime(oneDayAgo)
.build());
assertThat(oldHost.isSubordinate()).isTrue();
assertThat(domain.getSubordinateHosts()).containsExactly("ns1.example.foo");
HostResource renamedHost = doSuccessfulTest();
assertAboutHosts().that(renamedHost)
// Ensure that the client id is copied off of the superordinate domain.
.hasCurrentSponsorClientId("TheRegistrar").and()
.hasSuperordinateDomain(null).and()
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(oneDayAgo).and()
.hasLastSuperordinateChange(clock.nowUtc());
assertThat(renamedHost.getLastTransferTime()).isEqualTo(oneDayAgo);
DomainResource reloadedDomain =
ofy().load().entity(domain).now().cloneProjectedAtTime(clock.nowUtc());
assertThat(reloadedDomain.getSubordinateHosts()).isEmpty();
@ -315,23 +371,18 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
null);
createTld("tld");
DomainResource domain = persistActiveDomain("example.tld");
HostResource oldHost = persistActiveHost(oldHostName());
assertThat(oldHost.getCurrentSponsorClientId()).isEqualTo("TheRegistrar");
persistActiveHost(oldHostName());
assertThat(domain.getSubordinateHosts()).isEmpty();
HostResource renamedHost = doSuccessfulTest();
DateTime now = clock.nowUtc();
assertAboutHosts().that(renamedHost)
.hasSuperordinateDomain(Key.create(domain)).and()
.hasLastSuperordinateChange(now);
.hasLastSuperordinateChange(now).and()
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(null);
assertThat(ofy().load().entity(domain).now().cloneProjectedAtTime(now).getSubordinateHosts())
.containsExactly("ns2.example.tld");
assertDnsTasksEnqueued("ns2.example.tld");
// Ensure that the client id is read off the domain because this is a subordinate host now.
persistResource(
domain.asBuilder().setCurrentSponsorClientId("it_should_be_this").build());
assertThat(
renamedHost.cloneProjectedAtTime(now.plusMinutes(1)).getCurrentSponsorClientId())
.isEqualTo("it_should_be_this");
}
@Test
@ -341,12 +392,13 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
"ns2.example.tld",
null,
null);
HostResource oldHost = persistActiveHost(oldHostName());
assertThat(oldHost.getCurrentSponsorClientId()).isEqualTo("TheRegistrar");
persistActiveHost(oldHostName());
HostResource renamedHost = doSuccessfulTest();
assertAboutHosts().that(renamedHost)
.hasSuperordinateDomain(null).and()
.hasLastSuperordinateChange(null);
.hasLastSuperordinateChange(null).and()
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(null);
assertNoDnsTasksEnqueued();
}
@ -363,6 +415,8 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
UserPrivileges.SUPERUSER,
readFile("host_update_response.xml"));
assertAboutHosts().that(reloadResourceByForeignKey())
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(null).and()
.hasStatusValue(StatusValue.CLIENT_UPDATE_PROHIBITED).and()
.hasStatusValue(StatusValue.SERVER_UPDATE_PROHIBITED);
}
@ -398,7 +452,9 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
.build());
clock.advanceOneMilli();
HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.getLastTransferTime()).isEqualTo(lastTransferTime);
assertAboutHosts().that(renamedHost)
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(lastTransferTime);
}
@Test
@ -429,7 +485,9 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
persistResource(
domain.asBuilder().setSubordinateHosts(ImmutableSet.of(oldHostName())).build());
HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.getLastTransferTime()).isEqualTo(lastTransferTime);
assertAboutHosts().that(renamedHost)
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(lastTransferTime);
}
@Test
@ -461,7 +519,9 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
.build());
clock.advanceOneMilli();
HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.getLastTransferTime()).isEqualTo(lastTransferTime);
assertAboutHosts().that(renamedHost)
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(lastTransferTime);
}
@Test
@ -495,7 +555,9 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
.build());
clock.advanceOneMilli();
HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.getLastTransferTime()).isEqualTo(lastTransferTime);
assertAboutHosts().that(renamedHost)
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(lastTransferTime);
}
@Test
@ -524,7 +586,9 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
persistResource(
foo.asBuilder().setSubordinateHosts(ImmutableSet.of(oldHostName())).build());
HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.getLastTransferTime()).isNull();
assertAboutHosts().that(renamedHost)
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(null);
}
@Test
@ -555,9 +619,10 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
.build());
// The last transfer time should be what was on the superordinate domain at the time of the host
// update, not what it is later changed to.
assertThat(renamedHost.getLastTransferTime()).isEqualTo(lastTransferTime);
// External hosts should always have null lastSuperordinateChange.
assertThat(renamedHost.getLastSuperordinateChange()).isEqualTo(clock.nowUtc());
assertAboutHosts().that(renamedHost)
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(lastTransferTime).and()
.hasLastSuperordinateChange(clock.nowUtc());
}
@Test
@ -571,7 +636,6 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
createTld("foo");
DomainResource domain = persistActiveDomain("example.foo");
DateTime lastTransferTime = clock.nowUtc().minusDays(12);
persistResource(
newHostResource(oldHostName()).asBuilder()
.setSuperordinateDomain(Key.create(domain))
@ -588,7 +652,9 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
// The last transfer time should be what was on the host, because the host's old superordinate
// domain wasn't transferred more recently than when the host was changed to have that
// superordinate domain.
assertThat(renamedHost.getLastTransferTime()).isEqualTo(lastTransferTime);
assertAboutHosts().that(renamedHost)
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(lastTransferTime);
}
@Test
@ -615,7 +681,9 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
HostResource renamedHost = doSuccessfulTest();
// The last transfer time should be what was on the superordinate domain, because the domain
// was transferred more recently than the last time the host's superordinate domain was changed.
assertThat(renamedHost.getLastTransferTime()).isEqualTo(domain.getLastTransferTime());
assertAboutHosts().that(renamedHost)
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(domain.getLastTransferTime());
}
private void doExternalToInternalLastTransferTimeTest(
@ -635,7 +703,9 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
.setLastTransferTime(hostTransferTime)
.build());
HostResource renamedHost = doSuccessfulTest();
assertThat(renamedHost.getLastTransferTime()).isEqualTo(hostTransferTime);
assertAboutHosts().that(renamedHost)
.hasPersistedCurrentSponsorClientId("TheRegistrar").and()
.hasLastTransferTime(hostTransferTime);
}
@Test
@ -896,7 +966,7 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
setEppInput("host_update_prohibited_status.xml");
createTld("tld");
persistActiveDomain("example.tld");
persistActiveHost(oldHostName());
persistActiveHost("ns1.example.tld");
clock.advanceOneMilli();
runFlowAssertResponse(
@ -908,7 +978,7 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
@Test
public void testFailure_unauthorizedClient() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
persistActiveHost(oldHostName());
persistActiveHost("ns1.example.tld");
thrown.expect(ResourceNotOwnedException.class);
runFlow();
}
@ -923,6 +993,136 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
CommitMode.DRY_RUN, UserPrivileges.SUPERUSER, readFile("host_update_response.xml"));
}
@Test
public void testSuccess_authorizedClientReadFromSuperordinate() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
createTld("tld");
DomainResource domain = persistResource(
newDomainResource("example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("NewRegistrar")
.build());
persistResource(
newHostResource("ns1.example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("TheRegistrar") // Shouldn't hurt.
.setSuperordinateDomain(Key.create(domain))
.setInetAddresses(ImmutableSet.of(InetAddresses.forString("127.0.0.1")))
.build());
clock.advanceOneMilli();
runFlowAssertResponse(readFile("host_update_response.xml"));
}
@Test
public void testFailure_unauthorizedClientReadFromSuperordinate() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
createTld("tld");
DomainResource domain = persistResource(
newDomainResource("example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("TheRegistrar")
.build());
persistResource(
newHostResource("ns1.example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("NewRegistrar") // Shouldn't help.
.setSuperordinateDomain(Key.create(domain))
.setInetAddresses(ImmutableSet.of(InetAddresses.forString("127.0.0.1")))
.build());
thrown.expect(ResourceNotOwnedException.class);
runFlow();
}
@Test
public void testSuccess_authorizedClientReadFromTransferredSuperordinate() throws Exception {
sessionMetadata.setClientId("NewRegistrar");
createTld("tld");
// Create a domain that will belong to NewRegistrar after cloneProjectedAtTime is called.
DomainResource domain = persistResource(createDomainWithServerApprovedTransfer("example.tld"));
persistResource(
newHostResource("ns1.example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("TheRegistrar") // Shouldn't hurt.
.setSuperordinateDomain(Key.create(domain))
.setInetAddresses(ImmutableSet.of(InetAddresses.forString("127.0.0.1")))
.build());
clock.advanceOneMilli();
runFlowAssertResponse(readFile("host_update_response.xml"));
}
@Test
public void testFailure_unauthorizedClientReadFromTransferredSuperordinate() throws Exception {
sessionMetadata.setClientId("TheRegistrar");
createTld("tld");
// Create a domain that will belong to NewRegistrar after cloneProjectedAtTime is called.
DomainResource domain = persistResource(createDomainWithServerApprovedTransfer("example.tld"));
persistResource(
newHostResource("ns1.example.tld").asBuilder()
.setPersistedCurrentSponsorClientId("TheRegistrar") // Shouldn't help.
.setSuperordinateDomain(Key.create(domain))
.setInetAddresses(ImmutableSet.of(InetAddresses.forString("127.0.0.1")))
.build());
thrown.expect(ResourceNotOwnedException.class);
runFlow();
}
@Test
public void testFailure_newSuperordinateOwnedByDifferentRegistrar() throws Exception {
setEppHostUpdateInput(
"ns1.example.foo",
"ns2.example.tld",
"<host:addr ip=\"v4\">192.0.2.22</host:addr>",
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",
"<host:addr ip=\"v4\">192.0.2.22</host:addr>",
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",
"<host:addr ip=\"v4\">192.0.2.22</host:addr>",
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<? extends Throwable> exception) throws Exception {
@ -941,6 +1141,19 @@ public class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Hos
doFailingHostNameTest("foo bar", InvalidHostNameException.class);
}
@Test
public void testFailure_renameToNotPunyCoded() throws Exception {
doFailingHostNameTest("みんな", HostNameNotPunyCodedException.class);
}
@Test
public void testFailure_renameToTooLong() throws Exception {
// Host names can be max 253 chars.
String suffix = ".example.tld";
String tooLong = Strings.repeat("a", 254 - suffix.length()) + suffix;
doFailingHostNameTest(tooLong, HostNameTooLongException.class);
}
@Test
public void testFailure_renameToTooShallowPublicSuffix() throws Exception {
doFailingHostNameTest("example.com", HostNameTooShallowException.class);

View file

@ -91,13 +91,13 @@ public class EppResourceUtilsTest {
HostResource oldHost = persistResourceWithCommitLog(
newHostResource("ns1.cat.tld").asBuilder()
.setCreationTimeForTest(START_OF_TIME)
.setCurrentSponsorClientId("OLD")
.setPersistedCurrentSponsorClientId("OLD")
.build());
// Advance a day so that the next created revision entry doesn't overwrite the existing one.
clock.advanceBy(Duration.standardDays(1));
// Overwrite the current host with one that has different data.
HostResource currentHost = persistResource(oldHost.asBuilder()
.setCurrentSponsorClientId("NEW")
.setPersistedCurrentSponsorClientId("NEW")
.build());
// Load at the point in time just before the latest update; the floor entry of the revisions
// map should point to the manifest for the first save, so we should get the old host.
@ -112,13 +112,13 @@ public class EppResourceUtilsTest {
HostResource oldHost = persistResource(
newHostResource("ns1.cat.tld").asBuilder()
.setCreationTimeForTest(START_OF_TIME)
.setCurrentSponsorClientId("OLD")
.setPersistedCurrentSponsorClientId("OLD")
.build());
// Advance a day so that the next created revision entry doesn't overwrite the existing one.
clock.advanceBy(Duration.standardDays(1));
// Overwrite the existing resource to force revisions map use.
HostResource host = persistResource(oldHost.asBuilder()
.setCurrentSponsorClientId("NEW")
.setPersistedCurrentSponsorClientId("NEW")
.build());
// Load at the point in time just before the latest update; the old host is not recoverable
// (revisions map link is broken, and guessing using the oldest revision map entry finds the
@ -134,13 +134,13 @@ public class EppResourceUtilsTest {
HostResource oldHost = persistResourceWithCommitLog(
newHostResource("ns1.cat.tld").asBuilder()
.setCreationTimeForTest(START_OF_TIME)
.setCurrentSponsorClientId("OLD")
.setPersistedCurrentSponsorClientId("OLD")
.build());
// Advance a day so that the next created revision entry doesn't overwrite the existing one.
clock.advanceBy(Duration.standardDays(1));
// Overwrite the current host with one that has different data.
HostResource currentHost = persistResource(oldHost.asBuilder()
.setCurrentSponsorClientId("NEW")
.setPersistedCurrentSponsorClientId("NEW")
.build());
// Load at the point in time before the first update; there will be no floor entry for the
// revisions map, so give up and return the oldest revision entry's mutation value (the old host
@ -157,7 +157,7 @@ public class EppResourceUtilsTest {
HostResource host = persistResource(
newHostResource("ns1.cat.tld").asBuilder()
.setCreationTimeForTest(START_OF_TIME)
.setCurrentSponsorClientId("OLD")
.setPersistedCurrentSponsorClientId("OLD")
.build());
// Load at the point in time before the first save; there will be no floor entry for the
// revisions map. Since the oldest revision entry is the only (i.e. current) revision, return

View file

@ -61,7 +61,7 @@ public class ContactResourceTest extends EntityTestCase {
.setLastEppUpdateTime(clock.nowUtc())
.setLastEppUpdateClientId("another registrar")
.setLastTransferTime(clock.nowUtc())
.setCurrentSponsorClientId("a third registrar")
.setPersistedCurrentSponsorClientId("a third registrar")
.setLocalizedPostalInfo(new PostalInfo.Builder()
.setType(Type.LOCALIZED)
.setAddress(new ContactAddress.Builder()

View file

@ -85,7 +85,7 @@ public class DomainApplicationTest extends EntityTestCase {
Key.create(persistActiveContact("contact_id2")))))
.setNameservers(
ImmutableSet.of(Key.create(persistActiveHost("ns1.example.com"))))
.setCurrentSponsorClientId("a third registrar")
.setPersistedCurrentSponsorClientId("a third registrar")
.setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("password")))
.setDsData(ImmutableSet.of(DelegationSignerData.create(1, 2, 3, new byte[] {0, 1, 2})))
.setLaunchNotice(
@ -125,11 +125,11 @@ public class DomainApplicationTest extends EntityTestCase {
@Test
public void testEmptyStringsBecomeNull() {
assertThat(emptyBuilder().setCurrentSponsorClientId(null).build()
assertThat(emptyBuilder().setPersistedCurrentSponsorClientId(null).build()
.getCurrentSponsorClientId()).isNull();
assertThat(emptyBuilder().setCurrentSponsorClientId("").build()
assertThat(emptyBuilder().setPersistedCurrentSponsorClientId("").build()
.getCurrentSponsorClientId()).isNull();
assertThat(emptyBuilder().setCurrentSponsorClientId(" ").build()
assertThat(emptyBuilder().setPersistedCurrentSponsorClientId(" ").build()
.getCurrentSponsorClientId()).isNotNull();
}

View file

@ -116,7 +116,7 @@ public class DomainResourceTest extends EntityTestCase {
.setContacts(ImmutableSet.of(DesignatedContact.create(Type.ADMIN, contact2Key)))
.setNameservers(ImmutableSet.of(hostKey))
.setSubordinateHosts(ImmutableSet.of("ns1.example.com"))
.setCurrentSponsorClientId("ThirdRegistrar")
.setPersistedCurrentSponsorClientId("ThirdRegistrar")
.setRegistrationExpirationTime(clock.nowUtc().plusYears(1))
.setAuthInfo(DomainAuthInfo.create(PasswordAuth.create("password")))
.setDsData(ImmutableSet.of(DelegationSignerData.create(1, 2, 3, new byte[] {0, 1, 2})))
@ -172,17 +172,17 @@ public class DomainResourceTest extends EntityTestCase {
@Test
public void testEmptyStringsBecomeNull() {
assertThat(newDomainResource("example.com").asBuilder()
.setCurrentSponsorClientId(null)
.setPersistedCurrentSponsorClientId(null)
.build()
.getCurrentSponsorClientId())
.isNull();
assertThat(newDomainResource("example.com").asBuilder()
.setCurrentSponsorClientId("")
.setPersistedCurrentSponsorClientId("")
.build()
.getCurrentSponsorClientId())
.isNull();
assertThat(newDomainResource("example.com").asBuilder()
.setCurrentSponsorClientId(" ")
.setPersistedCurrentSponsorClientId(" ")
.build()
.getCurrentSponsorClientId())
.isNotNull();

View file

@ -30,14 +30,11 @@ import google.registry.model.billing.BillingEvent;
import google.registry.model.domain.DomainResource;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppcommon.Trid;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferData.TransferServerApproveEntity;
import google.registry.model.transfer.TransferStatus;
import google.registry.testing.ExceptionRule;
import java.net.InetAddress;
import javax.annotation.Nullable;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Rule;
@ -49,13 +46,18 @@ public class HostResourceTest extends EntityTestCase {
@Rule
public final ExceptionRule thrown = new ExceptionRule();
HostResource hostResource;
final DateTime day3 = clock.nowUtc();
final DateTime day2 = day3.minusDays(1);
final DateTime day1 = day2.minusDays(1);
DomainResource domain;
HostResource host;
@Before
public void setUp() throws Exception {
createTld("com");
// Set up a new persisted registrar entity.
persistResource(
domain = persistResource(
newDomainResource("example.com").asBuilder()
.setRepoId("1-COM")
.setTransferData(new TransferData.Builder()
@ -71,7 +73,7 @@ public class HostResourceTest extends EntityTestCase {
.setTransferRequestTrid(Trid.create("client trid"))
.build())
.build());
hostResource =
host =
persistResource(
cloneAndSetAutoTimestamps(
new HostResource.Builder()
@ -83,17 +85,15 @@ public class HostResourceTest extends EntityTestCase {
.setLastTransferTime(clock.nowUtc())
.setInetAddresses(ImmutableSet.of(InetAddresses.forString("127.0.0.1")))
.setStatusValues(ImmutableSet.of(StatusValue.OK))
.setSuperordinateDomain(
Key.create(
loadByForeignKey(DomainResource.class, "example.com", clock.nowUtc())))
.setSuperordinateDomain(Key.create(domain))
.build()));
}
@Test
public void testPersistence() throws Exception {
assertThat(loadByForeignKey(
HostResource.class, hostResource.getForeignKey(), clock.nowUtc()))
.isEqualTo(hostResource.cloneProjectedAtTime(clock.nowUtc()));
HostResource.class, host.getForeignKey(), clock.nowUtc()))
.isEqualTo(host);
}
@Test
@ -101,7 +101,7 @@ public class HostResourceTest extends EntityTestCase {
// Clone it and save it before running the indexing test so that its transferData fields are
// populated from the superordinate domain.
verifyIndexing(
persistResource(hostResource.cloneProjectedAtTime(clock.nowUtc())),
persistResource(host),
"deletionTime",
"fullyQualifiedHostName",
"inetAddresses",
@ -111,30 +111,17 @@ public class HostResourceTest extends EntityTestCase {
@Test
public void testEmptyStringsBecomeNull() {
assertThat(new HostResource.Builder().setCurrentSponsorClientId(null).build()
.getCurrentSponsorClientId())
assertThat(new HostResource.Builder().setPersistedCurrentSponsorClientId(null).build()
.getPersistedCurrentSponsorClientId())
.isNull();
assertThat(new HostResource.Builder().setCurrentSponsorClientId("").build()
.getCurrentSponsorClientId())
assertThat(new HostResource.Builder().setPersistedCurrentSponsorClientId("").build()
.getPersistedCurrentSponsorClientId())
.isNull();
assertThat(new HostResource.Builder().setCurrentSponsorClientId(" ").build()
.getCurrentSponsorClientId())
assertThat(new HostResource.Builder().setPersistedCurrentSponsorClientId(" ").build()
.getPersistedCurrentSponsorClientId())
.isNotNull();
}
@Test
public void testCurrentSponsorClientId_comesFromSuperordinateDomain() {
assertThat(hostResource.getCurrentSponsorClientId()).isNull();
HostResource projectedHost =
loadByForeignKey(HostResource.class, hostResource.getForeignKey(), clock.nowUtc());
assertThat(projectedHost.getCurrentSponsorClientId())
.isEqualTo(loadByForeignKey(
DomainResource.class,
"example.com",
clock.nowUtc())
.getCurrentSponsorClientId());
}
@Test
public void testEmptySetsBecomeNull() throws Exception {
assertThat(new HostResource.Builder().setInetAddresses(null).build().inetAddresses).isNull();
@ -169,113 +156,108 @@ public class HostResourceTest extends EntityTestCase {
.hasExactlyStatusValues(StatusValue.CLIENT_HOLD);
}
@Nullable
private DateTime runCloneProjectedAtTimeTest(
@Nullable DateTime domainTransferTime,
@Nullable DateTime hostTransferTime,
@Nullable DateTime superordinateChangeTime) {
DomainResource domain = loadByForeignKey(
DomainResource.class, "example.com", clock.nowUtc());
persistResource(
domain.asBuilder().setTransferData(null).setLastTransferTime(domainTransferTime).build());
hostResource = persistResource(
hostResource.asBuilder()
.setLastSuperordinateChange(superordinateChangeTime)
.setLastTransferTime(hostTransferTime)
.build());
return hostResource.cloneProjectedAtTime(clock.nowUtc()).getLastTransferTime();
}
@Test
public void testCloneProjectedAtTime_lastTransferTimeComesOffHostWhenTransferredMoreRecently() {
assertThat(runCloneProjectedAtTimeTest(
clock.nowUtc().minusDays(10), clock.nowUtc().minusDays(2), clock.nowUtc().minusDays(1)))
.isEqualTo(clock.nowUtc().minusDays(2));
}
@Test
public void testCloneProjectedAtTime_lastTransferTimeNullWhenAllTransfersAreNull() {
assertThat(runCloneProjectedAtTimeTest(null, null, null)).isNull();
}
@Test
public void testCloneProjectedAtTime_lastTransferTimeComesOffHostWhenTimeOnDomainIsNull() {
assertThat(runCloneProjectedAtTimeTest(null, clock.nowUtc().minusDays(30), null))
.isEqualTo(clock.nowUtc().minusDays(30));
}
@Test
public void testCloneProjectedAtTime_lastTransferTimeIsNullWhenHostMovedAfterDomainTransferred() {
assertThat(runCloneProjectedAtTimeTest(
clock.nowUtc().minusDays(30), null, clock.nowUtc().minusDays(20)))
.isNull();
}
@Test
public void testCloneProjectedAtTime_lastTransferTimeComesOffDomainWhenTimeOnHostIsNull() {
assertThat(runCloneProjectedAtTimeTest(clock.nowUtc().minusDays(5), null, null))
.isEqualTo(clock.nowUtc().minusDays(5));
}
@Test
public void testCloneProjectedAtTime_lastTransferTimeComesOffDomainWhenLastMoveIsntNull() {
assertThat(runCloneProjectedAtTimeTest(
clock.nowUtc().minusDays(5), null, clock.nowUtc().minusDays(10)))
.isEqualTo(clock.nowUtc().minusDays(5));
}
@Test
public void testCloneProjectedAtTime_lastTransferTimeComesOffDomainWhenThatIsMostRecent() {
assertThat(runCloneProjectedAtTimeTest(
clock.nowUtc().minusDays(5), clock.nowUtc().minusDays(20), clock.nowUtc().minusDays(10)))
.isEqualTo(clock.nowUtc().minusDays(5));
}
@Test
public void testExpiredTransfer_subordinateHost() {
DomainResource domain = loadByForeignKey(
DomainResource.class, "example.com", clock.nowUtc());
persistResource(domain.asBuilder()
.setTransferData(domain.getTransferData().asBuilder()
.setTransferStatus(TransferStatus.PENDING)
.setPendingTransferExpirationTime(clock.nowUtc().plusDays(1))
.setGainingClientId("winner")
.setExtendedRegistrationYears(2)
.setServerApproveBillingEvent(Key.create(
new BillingEvent.OneTime.Builder()
.setParent(new HistoryEntry.Builder().setParent(domain).build())
.setCost(Money.parse("USD 100"))
.setBillingTime(clock.nowUtc().plusYears(2))
.setReason(BillingEvent.Reason.TRANSFER)
.setClientId("TheRegistrar")
.setTargetId("example.com")
.setEventTime(clock.nowUtc().plusYears(2))
.setPeriodYears(2)
.build()))
.build())
.build());
HostResource afterTransfer = hostResource.cloneProjectedAtTime(clock.nowUtc().plusDays(1));
assertThat(afterTransfer.getCurrentSponsorClientId()).isEqualTo("winner");
assertThat(afterTransfer.getLastTransferTime()).isEqualTo(clock.nowUtc().plusDays(1));
}
@Test
public void testToHydratedString_notCircular() {
// If there are circular references, this will overflow the stack.
hostResource.toHydratedString();
host.toHydratedString();
}
@Test
public void testFailure_uppercaseHostName() {
thrown.expect(
IllegalArgumentException.class, "Host name must be in puny-coded, lower-case form");
hostResource.asBuilder().setFullyQualifiedHostName("AAA.BBB.CCC");
host.asBuilder().setFullyQualifiedHostName("AAA.BBB.CCC");
}
@Test
public void testFailure_utf8HostName() {
thrown.expect(
IllegalArgumentException.class, "Host name must be in puny-coded, lower-case form");
hostResource.asBuilder().setFullyQualifiedHostName("みんな.みんな.みんな");
host.asBuilder().setFullyQualifiedHostName("みんな.みんな.みんな");
}
@Test
public void testComputeLastTransferTime_hostNeverSwitchedDomains_domainWasNeverTransferred() {
domain = domain.asBuilder().setLastTransferTime(null).build();
host = host.asBuilder()
.setLastTransferTime(null)
.setLastSuperordinateChange(null)
.build();
assertThat(host.computeLastTransferTime(domain)).isNull();
}
@Test
public void testComputeLastTransferTime_hostNeverSwitchedDomains_domainWasTransferred() {
// Host was created on Day 1.
// Domain was transferred on Day 2.
// Host was always subordinate to domain (and was created before the transfer).
domain = domain.asBuilder().setLastTransferTime(day2).build();
host = host.asBuilder()
.setCreationTimeForTest(day1)
.setLastTransferTime(null)
.setLastSuperordinateChange(null)
.build();
assertThat(host.computeLastTransferTime(domain)).isEqualTo(day2);
}
@Test
public void testComputeLastTransferTime_hostCreatedAfterDomainWasTransferred() {
// Domain was transferred on Day 1.
// Host was created subordinate to domain on Day 2.
domain = domain.asBuilder().setLastTransferTime(day1).build();
host =
persistResource(
cloneAndSetAutoTimestamps(
new HostResource.Builder()
.setCreationTime(day2)
.setRepoId("DEADBEEF-COM")
.setFullyQualifiedHostName("ns1.example.com")
.setCreationClientId("a registrar")
.setLastEppUpdateTime(clock.nowUtc())
.setLastEppUpdateClientId("another registrar")
.setInetAddresses(ImmutableSet.of(InetAddresses.forString("127.0.0.1")))
.setStatusValues(ImmutableSet.of(StatusValue.OK))
.setSuperordinateDomain(Key.create(domain))
.build()));
assertThat(host.computeLastTransferTime(domain)).isNull();
}
@Test
public void testComputeLastTransferTime_hostWasTransferred_domainWasNeverTransferred() {
// Host was transferred on Day 1.
// Host was made subordinate to domain on Day 2.
// Domain was never transferred.
domain = domain.asBuilder().setLastTransferTime(null).build();
host = host.asBuilder()
.setLastTransferTime(day1)
.setLastSuperordinateChange(day2)
.build();
assertThat(host.computeLastTransferTime(domain)).isEqualTo(day1);
}
@Test
public void testComputeLastTransferTime_domainWasTransferredBeforeHostBecameSubordinate() {
// Host was transferred on Day 1.
// Domain was transferred on Day 2.
// Host was made subordinate to domain on Day 3.
domain = domain.asBuilder().setLastTransferTime(day2).build();
host = host.asBuilder()
.setLastTransferTime(day1)
.setLastSuperordinateChange(day3)
.build();
assertThat(host.computeLastTransferTime(domain)).isEqualTo(day1);
}
@Test
public void testComputeLastTransferTime_domainWasTransferredAfterHostBecameSubordinate() {
// Host was transferred on Day 1.
// Host was made subordinate to domain on Day 2.
// Domain was transferred on Day 3.
domain = domain.asBuilder().setLastTransferTime(day3).build();
host = host.asBuilder()
.setLastTransferTime(day1)
.setLastSuperordinateChange(day2)
.build();
assertThat(host.computeLastTransferTime(domain)).isEqualTo(day3);
}
}

View file

@ -30,17 +30,21 @@ import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.googlecode.objectify.Key;
import google.registry.config.RdapNoticeDescriptor;
import google.registry.model.contact.ContactResource;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DomainResource;
import google.registry.model.domain.Period;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.HostResource;
import google.registry.model.ofy.Ofy;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarContact;
import google.registry.model.registry.Registry.TldState;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.TransferData;
import google.registry.model.transfer.TransferStatus;
import google.registry.rdap.RdapJsonFormatter.OutputDataType;
import google.registry.testing.AppEngineRule;
import google.registry.testing.FakeClock;
@ -75,6 +79,7 @@ public class RdapJsonFormatterTest {
private HostResource hostResourceBoth;
private HostResource hostResourceNoAddresses;
private HostResource hostResourceNotLinked;
private HostResource hostResourceSuperordinatePendingTransfer;
private ContactResource contactResourceRegistrant;
private ContactResource contactResourceAdmin;
private ContactResource contactResourceTech;
@ -134,6 +139,31 @@ public class RdapJsonFormatterTest {
"ns4.cat.みんな", null, clock.nowUtc().minusYears(4));
hostResourceNotLinked = makeAndPersistHostResource(
"ns5.cat.みんな", null, clock.nowUtc().minusYears(5));
hostResourceSuperordinatePendingTransfer = persistResource(
makeAndPersistHostResource("ns1.dog.みんな", null, clock.nowUtc().minusYears(6))
.asBuilder()
.setSuperordinateDomain(Key.create(
persistResource(
makeDomainResource(
"dog.みんな",
contactResourceRegistrant,
contactResourceAdmin,
contactResourceTech,
null,
null,
registrar)
.asBuilder()
.addStatusValue(StatusValue.PENDING_TRANSFER)
.setTransferData(new TransferData.Builder()
.setTransferStatus(TransferStatus.PENDING)
.setGainingClientId("NewRegistrar")
.setTransferRequestTime(clock.nowUtc().minusDays(1))
.setLosingClientId("TheRegistrar")
.setPendingTransferExpirationTime(clock.nowUtc().plusYears(100))
.setExtendedRegistrationYears(1)
.build())
.build())))
.build());
domainResourceFull = persistResource(
makeDomainResource(
"cat.みんな",
@ -314,6 +344,18 @@ public class RdapJsonFormatterTest {
.isEqualTo(loadJson("rdapjson_host_not_linked.json"));
}
@Test
public void testHost_superordinateHasPendingTransfer() throws Exception {
assertThat(rdapJsonFormatter.makeRdapJsonForHost(
hostResourceSuperordinatePendingTransfer,
false,
LINK_BASE,
WHOIS_SERVER,
clock.nowUtc(),
OutputDataType.FULL))
.isEqualTo(loadJson("rdapjson_host_pending_transfer.json"));
}
@Test
public void testRegistrant() throws Exception {
assertThat(

View file

@ -1,6 +1,6 @@
{
"objectClassName" : "domain",
"handle" : "14-Q9JYB4C",
"handle" : "17-Q9JYB4C",
"ldhName" : "cat.xn--q9jyb4c",
"unicodeName" : "cat.みんな",
"status" :

View file

@ -1,6 +1,6 @@
{
"objectClassName" : "domain",
"handle" : "15-Q9JYB4C",
"handle" : "18-Q9JYB4C",
"ldhName" : "fish.xn--q9jyb4c",
"unicodeName" : "fish.みんな",
"status" :

View file

@ -1,6 +1,6 @@
{
"objectClassName" : "domain",
"handle" : "14-Q9JYB4C",
"handle" : "17-Q9JYB4C",
"ldhName" : "cat.xn--q9jyb4c",
"unicodeName" : "cat.みんな",
"status" :

View file

@ -0,0 +1,27 @@
{
"objectClassName" : "nameserver",
"handle" : "14-ROID",
"ldhName" : "ns1.dog.xn--q9jyb4c",
"unicodeName" : "ns1.dog.みんな",
"status" : ["active", "pending transfer"],
"links" :
[
{
"value" : "http://myserver.example.com/nameserver/ns1.dog.xn--q9jyb4c",
"rel" : "self",
"href" : "http://myserver.example.com/nameserver/ns1.dog.xn--q9jyb4c",
"type" : "application/rdap+json"
}
],
"events": [
{
"eventAction": "registration",
"eventActor": "foo",
"eventDate": "1994-01-01T00:00:00.000Z"
},
{
"eventAction": "last update of RDAP database",
"eventDate": "2000-01-01T00:00:00.000Z"
}
]
}

View file

@ -300,7 +300,7 @@ public class ContactResourceToXjcConverterTest {
.setContactId("love-id")
.setRepoId("2-ROID")
.setCreationClientId("NewRegistrar")
.setCurrentSponsorClientId("TheRegistrar")
.setPersistedCurrentSponsorClientId("TheRegistrar")
.setLastEppUpdateClientId("TheRegistrar")
.setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("2fooBAR")))
.setCreationTimeForTest(DateTime.parse("1900-01-01TZ"))

View file

@ -266,7 +266,7 @@ public class DomainResourceToXjcConverterTest {
"bird or fiend!? i shrieked upstarting", "bog@cat.みんな")))))
.setCreationClientId("LawyerCat")
.setCreationTimeForTest(DateTime.parse("1900-01-01T00:00:00Z"))
.setCurrentSponsorClientId("GetTheeBack")
.setPersistedCurrentSponsorClientId("GetTheeBack")
.setDsData(ImmutableSet.of(DelegationSignerData.create(
123, 200, 230, base16().decode("1234567890"))))
.setFullyQualifiedDomainName(Idn.toASCII("love.みんな"))
@ -367,7 +367,7 @@ public class DomainResourceToXjcConverterTest {
new ContactResource.Builder()
.setContactId(id)
.setEmailAddress(email)
.setCurrentSponsorClientId("GetTheeBack")
.setPersistedCurrentSponsorClientId("GetTheeBack")
.setCreationClientId("GetTheeBack")
.setCreationTimeForTest(END_OF_TIME)
.setInternationalizedPostalInfo(new PostalInfo.Builder()
@ -401,7 +401,7 @@ public class DomainResourceToXjcConverterTest {
new HostResource.Builder()
.setCreationClientId("LawyerCat")
.setCreationTimeForTest(DateTime.parse("1900-01-01T00:00:00Z"))
.setCurrentSponsorClientId("BusinessCat")
.setPersistedCurrentSponsorClientId("BusinessCat")
.setFullyQualifiedHostName(Idn.toASCII(fqhn))
.setInetAddresses(ImmutableSet.of(InetAddresses.forString(ip)))
.setLastTransferTime(DateTime.parse("1910-01-01T00:00:00Z"))

View file

@ -16,15 +16,19 @@ package google.registry.rde;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.newDomainResource;
import static google.registry.xjc.XjcXmlTransformer.marshalStrict;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.ImmutableSet;
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.testing.AppEngineRule;
import google.registry.testing.ExceptionRule;
import google.registry.xjc.host.XjcHostStatusType;
import google.registry.xjc.host.XjcHostStatusValueType;
import google.registry.xjc.rdehost.XjcRdeHost;
import google.registry.xjc.rdehost.XjcRdeHostElement;
@ -59,12 +63,72 @@ public class HostResourceToXjcConverterTest {
}
@Test
public void testConvert() throws Exception {
XjcRdeHost bean = HostResourceToXjcConverter.convertHost(
public void testConvertSubordinateHost() throws Exception {
DomainResource domain = newDomainResource("love.foobar").asBuilder()
.setPersistedCurrentSponsorClientId("LeisureDog")
.setLastTransferTime(DateTime.parse("2010-01-01T00:00:00Z"))
.addStatusValue(StatusValue.PENDING_TRANSFER)
.build();
XjcRdeHost bean = HostResourceToXjcConverter.convertSubordinateHost(
new HostResource.Builder()
.setCreationClientId("LawyerCat")
.setCreationTimeForTest(DateTime.parse("1900-01-01T00:00:00Z"))
.setCurrentSponsorClientId("BusinessCat")
.setPersistedCurrentSponsorClientId("BusinessCat")
.setFullyQualifiedHostName("ns1.love.foobar")
.setInetAddresses(ImmutableSet.of(InetAddresses.forString("127.0.0.1")))
.setLastTransferTime(DateTime.parse("1910-01-01T00:00:00Z"))
.setLastEppUpdateClientId("CeilingCat")
.setLastEppUpdateTime(DateTime.parse("1920-01-01T00:00:00Z"))
.setRepoId("2-roid")
.setStatusValues(ImmutableSet.of(StatusValue.OK))
.setSuperordinateDomain(Key.create(domain))
.build(),
domain);
assertThat(bean.getAddrs()).hasSize(1);
assertThat(bean.getAddrs().get(0).getIp().value()).isEqualTo("v4");
assertThat(bean.getAddrs().get(0).getValue()).isEqualTo("127.0.0.1");
assertThat(bean.getCrDate()).isEqualTo(DateTime.parse("1900-01-01T00:00:00Z"));
// o A <crRr> 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);
}
}

View file

@ -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"))

View file

@ -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 MapreduceTestCase<RdeHostImportActi
@Before
public void before() throws Exception {
createTld("test");
response = new FakeResponse();
mrRunner = new MapreduceRunner(Optional.<Integer>absent(), Optional.<Integer>absent());
action = new RdeHostImportAction(
@ -106,12 +104,12 @@ public class RdeHostImportActionTest extends MapreduceTestCase<RdeHostImportActi
// Create host and history entry first
HostResource existingHost = persistResource(
newHostResource("ns1.example1.test")
.asBuilder()
.setRepoId("Hns1_example1_test-TEST")
.build());
.asBuilder()
.setRepoId("Hns1_example1_test-TEST")
.build());
persistSimpleResource(createHistoryEntry(
existingHost.getRepoId(),
existingHost.getCurrentSponsorClientId(),
existingHost.getPersistedCurrentSponsorClientId(),
loadHostXml(DEPOSIT_1_HOST)));
// Simulate running a second import and verify that the resources
// aren't imported twice (only one host, and one history entry)
@ -128,7 +126,7 @@ public class RdeHostImportActionTest extends MapreduceTestCase<RdeHostImportActi
/** Verify history entry fields are correct */
private void checkHistoryEntry(HistoryEntry entry, HostResource parent) {
assertThat(entry.getType()).isEqualTo(HistoryEntry.Type.RDE_IMPORT);
assertThat(entry.getClientId()).isEqualTo(parent.getCurrentSponsorClientId());
assertThat(entry.getClientId()).isEqualTo(parent.getPersistedCurrentSponsorClientId());
assertThat(entry.getXmlBytes().length).isGreaterThan(0);
assertThat(entry.getBySuperuser()).isTrue();
assertThat(entry.getReason()).isEqualTo("RDE Import");

View file

@ -288,7 +288,7 @@ public class RdeImportUtilsTest extends ShardableTestCase {
.setContacts(ImmutableSet.of(
DesignatedContact.create(Type.ADMIN, Key.create(admin)),
DesignatedContact.create(Type.TECH, Key.create(admin))))
.setCurrentSponsorClientId("RegistrarX")
.setPersistedCurrentSponsorClientId("RegistrarX")
.setCreationClientId("RegistrarX")
.setCreationTime(DateTime.parse("1999-04-03T22:00:00.0Z"))
.setRegistrationExpirationTime(DateTime.parse("2015-04-03T22:00:00.0Z"))

View file

@ -97,7 +97,7 @@ public class XjcToHostResourceConverterTest extends ShardableTestCase {
InetAddresses.forString("192.0.2.2"),
InetAddresses.forString("192.0.2.29"),
InetAddresses.forString("1080:0:0:0:8:800:200C:417A"));
assertThat(host.getCurrentSponsorClientId()).isEqualTo("RegistrarX");
assertThat(host.getPersistedCurrentSponsorClientId()).isEqualTo("RegistrarX");
assertThat(host.getCreationClientId()).isEqualTo("RegistrarX");
assertThat(host.getCreationTime()).isEqualTo(DateTime.parse("1999-05-08T12:10:00.0Z"));
assertThat(host.getLastEppUpdateClientId()).isEqualTo("RegistrarX");

View file

@ -60,4 +60,11 @@ public abstract class AbstractDomainBaseSubject
AuthInfo authInfo = actual().getAuthInfo();
return hasValue(pw, authInfo == null ? null : authInfo.getPw().getValue(), "has auth info pw");
}
public And<S> hasCurrentSponsorClientId(String clientId) {
return hasValue(
clientId,
actual().getCurrentSponsorClientId(),
"has currentSponsorClientId");
}
}

View file

@ -172,11 +172,12 @@ abstract class AbstractEppResourceSubject
"has lastEppUpdateClientId");
}
public And<S> hasCurrentSponsorClientId(String clientId) {
public And<S> hasPersistedCurrentSponsorClientId(String clientId) {
return hasValue(
clientId,
actual().getCurrentSponsorClientId(),
"has currentSponsorClientId");
actual().getPersistedCurrentSponsorClientId(),
"has persisted currentSponsorClientId");
}
public And<S> isActiveAt(DateTime time) {

View file

@ -175,6 +175,14 @@ public final class ContactResourceSubject
actual().getLastTransferTime(),
"lastTransferTime");
}
public And<ContactResourceSubject> hasCurrentSponsorClientId(String clientId) {
return hasValue(
clientId,
actual().getCurrentSponsorClientId(),
"has currentSponsorClientId");
}
public static DelegatedVerb<ContactResourceSubject, ContactResource> assertAboutContacts() {
return assertAbout(new SubjectFactory());
}

View file

@ -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)

View file

@ -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,

View file

@ -167,7 +167,7 @@ public class GenerateAuctionDataCommandTest extends CommandTestCase<GenerateAuct
persistResource(newDomainApplication("label.xn--q9jyb4c", contact1));
persistResource(newDomainApplication("label.xn--q9jyb4c", contact2)
.asBuilder()
.setCurrentSponsorClientId("NewRegistrar")
.setPersistedCurrentSponsorClientId("NewRegistrar")
.build());
runCommand("--output=" + output, "xn--q9jyb4c");
assertThat(getOutput()).isEqualTo(Joiner.on('\n').join(ImmutableList.of(

View file

@ -198,7 +198,7 @@ public class GenerateEscrowDepositCommandTest
.setRepoId(generateNewContactHostRoid())
.setCreationClientId("LawyerCat")
.setCreationTimeForTest(clock.nowUtc())
.setCurrentSponsorClientId("BusinessCat")
.setPersistedCurrentSponsorClientId("BusinessCat")
.setFullyQualifiedHostName(Idn.toASCII(fqdn))
.setInetAddresses(ImmutableSet.of(InetAddresses.forString(ip)))
.setLastTransferTime(DateTime.parse("1910-01-01T00:00:00Z"))

View file

@ -77,7 +77,7 @@ public class MutatingCommandTest {
newHost1 = host1.asBuilder()
.setLastEppUpdateTime(DateTime.parse("2014-09-09T09:09:09.000Z"))
.build();
newHost2 = host2.asBuilder().setCurrentSponsorClientId("Registrar2").build();
newHost2 = host2.asBuilder().setPersistedCurrentSponsorClientId("Registrar2").build();
}
@Test

View file

@ -61,7 +61,7 @@ public class UpdateApplicationStatusCommandTest
domainApplication = persistResource(newDomainApplication(
"label.xn--q9jyb4c", persistResource(newContactResourceWithRoid("contact1", "C1-ROID")))
.asBuilder()
.setCurrentSponsorClientId("TheRegistrar")
.setPersistedCurrentSponsorClientId("TheRegistrar")
.build());
this.creationTime = domainApplication.getCreationTime();

View file

@ -43,7 +43,7 @@ public class UpdateClaimsNoticeCommandTest extends CommandTestCase<UpdateClaimsN
createTld("xn--q9jyb4c");
domainApplication = persistResource(newDomainApplication("example-one.xn--q9jyb4c")
.asBuilder()
.setCurrentSponsorClientId("TheRegistrar")
.setPersistedCurrentSponsorClientId("TheRegistrar")
.build());
}

View file

@ -66,7 +66,7 @@ public class UpdateSmdCommandTest extends CommandTestCase<UpdateSmdCommand> {
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 =

View file

@ -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,

View file

@ -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")))